@cardog/api 0.1.1
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 +327 -0
- package/cardog-icon.png +0 -0
- package/dist/index.d.mts +1591 -0
- package/dist/index.d.ts +1591 -0
- package/dist/index.js +2245 -0
- package/dist/index.mjs +2208 -0
- package/dist/react/index.d.mts +91 -0
- package/dist/react/index.d.ts +91 -0
- package/dist/react/index.js +1967 -0
- package/dist/react/index.mjs +1964 -0
- package/package.json +94 -0
|
@@ -0,0 +1,1967 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var reactQuery = require('@tanstack/react-query');
|
|
4
|
+
require('axios');
|
|
5
|
+
var zod = require('zod');
|
|
6
|
+
|
|
7
|
+
// src/react/hooks.ts
|
|
8
|
+
var MAX_PAGE_SIZE = 250;
|
|
9
|
+
var DEFAULT_RADIUS = 50;
|
|
10
|
+
var MAX_RADIUS = 500;
|
|
11
|
+
zod.z.object({
|
|
12
|
+
make: zod.z.string(),
|
|
13
|
+
model: zod.z.string(),
|
|
14
|
+
year: zod.z.coerce.number().int().min(1900).max(2050)
|
|
15
|
+
});
|
|
16
|
+
zod.z.string().length(17, "VIN must be exactly 17 characters").regex(/^[A-HJ-NPR-Z0-9]{17}$/, "Invalid VIN format");
|
|
17
|
+
var paginationSchema = zod.z.object({
|
|
18
|
+
page: zod.z.coerce.number().int().min(1, "Page number must be 1 or greater"),
|
|
19
|
+
// .default(1),
|
|
20
|
+
limit: zod.z.coerce.number().int().min(1, "Page size must be at least 1").max(MAX_PAGE_SIZE, `Page size cannot exceed ${MAX_PAGE_SIZE}`)
|
|
21
|
+
// .default(DEFAULT_PAGE_SIZE),
|
|
22
|
+
});
|
|
23
|
+
var locationSchema = zod.z.object({
|
|
24
|
+
lat: zod.z.coerce.number().min(-90, "Latitude must be between -90 and 90").max(90, "Latitude must be between -90 and 90"),
|
|
25
|
+
lng: zod.z.coerce.number().min(-180, "Longitude must be between -180 and 180").max(180, "Longitude must be between -180 and 180"),
|
|
26
|
+
radius: zod.z.coerce.number().min(1, "Radius must be at least 1 km").max(MAX_RADIUS, `Radius cannot exceed ${MAX_RADIUS} km`).default(DEFAULT_RADIUS)
|
|
27
|
+
});
|
|
28
|
+
var rangeSchema = (min, max) => zod.z.object({
|
|
29
|
+
min: zod.z.number().int().min(min).optional(),
|
|
30
|
+
max: zod.z.number().int().max(max).optional()
|
|
31
|
+
});
|
|
32
|
+
var sortDirectionsSchema = zod.z.string().transform((val) => val.toLowerCase()).pipe(zod.z.enum(["asc", "desc"]));
|
|
33
|
+
var idSchema = zod.z.string();
|
|
34
|
+
var timestampSchema = zod.z.string().datetime();
|
|
35
|
+
var sellerSchema = zod.z.object({
|
|
36
|
+
id: idSchema,
|
|
37
|
+
slug: zod.z.string().optional(),
|
|
38
|
+
// TODO: Remove soon.
|
|
39
|
+
type: zod.z.string(),
|
|
40
|
+
name: zod.z.string(),
|
|
41
|
+
email: zod.z.string().nullable(),
|
|
42
|
+
phone: zod.z.string().nullable(),
|
|
43
|
+
addressId: zod.z.number().nullable(),
|
|
44
|
+
dealershipId: idSchema.nullable(),
|
|
45
|
+
// Google My Business enhanced fields
|
|
46
|
+
gmbPhone: zod.z.string().nullable(),
|
|
47
|
+
gmbRating: zod.z.string().nullable(),
|
|
48
|
+
gmbReviewCount: zod.z.number().nullable(),
|
|
49
|
+
createdAt: timestampSchema,
|
|
50
|
+
updatedAt: timestampSchema,
|
|
51
|
+
deactivatedAt: timestampSchema.nullable()
|
|
52
|
+
});
|
|
53
|
+
var dealershipSchema = zod.z.object({
|
|
54
|
+
id: idSchema,
|
|
55
|
+
name: zod.z.string(),
|
|
56
|
+
primaryDomain: zod.z.string(),
|
|
57
|
+
metadata: zod.z.any(),
|
|
58
|
+
isVerified: zod.z.boolean(),
|
|
59
|
+
createdAt: timestampSchema,
|
|
60
|
+
updatedAt: timestampSchema
|
|
61
|
+
});
|
|
62
|
+
var addressSchema = zod.z.object({
|
|
63
|
+
id: zod.z.number(),
|
|
64
|
+
street: zod.z.string(),
|
|
65
|
+
city: zod.z.string(),
|
|
66
|
+
state: zod.z.string(),
|
|
67
|
+
postalCode: zod.z.string(),
|
|
68
|
+
country: zod.z.string(),
|
|
69
|
+
latitude: zod.z.string(),
|
|
70
|
+
longitude: zod.z.string(),
|
|
71
|
+
location: zod.z.object({
|
|
72
|
+
x: zod.z.number(),
|
|
73
|
+
y: zod.z.number()
|
|
74
|
+
}),
|
|
75
|
+
createdAt: timestampSchema,
|
|
76
|
+
updatedAt: timestampSchema
|
|
77
|
+
});
|
|
78
|
+
var mediaSchema = zod.z.object({
|
|
79
|
+
id: zod.z.number(),
|
|
80
|
+
listingId: idSchema.nullable(),
|
|
81
|
+
type: zod.z.string(),
|
|
82
|
+
url: zod.z.string(),
|
|
83
|
+
make: zod.z.string().nullable(),
|
|
84
|
+
model: zod.z.string().nullable(),
|
|
85
|
+
year: zod.z.number().nullable(),
|
|
86
|
+
width: zod.z.number().nullable(),
|
|
87
|
+
height: zod.z.number().nullable(),
|
|
88
|
+
sizeBytes: zod.z.number().nullable(),
|
|
89
|
+
mimeType: zod.z.string().nullable(),
|
|
90
|
+
sourceUri: zod.z.string().nullable(),
|
|
91
|
+
sourceType: zod.z.string().nullable(),
|
|
92
|
+
metadata: zod.z.any().nullable(),
|
|
93
|
+
createdAt: timestampSchema.nullable(),
|
|
94
|
+
updatedAt: timestampSchema.nullable(),
|
|
95
|
+
removedAt: timestampSchema.nullable()
|
|
96
|
+
});
|
|
97
|
+
var vehicleReportSchema = zod.z.object({
|
|
98
|
+
id: zod.z.string(),
|
|
99
|
+
vin: zod.z.string(),
|
|
100
|
+
url: zod.z.string().nullable(),
|
|
101
|
+
version: zod.z.string(),
|
|
102
|
+
type: zod.z.string(),
|
|
103
|
+
data: zod.z.any(),
|
|
104
|
+
// jsonb data
|
|
105
|
+
createdAt: timestampSchema,
|
|
106
|
+
updatedAt: timestampSchema
|
|
107
|
+
});
|
|
108
|
+
var patternMatchSchema = zod.z.object({
|
|
109
|
+
element: zod.z.string(),
|
|
110
|
+
code: zod.z.string(),
|
|
111
|
+
attributeId: zod.z.union([zod.z.string(), zod.z.number(), zod.z.null()]),
|
|
112
|
+
value: zod.z.string().nullable(),
|
|
113
|
+
confidence: zod.z.number(),
|
|
114
|
+
positions: zod.z.array(zod.z.number()),
|
|
115
|
+
schema: zod.z.string(),
|
|
116
|
+
metadata: zod.z.object({
|
|
117
|
+
lookupTable: zod.z.string().nullable().optional(),
|
|
118
|
+
groupName: zod.z.string().nullable().optional(),
|
|
119
|
+
elementWeight: zod.z.number().nullable().optional(),
|
|
120
|
+
patternType: zod.z.enum(["VDS", "VIS"]).nullable().optional(),
|
|
121
|
+
rawPattern: zod.z.string().nullable().optional(),
|
|
122
|
+
matchDetails: zod.z.object({
|
|
123
|
+
exactMatches: zod.z.number().optional(),
|
|
124
|
+
wildcardMatches: zod.z.number().optional(),
|
|
125
|
+
totalPositions: zod.z.number().optional()
|
|
126
|
+
}).nullable().optional()
|
|
127
|
+
}).optional()
|
|
128
|
+
});
|
|
129
|
+
zod.z.object({
|
|
130
|
+
vin: zod.z.string(),
|
|
131
|
+
valid: zod.z.boolean(),
|
|
132
|
+
components: zod.z.object({
|
|
133
|
+
checkDigit: zod.z.object({
|
|
134
|
+
position: zod.z.number(),
|
|
135
|
+
actual: zod.z.string(),
|
|
136
|
+
expected: zod.z.string().optional(),
|
|
137
|
+
isValid: zod.z.boolean()
|
|
138
|
+
}).optional(),
|
|
139
|
+
modelYear: zod.z.object({
|
|
140
|
+
year: zod.z.number(),
|
|
141
|
+
source: zod.z.enum(["position", "override", "calculated"]),
|
|
142
|
+
confidence: zod.z.number()
|
|
143
|
+
}).optional(),
|
|
144
|
+
wmi: zod.z.object({
|
|
145
|
+
code: zod.z.string(),
|
|
146
|
+
manufacturer: zod.z.string(),
|
|
147
|
+
country: zod.z.string(),
|
|
148
|
+
vehicleType: zod.z.string(),
|
|
149
|
+
region: zod.z.string(),
|
|
150
|
+
make: zod.z.string()
|
|
151
|
+
}).optional(),
|
|
152
|
+
vds: zod.z.object({
|
|
153
|
+
raw: zod.z.string(),
|
|
154
|
+
patterns: zod.z.array(patternMatchSchema)
|
|
155
|
+
}).optional(),
|
|
156
|
+
vis: zod.z.object({
|
|
157
|
+
raw: zod.z.string(),
|
|
158
|
+
patterns: zod.z.array(patternMatchSchema)
|
|
159
|
+
}).optional(),
|
|
160
|
+
vehicle: zod.z.object({
|
|
161
|
+
make: zod.z.string(),
|
|
162
|
+
model: zod.z.string(),
|
|
163
|
+
year: zod.z.number(),
|
|
164
|
+
series: zod.z.string().optional(),
|
|
165
|
+
trim: zod.z.string().optional(),
|
|
166
|
+
bodyStyle: zod.z.string().optional(),
|
|
167
|
+
driveType: zod.z.string().optional(),
|
|
168
|
+
engineType: zod.z.string().optional(),
|
|
169
|
+
fuelType: zod.z.string().optional(),
|
|
170
|
+
transmission: zod.z.string().optional(),
|
|
171
|
+
doors: zod.z.string().optional(),
|
|
172
|
+
gvwr: zod.z.string().optional(),
|
|
173
|
+
manufacturer: zod.z.string().optional()
|
|
174
|
+
}).optional(),
|
|
175
|
+
plant: zod.z.object({
|
|
176
|
+
country: zod.z.string(),
|
|
177
|
+
city: zod.z.string().optional(),
|
|
178
|
+
manufacturer: zod.z.string().optional(),
|
|
179
|
+
code: zod.z.string()
|
|
180
|
+
}).optional(),
|
|
181
|
+
engine: zod.z.object({
|
|
182
|
+
type: zod.z.string().optional(),
|
|
183
|
+
model: zod.z.string().optional(),
|
|
184
|
+
cylinders: zod.z.string().optional(),
|
|
185
|
+
displacement: zod.z.string().optional(),
|
|
186
|
+
fuel: zod.z.string().optional(),
|
|
187
|
+
power: zod.z.string().optional()
|
|
188
|
+
}).optional()
|
|
189
|
+
}),
|
|
190
|
+
errors: zod.z.array(zod.z.unknown()),
|
|
191
|
+
patterns: zod.z.array(patternMatchSchema).optional(),
|
|
192
|
+
metadata: zod.z.object({
|
|
193
|
+
processingTime: zod.z.number(),
|
|
194
|
+
confidence: zod.z.number(),
|
|
195
|
+
schemaVersion: zod.z.string(),
|
|
196
|
+
matchedSchema: zod.z.string().optional(),
|
|
197
|
+
totalPatterns: zod.z.number().optional(),
|
|
198
|
+
rawRecords: zod.z.array(zod.z.unknown()).optional(),
|
|
199
|
+
queries: zod.z.array(
|
|
200
|
+
zod.z.object({
|
|
201
|
+
sql: zod.z.string(),
|
|
202
|
+
params: zod.z.array(zod.z.unknown()),
|
|
203
|
+
timing: zod.z.number()
|
|
204
|
+
})
|
|
205
|
+
).optional()
|
|
206
|
+
}).optional()
|
|
207
|
+
});
|
|
208
|
+
zod.z.object({
|
|
209
|
+
// TODO: Implement this properly with correct structure
|
|
210
|
+
variants: zod.z.array(zod.z.unknown())
|
|
211
|
+
// Temporary until research schemas are ported
|
|
212
|
+
});
|
|
213
|
+
zod.z.object({
|
|
214
|
+
result: zod.z.string(),
|
|
215
|
+
success: zod.z.boolean()
|
|
216
|
+
});
|
|
217
|
+
zod.z.object({
|
|
218
|
+
vehicle: zod.z.string().describe("Human-readable vehicle label, e.g. '2022 Honda Civic'"),
|
|
219
|
+
totalListings: zod.z.number().describe("Count of active listings in the cohort"),
|
|
220
|
+
avgPrice: zod.z.number().describe("Average listing price (rounded)"),
|
|
221
|
+
medianPrice: zod.z.number().describe("Median listing price (rounded)"),
|
|
222
|
+
minPrice: zod.z.number().describe("Minimum listing price"),
|
|
223
|
+
maxPrice: zod.z.number().describe("Maximum listing price"),
|
|
224
|
+
q1Price: zod.z.number().describe("25th percentile price (rounded)"),
|
|
225
|
+
q3Price: zod.z.number().describe("75th percentile price (rounded)"),
|
|
226
|
+
avgDaysOnMarket: zod.z.number().describe("Average days on market across cohort (rounded)"),
|
|
227
|
+
avgOdometer: zod.z.number().describe("Average odometer reading across cohort (rounded)")
|
|
228
|
+
});
|
|
229
|
+
var priceDistributionSchema = zod.z.object({
|
|
230
|
+
bucketMin: zod.z.number().describe("Inclusive lower bound of the bucket"),
|
|
231
|
+
bucketMax: zod.z.number().describe(
|
|
232
|
+
"Inclusive upper bound for the last bucket, exclusive for others"
|
|
233
|
+
),
|
|
234
|
+
count: zod.z.number().describe("Number of listings within the bucket bounds"),
|
|
235
|
+
percentage: zod.z.number().describe("Percentage of total listings that fall into the bucket")
|
|
236
|
+
}).describe("A single price histogram bucket.");
|
|
237
|
+
zod.z.object({
|
|
238
|
+
distribution: zod.z.array(priceDistributionSchema).describe("Price distribution for a make/model/year cohort")
|
|
239
|
+
});
|
|
240
|
+
var odometerSegmentSchema = zod.z.object({
|
|
241
|
+
odometerMin: zod.z.number().describe("Inclusive lower bound of odometer segment"),
|
|
242
|
+
odometerMax: zod.z.number().describe("Inclusive upper bound for last segment, exclusive for others"),
|
|
243
|
+
listings: zod.z.number().describe("Number of listings within this odometer band"),
|
|
244
|
+
avgPrice: zod.z.number().describe("Average price within the segment (rounded)"),
|
|
245
|
+
avgOdometer: zod.z.number().describe("Average odometer within the segment (rounded)"),
|
|
246
|
+
minPrice: zod.z.number().describe("Minimum observed price in the segment"),
|
|
247
|
+
maxPrice: zod.z.number().describe("Maximum observed price in the segment")
|
|
248
|
+
});
|
|
249
|
+
zod.z.object({
|
|
250
|
+
segments: zod.z.array(odometerSegmentSchema).describe("Odometer analysis for a make/model/year cohort")
|
|
251
|
+
});
|
|
252
|
+
var geographicMarketSchema = zod.z.object({
|
|
253
|
+
state: zod.z.string().describe("Two-letter region code (e.g. US state or CA province)"),
|
|
254
|
+
listings: zod.z.number().describe("Number of listings in the region"),
|
|
255
|
+
avgPrice: zod.z.number().describe("Average listing price in region (rounded)"),
|
|
256
|
+
medianPrice: zod.z.number().describe("Median listing price in region (rounded)"),
|
|
257
|
+
avgOdometer: zod.z.number().describe("Average odometer reading in region (rounded)"),
|
|
258
|
+
avgDaysOnMarket: zod.z.number().describe("Average days on market in region (rounded)"),
|
|
259
|
+
centerLat: zod.z.number().describe("Approximate geographic center latitude of listings in region"),
|
|
260
|
+
centerLng: zod.z.number().describe("Approximate geographic center longitude of listings in region")
|
|
261
|
+
});
|
|
262
|
+
zod.z.object({
|
|
263
|
+
markets: zod.z.array(geographicMarketSchema).describe("Geographic analysis for a make/model/year cohort")
|
|
264
|
+
});
|
|
265
|
+
var timeSeriesPointSchema = zod.z.object({
|
|
266
|
+
period: zod.z.coerce.date().describe("Start of period (Monday for week, first day for month)"),
|
|
267
|
+
newListings: zod.z.number().describe("Number of new listings observed within the period"),
|
|
268
|
+
avgPrice: zod.z.number().describe("Period average listing price (rounded)"),
|
|
269
|
+
avgOdometer: zod.z.number().describe("Period average odometer (rounded)"),
|
|
270
|
+
priceChangePct: zod.z.number().describe(
|
|
271
|
+
"Price change vs previous period in percent (one decimal), if applicable"
|
|
272
|
+
)
|
|
273
|
+
});
|
|
274
|
+
zod.z.object({
|
|
275
|
+
trends: zod.z.array(timeSeriesPointSchema).describe("Time series data for a make/model/year cohort")
|
|
276
|
+
});
|
|
277
|
+
zod.z.object({
|
|
278
|
+
similarListings: zod.z.array(
|
|
279
|
+
zod.z.object({
|
|
280
|
+
id: zod.z.string(),
|
|
281
|
+
price: zod.z.number(),
|
|
282
|
+
odometer: zod.z.number(),
|
|
283
|
+
vin: zod.z.string(),
|
|
284
|
+
year: zod.z.number(),
|
|
285
|
+
make: zod.z.string(),
|
|
286
|
+
model: zod.z.string(),
|
|
287
|
+
trim: zod.z.string().nullable(),
|
|
288
|
+
listingDate: zod.z.coerce.date(),
|
|
289
|
+
daysOnMarket: zod.z.number(),
|
|
290
|
+
location: zod.z.string().nullable()
|
|
291
|
+
})
|
|
292
|
+
),
|
|
293
|
+
priceAnalysis: zod.z.object({
|
|
294
|
+
count: zod.z.number(),
|
|
295
|
+
min: zod.z.number(),
|
|
296
|
+
max: zod.z.number(),
|
|
297
|
+
average: zod.z.number(),
|
|
298
|
+
median: zod.z.number(),
|
|
299
|
+
standardDev: zod.z.number(),
|
|
300
|
+
priceDistribution: zod.z.array(
|
|
301
|
+
zod.z.object({
|
|
302
|
+
range: zod.z.string(),
|
|
303
|
+
count: zod.z.number(),
|
|
304
|
+
percentage: zod.z.number()
|
|
305
|
+
})
|
|
306
|
+
)
|
|
307
|
+
}),
|
|
308
|
+
marketTrends: zod.z.object({
|
|
309
|
+
averageDaysOnMarket: zod.z.number(),
|
|
310
|
+
priceTrend: zod.z.number(),
|
|
311
|
+
listingVolume: zod.z.number()
|
|
312
|
+
}),
|
|
313
|
+
pricingGuidance: zod.z.object({
|
|
314
|
+
suggested: zod.z.number(),
|
|
315
|
+
confidence: zod.z.enum(["low", "medium", "high"])
|
|
316
|
+
})
|
|
317
|
+
});
|
|
318
|
+
zod.z.object({
|
|
319
|
+
id: zod.z.string().describe("Listing Id"),
|
|
320
|
+
price: zod.z.number().describe("Listing price"),
|
|
321
|
+
odometer: zod.z.number().describe("Odometer reading"),
|
|
322
|
+
trim: zod.z.string().nullable().describe("Vehicle trim"),
|
|
323
|
+
daysonmarket: zod.z.coerce.number().describe("Days on market"),
|
|
324
|
+
city: zod.z.string().nullable().describe("City"),
|
|
325
|
+
state: zod.z.string().nullable().describe("State"),
|
|
326
|
+
pricepercentile: zod.z.coerce.number().describe("Price percentile"),
|
|
327
|
+
pricevsmedian: zod.z.coerce.number().describe("Price vs median"),
|
|
328
|
+
pricecategory: zod.z.string().describe("Price category"),
|
|
329
|
+
marketaverage: zod.z.coerce.number().describe("Market average price")
|
|
330
|
+
});
|
|
331
|
+
zod.z.object({
|
|
332
|
+
overview: zod.z.object({
|
|
333
|
+
totalListings: zod.z.number(),
|
|
334
|
+
avgPrice: zod.z.number(),
|
|
335
|
+
medianPrice: zod.z.number(),
|
|
336
|
+
minPrice: zod.z.number(),
|
|
337
|
+
maxPrice: zod.z.number(),
|
|
338
|
+
stdDev: zod.z.number()
|
|
339
|
+
}),
|
|
340
|
+
priceDistribution: zod.z.array(
|
|
341
|
+
zod.z.object({
|
|
342
|
+
range: zod.z.string(),
|
|
343
|
+
count: zod.z.number()
|
|
344
|
+
})
|
|
345
|
+
).describe(
|
|
346
|
+
"Distribution of price ranges, e.g. [{ 'range': '$10,000 - $15,000', 'count': 100 }, { 'range': '$15,000 - $20,000', 'count': 50 }]"
|
|
347
|
+
),
|
|
348
|
+
makeDistribution: zod.z.array(
|
|
349
|
+
zod.z.object({
|
|
350
|
+
make: zod.z.string(),
|
|
351
|
+
count: zod.z.number()
|
|
352
|
+
})
|
|
353
|
+
).describe(
|
|
354
|
+
"Distribution of makes, e.g. [{ 'make': 'Honda', 'count': 100 }, { 'make': 'Toyota', 'count': 50 }]"
|
|
355
|
+
),
|
|
356
|
+
modelDistribution: zod.z.record(
|
|
357
|
+
zod.z.string(),
|
|
358
|
+
zod.z.array(
|
|
359
|
+
zod.z.object({
|
|
360
|
+
model: zod.z.string(),
|
|
361
|
+
count: zod.z.number()
|
|
362
|
+
})
|
|
363
|
+
)
|
|
364
|
+
).describe(
|
|
365
|
+
"Distribution of models by make, e.g. { 'Honda': [{ 'model': 'Civic', 'count': 100 }, { 'model': 'Accord', 'count': 50 }] }"
|
|
366
|
+
),
|
|
367
|
+
yearDistribution: zod.z.array(
|
|
368
|
+
zod.z.object({
|
|
369
|
+
range: zod.z.string(),
|
|
370
|
+
count: zod.z.number()
|
|
371
|
+
})
|
|
372
|
+
),
|
|
373
|
+
daysOnMarketByPrice: zod.z.array(
|
|
374
|
+
zod.z.object({
|
|
375
|
+
range: zod.z.string(),
|
|
376
|
+
avgDays: zod.z.number()
|
|
377
|
+
})
|
|
378
|
+
)
|
|
379
|
+
});
|
|
380
|
+
var trimBreakdownSchema = zod.z.object({
|
|
381
|
+
trim: zod.z.string().nullable().describe("Vehicle trim name"),
|
|
382
|
+
listings: zod.z.number().describe("Number of listings with this trim"),
|
|
383
|
+
avgPrice: zod.z.number().describe("Average listing price for this trim (rounded)"),
|
|
384
|
+
medianPrice: zod.z.number().describe("Median listing price for this trim (rounded)"),
|
|
385
|
+
minPrice: zod.z.number().describe("Minimum listing price for this trim"),
|
|
386
|
+
maxPrice: zod.z.number().describe("Maximum listing price for this trim"),
|
|
387
|
+
avgOdometer: zod.z.number().describe("Average odometer reading for this trim (rounded)"),
|
|
388
|
+
avgDaysOnMarket: zod.z.number().describe("Average days on market for this trim (rounded)"),
|
|
389
|
+
priceVsMarket: zod.z.number().describe("Percentage difference from overall market average")
|
|
390
|
+
});
|
|
391
|
+
zod.z.object({
|
|
392
|
+
vehicle: zod.z.string().describe("Human-readable vehicle label, e.g. '2022 Honda Civic'"),
|
|
393
|
+
totalListings: zod.z.number().describe("Total number of listings across all trims"),
|
|
394
|
+
overallAvgPrice: zod.z.number().describe("Overall average price across all trims"),
|
|
395
|
+
overallMedianPrice: zod.z.number().describe("Overall median price across all trims"),
|
|
396
|
+
trims: zod.z.array(trimBreakdownSchema).describe("Breakdown of prices by trim")
|
|
397
|
+
});
|
|
398
|
+
zod.z.object({
|
|
399
|
+
make: zod.z.string().describe("Vehicle make (e.g., 'Toyota')"),
|
|
400
|
+
model: zod.z.string().describe("Vehicle model (e.g., 'Camry')"),
|
|
401
|
+
year: zod.z.number().int().min(1900).max(2100).describe("Model year"),
|
|
402
|
+
lat: zod.z.number().min(-90).max(90).describe("Latitude of search center"),
|
|
403
|
+
lng: zod.z.number().min(-180).max(180).describe("Longitude of search center"),
|
|
404
|
+
radius: zod.z.number().min(10).max(500).default(75).describe("Search radius in kilometers (default 75km)")
|
|
405
|
+
});
|
|
406
|
+
var marketComparisonSchema = zod.z.object({
|
|
407
|
+
localAvgPrice: zod.z.number().describe("Local average price"),
|
|
408
|
+
nationalAvgPrice: zod.z.number().describe("National average price"),
|
|
409
|
+
priceDifferencePercent: zod.z.number().describe("Percentage difference (positive = local is higher)"),
|
|
410
|
+
localListings: zod.z.number().describe("Number of local listings"),
|
|
411
|
+
nationalListings: zod.z.number().describe("Total national listings")
|
|
412
|
+
});
|
|
413
|
+
zod.z.object({
|
|
414
|
+
vehicle: zod.z.string().describe("Vehicle label (e.g., '2022 Toyota Camry')"),
|
|
415
|
+
location: zod.z.object({
|
|
416
|
+
city: zod.z.string().nullable().describe("Nearest city name"),
|
|
417
|
+
province: zod.z.string().nullable().describe("Province/state"),
|
|
418
|
+
lat: zod.z.number().describe("Search center latitude"),
|
|
419
|
+
lng: zod.z.number().describe("Search center longitude"),
|
|
420
|
+
radiusKm: zod.z.number().describe("Search radius used")
|
|
421
|
+
}),
|
|
422
|
+
totalListings: zod.z.number().describe("Total listings found in area"),
|
|
423
|
+
pricing: zod.z.object({
|
|
424
|
+
avgPrice: zod.z.number().describe("Average listing price in the area"),
|
|
425
|
+
medianPrice: zod.z.number().describe("Median listing price in the area"),
|
|
426
|
+
minPrice: zod.z.number().describe("Minimum listing price found"),
|
|
427
|
+
maxPrice: zod.z.number().describe("Maximum listing price found"),
|
|
428
|
+
q1Price: zod.z.number().describe("25th percentile price"),
|
|
429
|
+
q3Price: zod.z.number().describe("75th percentile price")
|
|
430
|
+
}),
|
|
431
|
+
comparison: marketComparisonSchema,
|
|
432
|
+
priceDistribution: zod.z.array(
|
|
433
|
+
zod.z.object({
|
|
434
|
+
range: zod.z.string().describe("Price range label"),
|
|
435
|
+
count: zod.z.number().describe("Number of listings in this range")
|
|
436
|
+
})
|
|
437
|
+
),
|
|
438
|
+
odometer: zod.z.object({
|
|
439
|
+
avgOdometer: zod.z.number().describe("Average odometer reading"),
|
|
440
|
+
minOdometer: zod.z.number().describe("Minimum odometer"),
|
|
441
|
+
maxOdometer: zod.z.number().describe("Maximum odometer")
|
|
442
|
+
}),
|
|
443
|
+
daysOnMarket: zod.z.object({
|
|
444
|
+
avg: zod.z.number().describe("Average days on market"),
|
|
445
|
+
median: zod.z.number().describe("Median days on market")
|
|
446
|
+
})
|
|
447
|
+
});
|
|
448
|
+
var demandMatrixCellSchema = zod.z.object({
|
|
449
|
+
count: zod.z.number().describe("Number of listings in this cell"),
|
|
450
|
+
avgPrice: zod.z.number().describe("Average price in this cell"),
|
|
451
|
+
avgDaysToSell: zod.z.number().describe("Average days to sell in this cell")
|
|
452
|
+
});
|
|
453
|
+
var demandMatrixRowSchema = zod.z.object({
|
|
454
|
+
priceBand: zod.z.string().describe("Price band label (e.g., 'P10-P25')"),
|
|
455
|
+
priceMin: zod.z.number().describe("Minimum price in this band"),
|
|
456
|
+
priceMax: zod.z.number().describe("Maximum price in this band"),
|
|
457
|
+
cells: zod.z.array(demandMatrixCellSchema).describe("Cells for each turn rate band")
|
|
458
|
+
});
|
|
459
|
+
zod.z.object({
|
|
460
|
+
vehicle: zod.z.string().describe("Vehicle label (e.g., '2022 Honda Civic')"),
|
|
461
|
+
totalListings: zod.z.number().describe("Total listings analyzed"),
|
|
462
|
+
totalSold: zod.z.number().describe("Total sold/removed listings used for turn rate"),
|
|
463
|
+
turnRateBands: zod.z.array(zod.z.string()).describe("Turn rate band labels (e.g., ['0-7d', '7-14d', ...])"),
|
|
464
|
+
priceBands: zod.z.array(demandMatrixRowSchema).describe("Price band rows with cell data"),
|
|
465
|
+
summary: zod.z.object({
|
|
466
|
+
medianPrice: zod.z.number().describe("Median price across all listings"),
|
|
467
|
+
medianDaysToSell: zod.z.number().describe("Median days to sell"),
|
|
468
|
+
fastestPriceBand: zod.z.string().nullable().describe("Price band with fastest turn"),
|
|
469
|
+
sweetSpot: zod.z.object({
|
|
470
|
+
priceBand: zod.z.string(),
|
|
471
|
+
turnRateBand: zod.z.string(),
|
|
472
|
+
count: zod.z.number()
|
|
473
|
+
}).nullable().describe("Optimal price/turn rate combination")
|
|
474
|
+
})
|
|
475
|
+
});
|
|
476
|
+
var sortFieldMap = {
|
|
477
|
+
price: "price",
|
|
478
|
+
year: "year",
|
|
479
|
+
odometer: "odometer",
|
|
480
|
+
createdat: "createdAt",
|
|
481
|
+
random: "random",
|
|
482
|
+
score: "score"
|
|
483
|
+
};
|
|
484
|
+
var listingSortFieldsSchema = zod.z.string().transform((val) => sortFieldMap[val.toLowerCase()]).refine((val) => val !== void 0, {
|
|
485
|
+
message: "Invalid sort field. Expected: price, year, odometer, createdAt, random, or score"
|
|
486
|
+
});
|
|
487
|
+
var listingSortSchema = zod.z.object({
|
|
488
|
+
field: listingSortFieldsSchema,
|
|
489
|
+
direction: sortDirectionsSchema
|
|
490
|
+
});
|
|
491
|
+
var listingFiltersSchema = zod.z.object({
|
|
492
|
+
ids: zod.z.array(zod.z.string()).optional().describe('An array of listing IDs to fetch directly. Example: ["abc-123", "def-456"]'),
|
|
493
|
+
makes: zod.z.array(zod.z.string()).optional().describe('An array of vehicle makes. Example: ["Toyota", "Honda"]'),
|
|
494
|
+
models: zod.z.record(zod.z.string(), zod.z.array(zod.z.string())).describe(
|
|
495
|
+
'An object with vehicle makes as keys and an array of models as values. Example: {"Toyota": ["Corolla", "Camry"], "Honda": ["Civic"]}'
|
|
496
|
+
).optional(),
|
|
497
|
+
trims: zod.z.array(zod.z.string()).optional().describe('An array of vehicle trims. Example: ["LE", "SE"]'),
|
|
498
|
+
year: rangeSchema(1900, 2030).optional().describe(
|
|
499
|
+
"An object with 'min' and 'max' properties representing the year range. Example: {min: 2010, max: 2020}"
|
|
500
|
+
),
|
|
501
|
+
price: rangeSchema(0, 1e6).optional().describe(
|
|
502
|
+
"An object with 'min' and 'max' properties representing the price range. Example: {min: 10000, max: 20000}"
|
|
503
|
+
),
|
|
504
|
+
odometer: rangeSchema(0, 1e6).optional().describe(
|
|
505
|
+
"An object with 'min' and 'max' properties representing the odometer range. Example: {min: 0, max: 50000}"
|
|
506
|
+
),
|
|
507
|
+
saleTypes: zod.z.array(zod.z.string()).optional().describe('An array of sale types. Example: ["new", "used"]'),
|
|
508
|
+
bodyStyles: zod.z.array(zod.z.string()).optional().describe('An array of body styles. Example: ["SUV", "Sedan"]'),
|
|
509
|
+
fuelTypes: zod.z.array(zod.z.string()).optional().describe(
|
|
510
|
+
'An array of fuel types. Example: ["Gasoline", "Electric", "Hybrid"]'
|
|
511
|
+
),
|
|
512
|
+
exteriorColors: zod.z.array(zod.z.string()).optional().describe('An array of exterior colors. Example: ["Red", "Blue"]'),
|
|
513
|
+
interiorColors: zod.z.array(zod.z.string()).optional().describe('An array of interior colors. Example: ["Black", "Beige"]'),
|
|
514
|
+
location: locationSchema.optional(),
|
|
515
|
+
sellers: zod.z.array(zod.z.string()).optional().describe("An array of seller IDs. Example: ['123', '456']"),
|
|
516
|
+
createdAfter: timestampSchema.optional().describe("Filter listings created after this timestamp"),
|
|
517
|
+
createdBefore: timestampSchema.optional().describe("Filter listings created before this timestamp"),
|
|
518
|
+
updatedAfter: timestampSchema.optional().describe("Filter listings updated after this timestamp"),
|
|
519
|
+
updatedBefore: timestampSchema.optional().describe("Filter listings updated before this timestamp")
|
|
520
|
+
});
|
|
521
|
+
var listingQuerySchema = zod.z.object({
|
|
522
|
+
filters: listingFiltersSchema.optional(),
|
|
523
|
+
sort: listingSortSchema.optional(),
|
|
524
|
+
pagination: paginationSchema.optional()
|
|
525
|
+
});
|
|
526
|
+
var listingSchema = zod.z.object({
|
|
527
|
+
id: zod.z.string(),
|
|
528
|
+
vin: zod.z.string(),
|
|
529
|
+
sellerId: zod.z.string(),
|
|
530
|
+
websiteDomain: zod.z.string(),
|
|
531
|
+
price: zod.z.number().positive(),
|
|
532
|
+
currency: zod.z.string().default("USD"),
|
|
533
|
+
odometer: zod.z.number().optional(),
|
|
534
|
+
sourceUri: zod.z.string(),
|
|
535
|
+
stockNumber: zod.z.string().optional().nullable(),
|
|
536
|
+
score: zod.z.number(),
|
|
537
|
+
status: zod.z.string(),
|
|
538
|
+
mediaCount: zod.z.number(),
|
|
539
|
+
createdAt: timestampSchema,
|
|
540
|
+
updatedAt: timestampSchema,
|
|
541
|
+
removedAt: timestampSchema.nullable(),
|
|
542
|
+
make: zod.z.string(),
|
|
543
|
+
model: zod.z.string(),
|
|
544
|
+
year: zod.z.number().int().min(1900).max(2030),
|
|
545
|
+
trim: zod.z.string().optional().nullable(),
|
|
546
|
+
bodyStyle: zod.z.string().optional().nullable(),
|
|
547
|
+
fuelType: zod.z.string().optional().nullable(),
|
|
548
|
+
driveTrain: zod.z.string().optional().nullable(),
|
|
549
|
+
transmission: zod.z.string().optional().nullable(),
|
|
550
|
+
engineSize: zod.z.string().optional().nullable(),
|
|
551
|
+
horsepower: zod.z.string().optional().nullable(),
|
|
552
|
+
torque: zod.z.string().optional().nullable(),
|
|
553
|
+
exteriorColor: zod.z.string().optional().nullable(),
|
|
554
|
+
interiorColor: zod.z.string().optional().nullable(),
|
|
555
|
+
condition: zod.z.enum(["new", "used", "certified"]),
|
|
556
|
+
seller: sellerSchema,
|
|
557
|
+
media: zod.z.array(mediaSchema),
|
|
558
|
+
dealership: dealershipSchema,
|
|
559
|
+
location: addressSchema,
|
|
560
|
+
report: vehicleReportSchema.nullable().optional()
|
|
561
|
+
});
|
|
562
|
+
zod.z.object({
|
|
563
|
+
listings: zod.z.array(listingSchema),
|
|
564
|
+
pagination: paginationSchema,
|
|
565
|
+
sort: listingSortSchema.optional(),
|
|
566
|
+
filters: listingFiltersSchema
|
|
567
|
+
});
|
|
568
|
+
zod.z.object({
|
|
569
|
+
count: zod.z.number().int().min(0),
|
|
570
|
+
filters: listingFiltersSchema
|
|
571
|
+
});
|
|
572
|
+
var facetItemSchema = zod.z.object({
|
|
573
|
+
value: zod.z.string(),
|
|
574
|
+
count: zod.z.number().int().min(0)
|
|
575
|
+
});
|
|
576
|
+
var histogramBucketSchema = zod.z.object({
|
|
577
|
+
min: zod.z.number(),
|
|
578
|
+
max: zod.z.number(),
|
|
579
|
+
count: zod.z.number().int().min(0)
|
|
580
|
+
});
|
|
581
|
+
zod.z.object({
|
|
582
|
+
makes: zod.z.array(facetItemSchema),
|
|
583
|
+
models: zod.z.array(
|
|
584
|
+
zod.z.object({
|
|
585
|
+
make: zod.z.string(),
|
|
586
|
+
model: zod.z.string(),
|
|
587
|
+
count: zod.z.number().int().min(0)
|
|
588
|
+
})
|
|
589
|
+
),
|
|
590
|
+
bodyStyles: zod.z.array(facetItemSchema),
|
|
591
|
+
fuelTypes: zod.z.array(facetItemSchema),
|
|
592
|
+
saleTypes: zod.z.array(facetItemSchema),
|
|
593
|
+
exteriorColors: zod.z.array(facetItemSchema),
|
|
594
|
+
years: zod.z.object({
|
|
595
|
+
min: zod.z.number().int(),
|
|
596
|
+
max: zod.z.number().int()
|
|
597
|
+
}),
|
|
598
|
+
prices: zod.z.object({
|
|
599
|
+
min: zod.z.number(),
|
|
600
|
+
max: zod.z.number(),
|
|
601
|
+
histogram: zod.z.array(histogramBucketSchema)
|
|
602
|
+
}),
|
|
603
|
+
odometer: zod.z.object({
|
|
604
|
+
min: zod.z.number(),
|
|
605
|
+
max: zod.z.number(),
|
|
606
|
+
histogram: zod.z.array(histogramBucketSchema)
|
|
607
|
+
}),
|
|
608
|
+
totalCount: zod.z.number().int().min(0),
|
|
609
|
+
filters: listingFiltersSchema
|
|
610
|
+
});
|
|
611
|
+
var sellerTypeSchema = zod.z.enum([
|
|
612
|
+
"individual",
|
|
613
|
+
"dealership",
|
|
614
|
+
"auction",
|
|
615
|
+
"aggregator"
|
|
616
|
+
]);
|
|
617
|
+
zod.z.object({
|
|
618
|
+
lat: zod.z.coerce.number().min(-90).max(90).optional(),
|
|
619
|
+
lng: zod.z.coerce.number().min(-180).max(180).optional(),
|
|
620
|
+
radius: zod.z.coerce.number().min(0.1).max(500).optional(),
|
|
621
|
+
name: zod.z.string().optional(),
|
|
622
|
+
country: zod.z.string().optional(),
|
|
623
|
+
sellerType: sellerTypeSchema.optional(),
|
|
624
|
+
websiteDomain: zod.z.string().optional(),
|
|
625
|
+
hasActiveListings: zod.z.preprocess(
|
|
626
|
+
(val) => val === "true" ? true : val === "false" ? false : val,
|
|
627
|
+
zod.z.boolean().default(false)
|
|
628
|
+
),
|
|
629
|
+
limit: zod.z.coerce.number().int().min(1).max(250).default(50),
|
|
630
|
+
offset: zod.z.coerce.number().int().min(0).default(0)
|
|
631
|
+
});
|
|
632
|
+
zod.z.object({
|
|
633
|
+
id: zod.z.string()
|
|
634
|
+
});
|
|
635
|
+
var locationAddressSchema = zod.z.object({
|
|
636
|
+
id: zod.z.number().nullable(),
|
|
637
|
+
street: zod.z.string().nullable(),
|
|
638
|
+
city: zod.z.string().nullable(),
|
|
639
|
+
state: zod.z.string().nullable(),
|
|
640
|
+
postalCode: zod.z.string().nullable(),
|
|
641
|
+
country: zod.z.string().nullable(),
|
|
642
|
+
latitude: zod.z.string().nullable(),
|
|
643
|
+
longitude: zod.z.string().nullable()
|
|
644
|
+
}).nullable();
|
|
645
|
+
var locationDealershipSchema = zod.z.object({
|
|
646
|
+
id: zod.z.string(),
|
|
647
|
+
name: zod.z.string(),
|
|
648
|
+
primaryDomain: zod.z.string().nullable()
|
|
649
|
+
}).nullable();
|
|
650
|
+
var locationResultSchema = zod.z.object({
|
|
651
|
+
id: zod.z.string(),
|
|
652
|
+
name: zod.z.string(),
|
|
653
|
+
slug: zod.z.string(),
|
|
654
|
+
type: sellerTypeSchema,
|
|
655
|
+
email: zod.z.string().nullable(),
|
|
656
|
+
phone: zod.z.string().nullable(),
|
|
657
|
+
// Google My Business enhanced fields
|
|
658
|
+
gmbPhone: zod.z.string().nullable().optional(),
|
|
659
|
+
gmbRating: zod.z.string().nullable().optional(),
|
|
660
|
+
gmbReviewCount: zod.z.number().nullable().optional(),
|
|
661
|
+
address: locationAddressSchema,
|
|
662
|
+
dealership: locationDealershipSchema,
|
|
663
|
+
totalActiveListings: zod.z.number(),
|
|
664
|
+
distance: zod.z.number().optional()
|
|
665
|
+
});
|
|
666
|
+
zod.z.object({
|
|
667
|
+
results: zod.z.array(locationResultSchema),
|
|
668
|
+
meta: zod.z.object({
|
|
669
|
+
total: zod.z.number(),
|
|
670
|
+
params: zod.z.any()
|
|
671
|
+
})
|
|
672
|
+
});
|
|
673
|
+
locationResultSchema.omit({
|
|
674
|
+
distance: true
|
|
675
|
+
});
|
|
676
|
+
var ConnectorType = /* @__PURE__ */ ((ConnectorType2) => {
|
|
677
|
+
ConnectorType2[ConnectorType2["TYPE_1"] = 1] = "TYPE_1";
|
|
678
|
+
ConnectorType2[ConnectorType2["TYPE_2"] = 25] = "TYPE_2";
|
|
679
|
+
ConnectorType2[ConnectorType2["CCS_TYPE_1"] = 33] = "CCS_TYPE_1";
|
|
680
|
+
ConnectorType2[ConnectorType2["CCS_TYPE_2"] = 32] = "CCS_TYPE_2";
|
|
681
|
+
ConnectorType2[ConnectorType2["CHADEMO"] = 2] = "CHADEMO";
|
|
682
|
+
ConnectorType2[ConnectorType2["TESLA"] = 27] = "TESLA";
|
|
683
|
+
ConnectorType2[ConnectorType2["NACS"] = 31] = "NACS";
|
|
684
|
+
ConnectorType2[ConnectorType2["WALL"] = 28] = "WALL";
|
|
685
|
+
ConnectorType2[ConnectorType2["TYPE_3"] = 3] = "TYPE_3";
|
|
686
|
+
ConnectorType2[ConnectorType2["IEC_60309"] = 8] = "IEC_60309";
|
|
687
|
+
ConnectorType2[ConnectorType2["DOMESTIC"] = 10] = "DOMESTIC";
|
|
688
|
+
ConnectorType2[ConnectorType2["COMMANDO"] = 11] = "COMMANDO";
|
|
689
|
+
ConnectorType2[ConnectorType2["GB_T"] = 13] = "GB_T";
|
|
690
|
+
ConnectorType2[ConnectorType2["UNSPECIFIED"] = 0] = "UNSPECIFIED";
|
|
691
|
+
return ConnectorType2;
|
|
692
|
+
})(ConnectorType || {});
|
|
693
|
+
var ChargingLevel = /* @__PURE__ */ ((ChargingLevel2) => {
|
|
694
|
+
ChargingLevel2[ChargingLevel2["LEVEL_1"] = 1] = "LEVEL_1";
|
|
695
|
+
ChargingLevel2[ChargingLevel2["LEVEL_2"] = 2] = "LEVEL_2";
|
|
696
|
+
ChargingLevel2[ChargingLevel2["LEVEL_3"] = 3] = "LEVEL_3";
|
|
697
|
+
ChargingLevel2[ChargingLevel2["UNSPECIFIED"] = 0] = "UNSPECIFIED";
|
|
698
|
+
return ChargingLevel2;
|
|
699
|
+
})(ChargingLevel || {});
|
|
700
|
+
var StationStatus = /* @__PURE__ */ ((StationStatus2) => {
|
|
701
|
+
StationStatus2["OPERATIONAL"] = "Operational";
|
|
702
|
+
StationStatus2["PLANNED"] = "Planned";
|
|
703
|
+
StationStatus2["NON_OPERATIONAL"] = "NonOperational";
|
|
704
|
+
StationStatus2["UNKNOWN"] = "Unknown";
|
|
705
|
+
return StationStatus2;
|
|
706
|
+
})(StationStatus || {});
|
|
707
|
+
zod.z.nativeEnum(ConnectorType);
|
|
708
|
+
zod.z.nativeEnum(ChargingLevel);
|
|
709
|
+
zod.z.nativeEnum(StationStatus);
|
|
710
|
+
var chargingConnectionSchema = zod.z.object({
|
|
711
|
+
connectionTypeId: zod.z.nativeEnum(ConnectorType),
|
|
712
|
+
connectionType: zod.z.string(),
|
|
713
|
+
powerKW: zod.z.number(),
|
|
714
|
+
currentType: zod.z.enum(["AC", "DC"]),
|
|
715
|
+
level: zod.z.nativeEnum(ChargingLevel),
|
|
716
|
+
voltage: zod.z.number(),
|
|
717
|
+
amperage: zod.z.number(),
|
|
718
|
+
pricing: zod.z.object({
|
|
719
|
+
costPerKWh: zod.z.number().nullable(),
|
|
720
|
+
costPerMinute: zod.z.number().nullable(),
|
|
721
|
+
costPerSession: zod.z.number().nullable(),
|
|
722
|
+
currency: zod.z.string()
|
|
723
|
+
}).optional()
|
|
724
|
+
});
|
|
725
|
+
var chargingStationSchema = zod.z.object({
|
|
726
|
+
id: zod.z.string(),
|
|
727
|
+
name: zod.z.string(),
|
|
728
|
+
address: zod.z.object({
|
|
729
|
+
addressLine1: zod.z.string(),
|
|
730
|
+
addressLine2: zod.z.string().optional().nullable(),
|
|
731
|
+
town: zod.z.string(),
|
|
732
|
+
stateOrProvince: zod.z.string(),
|
|
733
|
+
postcode: zod.z.string(),
|
|
734
|
+
countryCode: zod.z.string()
|
|
735
|
+
}),
|
|
736
|
+
location: zod.z.object({
|
|
737
|
+
latitude: zod.z.number(),
|
|
738
|
+
longitude: zod.z.number()
|
|
739
|
+
}),
|
|
740
|
+
connections: zod.z.array(chargingConnectionSchema),
|
|
741
|
+
status: zod.z.nativeEnum(StationStatus),
|
|
742
|
+
network: zod.z.string().nullable(),
|
|
743
|
+
operator: zod.z.string().nullable(),
|
|
744
|
+
dateCreated: zod.z.string(),
|
|
745
|
+
dateLastVerified: zod.z.string().nullable(),
|
|
746
|
+
usage: zod.z.string().nullable(),
|
|
747
|
+
supportPhone: zod.z.string().nullable(),
|
|
748
|
+
supportUrl: zod.z.string().nullable(),
|
|
749
|
+
isMembershipRequired: zod.z.boolean(),
|
|
750
|
+
isPayAtLocation: zod.z.boolean(),
|
|
751
|
+
photos: zod.z.array(zod.z.string()).optional(),
|
|
752
|
+
rating: zod.z.number().optional()
|
|
753
|
+
});
|
|
754
|
+
zod.z.object({
|
|
755
|
+
country: zod.z.string().default("US").describe("The country to search in"),
|
|
756
|
+
region: zod.z.string().optional().describe("The region to search in"),
|
|
757
|
+
lat: zod.z.coerce.number().optional().describe("The latitude to search in"),
|
|
758
|
+
lng: zod.z.coerce.number().optional().describe("The longitude to search in"),
|
|
759
|
+
radius: zod.z.coerce.number().optional().describe("The radius to search in"),
|
|
760
|
+
connector: zod.z.array(zod.z.nativeEnum(ConnectorType)).optional().describe("The connector types to search for"),
|
|
761
|
+
minPower: zod.z.coerce.number().optional().describe("The minimum power to search for"),
|
|
762
|
+
limit: zod.z.coerce.number().optional().describe("The number of results to return"),
|
|
763
|
+
includeInactive: zod.z.boolean().optional().describe("Whether to include inactive stations"),
|
|
764
|
+
includePhotos: zod.z.coerce.boolean().optional().describe("Whether to include photos")
|
|
765
|
+
});
|
|
766
|
+
zod.z.object({
|
|
767
|
+
stations: zod.z.array(chargingStationSchema),
|
|
768
|
+
totalCount: zod.z.number(),
|
|
769
|
+
location: zod.z.object({
|
|
770
|
+
name: zod.z.string().nullable(),
|
|
771
|
+
countryCode: zod.z.string(),
|
|
772
|
+
regionCode: zod.z.string().nullable()
|
|
773
|
+
})
|
|
774
|
+
});
|
|
775
|
+
zod.z.object({
|
|
776
|
+
id: zod.z.string().min(1)
|
|
777
|
+
});
|
|
778
|
+
zod.z.object({
|
|
779
|
+
station: chargingStationSchema
|
|
780
|
+
});
|
|
781
|
+
var FuelType = /* @__PURE__ */ ((FuelType2) => {
|
|
782
|
+
FuelType2[FuelType2["REGULAR"] = 1] = "REGULAR";
|
|
783
|
+
FuelType2[FuelType2["MIDGRADE"] = 2] = "MIDGRADE";
|
|
784
|
+
FuelType2[FuelType2["PREMIUM"] = 3] = "PREMIUM";
|
|
785
|
+
FuelType2[FuelType2["DIESEL"] = 4] = "DIESEL";
|
|
786
|
+
FuelType2[FuelType2["E85"] = 5] = "E85";
|
|
787
|
+
FuelType2[FuelType2["E15"] = 6] = "E15";
|
|
788
|
+
FuelType2[FuelType2["PROPANE"] = 7] = "PROPANE";
|
|
789
|
+
FuelType2[FuelType2["BIODIESEL"] = 8] = "BIODIESEL";
|
|
790
|
+
FuelType2[FuelType2["CNG"] = 9] = "CNG";
|
|
791
|
+
FuelType2[FuelType2["LNG"] = 10] = "LNG";
|
|
792
|
+
return FuelType2;
|
|
793
|
+
})(FuelType || {});
|
|
794
|
+
var fuelTypeEnum = zod.z.nativeEnum(FuelType);
|
|
795
|
+
var fuelStationSchema = zod.z.object({
|
|
796
|
+
id: zod.z.string(),
|
|
797
|
+
name: zod.z.string(),
|
|
798
|
+
address: zod.z.object({
|
|
799
|
+
line1: zod.z.string(),
|
|
800
|
+
line2: zod.z.string().optional(),
|
|
801
|
+
locality: zod.z.string(),
|
|
802
|
+
region: zod.z.string(),
|
|
803
|
+
postalCode: zod.z.string(),
|
|
804
|
+
country: zod.z.string()
|
|
805
|
+
}),
|
|
806
|
+
location: zod.z.object({
|
|
807
|
+
latitude: zod.z.number(),
|
|
808
|
+
longitude: zod.z.number()
|
|
809
|
+
}),
|
|
810
|
+
price: zod.z.object({
|
|
811
|
+
credit: zod.z.number().nullable(),
|
|
812
|
+
cash: zod.z.number().nullable(),
|
|
813
|
+
postedTime: zod.z.string().nullable(),
|
|
814
|
+
formattedPrice: zod.z.string().nullable(),
|
|
815
|
+
reportedBy: zod.z.string().nullable()
|
|
816
|
+
}),
|
|
817
|
+
amenities: zod.z.array(zod.z.string()),
|
|
818
|
+
brands: zod.z.array(
|
|
819
|
+
zod.z.object({
|
|
820
|
+
id: zod.z.string(),
|
|
821
|
+
name: zod.z.string(),
|
|
822
|
+
type: zod.z.string(),
|
|
823
|
+
imageUrl: zod.z.string().optional().nullable()
|
|
824
|
+
})
|
|
825
|
+
),
|
|
826
|
+
rating: zod.z.number().nullable(),
|
|
827
|
+
ratingsCount: zod.z.number(),
|
|
828
|
+
reviews: zod.z.array(
|
|
829
|
+
zod.z.object({
|
|
830
|
+
rating: zod.z.number(),
|
|
831
|
+
review: zod.z.string(),
|
|
832
|
+
nickname: zod.z.string(),
|
|
833
|
+
date: zod.z.string()
|
|
834
|
+
})
|
|
835
|
+
),
|
|
836
|
+
fuels: zod.z.array(zod.z.string()),
|
|
837
|
+
isOpen: zod.z.boolean().optional()
|
|
838
|
+
});
|
|
839
|
+
zod.z.object({
|
|
840
|
+
current: zod.z.number().nullable(),
|
|
841
|
+
average: zod.z.number().nullable(),
|
|
842
|
+
postedTime: zod.z.string().nullable(),
|
|
843
|
+
unit: zod.z.string(),
|
|
844
|
+
isMetric: zod.z.boolean(),
|
|
845
|
+
fuelType: fuelTypeEnum,
|
|
846
|
+
fuelName: zod.z.string(),
|
|
847
|
+
location: zod.z.object({
|
|
848
|
+
name: zod.z.string().nullable(),
|
|
849
|
+
countryCode: zod.z.string(),
|
|
850
|
+
regionCode: zod.z.string().nullable(),
|
|
851
|
+
locationType: zod.z.string().nullable(),
|
|
852
|
+
nearbyLocalities: zod.z.array(zod.z.string())
|
|
853
|
+
}),
|
|
854
|
+
history: zod.z.array(
|
|
855
|
+
zod.z.object({
|
|
856
|
+
date: zod.z.string(),
|
|
857
|
+
price: zod.z.number(),
|
|
858
|
+
formattedPrice: zod.z.string()
|
|
859
|
+
})
|
|
860
|
+
),
|
|
861
|
+
stations: zod.z.array(fuelStationSchema)
|
|
862
|
+
});
|
|
863
|
+
zod.z.object({
|
|
864
|
+
// Coordinate-based search (preferred)
|
|
865
|
+
lat: zod.z.coerce.number().min(-90).max(90).optional(),
|
|
866
|
+
lng: zod.z.coerce.number().min(-180).max(180).optional(),
|
|
867
|
+
radius: zod.z.coerce.number().min(1).max(100).optional().default(10),
|
|
868
|
+
// km
|
|
869
|
+
// Region-based search (legacy)
|
|
870
|
+
country: zod.z.string().optional().default("US"),
|
|
871
|
+
region: zod.z.string().optional(),
|
|
872
|
+
city: zod.z.string().optional(),
|
|
873
|
+
// Filter options
|
|
874
|
+
fuelType: fuelTypeEnum.optional().default(1 /* REGULAR */),
|
|
875
|
+
limit: zod.z.coerce.number().min(1).max(50).optional().default(50),
|
|
876
|
+
distanceFormat: zod.z.enum(["auto", "mi", "km"]).optional().default("auto")
|
|
877
|
+
}).refine(
|
|
878
|
+
(data) => {
|
|
879
|
+
const hasCoords = data.lat !== void 0 && data.lng !== void 0;
|
|
880
|
+
const hasRegion = data.country !== void 0;
|
|
881
|
+
return hasCoords || hasRegion;
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
message: "Either lat/lng coordinates or country must be provided"
|
|
885
|
+
}
|
|
886
|
+
).refine(
|
|
887
|
+
(data) => {
|
|
888
|
+
if (data.lat !== void 0 && data.lng === void 0) {
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
891
|
+
if (data.lng !== void 0 && data.lat === void 0) {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
return true;
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
message: "Both lat and lng must be provided together"
|
|
898
|
+
}
|
|
899
|
+
);
|
|
900
|
+
zod.z.object({
|
|
901
|
+
stationId: zod.z.string().min(1)
|
|
902
|
+
});
|
|
903
|
+
var regionSchema = zod.z.enum(["US", "CA", "EU"]);
|
|
904
|
+
zod.z.enum([
|
|
905
|
+
"gasoline",
|
|
906
|
+
"diesel",
|
|
907
|
+
"electric",
|
|
908
|
+
"hybrid",
|
|
909
|
+
"plugin_hybrid",
|
|
910
|
+
"lpg",
|
|
911
|
+
"cng",
|
|
912
|
+
"hydrogen"
|
|
913
|
+
]);
|
|
914
|
+
zod.z.enum(["FWD", "RWD", "AWD", "4WD"]);
|
|
915
|
+
zod.z.enum([
|
|
916
|
+
"manual",
|
|
917
|
+
"automatic",
|
|
918
|
+
"CVT",
|
|
919
|
+
"DCT",
|
|
920
|
+
"AMT",
|
|
921
|
+
"single_speed"
|
|
922
|
+
]);
|
|
923
|
+
zod.z.record(zod.z.string(), zod.z.unknown());
|
|
924
|
+
zod.z.record(zod.z.string(), zod.z.unknown());
|
|
925
|
+
var variantSchema = zod.z.object({
|
|
926
|
+
id: zod.z.string(),
|
|
927
|
+
make: zod.z.string(),
|
|
928
|
+
model: zod.z.string(),
|
|
929
|
+
year: zod.z.number(),
|
|
930
|
+
trim: zod.z.string().optional().nullable(),
|
|
931
|
+
msrp: zod.z.number().optional().nullable(),
|
|
932
|
+
bodyStyle: zod.z.string().optional().nullable(),
|
|
933
|
+
styleName: zod.z.string().optional().nullable(),
|
|
934
|
+
region: regionSchema.optional().nullable(),
|
|
935
|
+
/** Spec object - passthrough to preserve all fields from different data sources */
|
|
936
|
+
spec: zod.z.record(zod.z.string(), zod.z.unknown()).optional().nullable(),
|
|
937
|
+
extra: zod.z.record(zod.z.string(), zod.z.unknown()).optional().nullable()
|
|
938
|
+
});
|
|
939
|
+
zod.z.object({
|
|
940
|
+
make: zod.z.string().min(1, "Make is required")
|
|
941
|
+
});
|
|
942
|
+
zod.z.object({
|
|
943
|
+
id: zod.z.string()
|
|
944
|
+
});
|
|
945
|
+
zod.z.object({
|
|
946
|
+
listingId: zod.z.string()
|
|
947
|
+
});
|
|
948
|
+
zod.z.object({
|
|
949
|
+
vin: zod.z.string().length(17, "VIN must be exactly 17 characters")
|
|
950
|
+
});
|
|
951
|
+
zod.z.object({
|
|
952
|
+
make: zod.z.string().min(1, "Make is required"),
|
|
953
|
+
model: zod.z.string().min(1, "Model is required")
|
|
954
|
+
});
|
|
955
|
+
zod.z.object({
|
|
956
|
+
make: zod.z.string().min(1, "Make is required"),
|
|
957
|
+
year: zod.z.coerce.number().int().min(1900).max(2030)
|
|
958
|
+
});
|
|
959
|
+
zod.z.object({
|
|
960
|
+
make: zod.z.string().min(1, "Make is required"),
|
|
961
|
+
model: zod.z.string().min(1, "Model is required"),
|
|
962
|
+
year: zod.z.coerce.number().int().min(1900).max(2030)
|
|
963
|
+
});
|
|
964
|
+
zod.z.object({
|
|
965
|
+
limit: zod.z.coerce.number().int().min(1).max(1e3).optional()
|
|
966
|
+
});
|
|
967
|
+
zod.z.object({
|
|
968
|
+
page: zod.z.coerce.number().int().min(1).optional().default(1),
|
|
969
|
+
limit: zod.z.coerce.number().int().min(1).max(500).optional().default(200),
|
|
970
|
+
region: regionSchema.optional(),
|
|
971
|
+
bodyStyle: zod.z.string().optional()
|
|
972
|
+
});
|
|
973
|
+
zod.z.object({
|
|
974
|
+
region: regionSchema.optional()
|
|
975
|
+
});
|
|
976
|
+
zod.z.object({
|
|
977
|
+
make: zod.z.string().min(1, "Make is required"),
|
|
978
|
+
model: zod.z.string().min(1, "Model is required"),
|
|
979
|
+
year: zod.z.coerce.number().int().min(1900).max(2030),
|
|
980
|
+
limit: zod.z.coerce.number().int().min(1).max(100).optional(),
|
|
981
|
+
page: zod.z.coerce.number().int().min(1).optional(),
|
|
982
|
+
shotType: zod.z.enum([
|
|
983
|
+
"FQ",
|
|
984
|
+
"RQ",
|
|
985
|
+
"I",
|
|
986
|
+
"RI",
|
|
987
|
+
"S",
|
|
988
|
+
"CARGO",
|
|
989
|
+
"E",
|
|
990
|
+
"W",
|
|
991
|
+
"D",
|
|
992
|
+
"CC",
|
|
993
|
+
"F",
|
|
994
|
+
"R",
|
|
995
|
+
"DETAIL",
|
|
996
|
+
"B",
|
|
997
|
+
"O",
|
|
998
|
+
"PROFILE",
|
|
999
|
+
"ALL"
|
|
1000
|
+
]).optional(),
|
|
1001
|
+
category: zod.z.enum(["EXTERIOR", "INTERIOR"]).optional()
|
|
1002
|
+
});
|
|
1003
|
+
zod.z.object({
|
|
1004
|
+
make: zod.z.string().min(1, "Make is required"),
|
|
1005
|
+
model: zod.z.string().min(1, "Model is required"),
|
|
1006
|
+
year: zod.z.coerce.number().int().min(1900).max(2030)
|
|
1007
|
+
});
|
|
1008
|
+
var colorInfoSchema = zod.z.object({
|
|
1009
|
+
rgb: zod.z.string(),
|
|
1010
|
+
hex: zod.z.string(),
|
|
1011
|
+
name: zod.z.string()
|
|
1012
|
+
});
|
|
1013
|
+
zod.z.object({
|
|
1014
|
+
EXTERIOR: zod.z.array(colorInfoSchema).optional(),
|
|
1015
|
+
INTERIOR: zod.z.array(colorInfoSchema).optional()
|
|
1016
|
+
});
|
|
1017
|
+
var researchImageSchema = zod.z.object({
|
|
1018
|
+
url: zod.z.string(),
|
|
1019
|
+
make: zod.z.string().optional().nullable(),
|
|
1020
|
+
model: zod.z.string().optional().nullable(),
|
|
1021
|
+
year: zod.z.number().optional().nullable(),
|
|
1022
|
+
shotType: zod.z.string().optional().nullable(),
|
|
1023
|
+
category: zod.z.string().optional().nullable(),
|
|
1024
|
+
title: zod.z.string().optional().nullable(),
|
|
1025
|
+
color: zod.z.string().optional().nullable(),
|
|
1026
|
+
metadata: zod.z.any().optional().nullable()
|
|
1027
|
+
});
|
|
1028
|
+
var lineupItemSchema = zod.z.object({
|
|
1029
|
+
make: zod.z.string(),
|
|
1030
|
+
model: zod.z.string(),
|
|
1031
|
+
year: zod.z.number(),
|
|
1032
|
+
msrp: zod.z.number().optional().nullable(),
|
|
1033
|
+
images: zod.z.array(researchImageSchema).optional()
|
|
1034
|
+
});
|
|
1035
|
+
zod.z.object({
|
|
1036
|
+
data: zod.z.array(lineupItemSchema),
|
|
1037
|
+
total: zod.z.coerce.number(),
|
|
1038
|
+
page: zod.z.coerce.number(),
|
|
1039
|
+
limit: zod.z.coerce.number()
|
|
1040
|
+
});
|
|
1041
|
+
zod.z.array(variantSchema);
|
|
1042
|
+
variantSchema.nullable();
|
|
1043
|
+
zod.z.array(researchImageSchema);
|
|
1044
|
+
zod.z.object({
|
|
1045
|
+
makes: zod.z.array(zod.z.string().transform((val) => val.toUpperCase())).optional(),
|
|
1046
|
+
models: zod.z.array(zod.z.string().transform((val) => val.toUpperCase())).optional(),
|
|
1047
|
+
year: zod.z.object({
|
|
1048
|
+
min: zod.z.coerce.number().optional(),
|
|
1049
|
+
max: zod.z.coerce.number().optional()
|
|
1050
|
+
}).optional(),
|
|
1051
|
+
limit: zod.z.coerce.number().optional(),
|
|
1052
|
+
offset: zod.z.coerce.number().optional(),
|
|
1053
|
+
sort: zod.z.enum(["recall_date", "year", "make", "model"]).optional(),
|
|
1054
|
+
order: zod.z.enum(["asc", "desc"]).optional(),
|
|
1055
|
+
// Coerce country to country code
|
|
1056
|
+
country: zod.z.enum(["canada", "usa"]).optional().default("canada").transform((val) => val === "canada" ? "ca" : "us")
|
|
1057
|
+
});
|
|
1058
|
+
var transportCanadaRecallDetailSchema = zod.z.object({
|
|
1059
|
+
id: zod.z.string(),
|
|
1060
|
+
recallNumber: zod.z.string(),
|
|
1061
|
+
year: zod.z.number(),
|
|
1062
|
+
manufacturerRecallNumber: zod.z.string(),
|
|
1063
|
+
category: zod.z.string(),
|
|
1064
|
+
model: zod.z.string(),
|
|
1065
|
+
make: zod.z.string(),
|
|
1066
|
+
unitsAffected: zod.z.number(),
|
|
1067
|
+
systemType: zod.z.string(),
|
|
1068
|
+
notificationType: zod.z.string(),
|
|
1069
|
+
comment: zod.z.string(),
|
|
1070
|
+
dateYear: zod.z.number(),
|
|
1071
|
+
recallDate: zod.z.string(),
|
|
1072
|
+
processedAt: zod.z.string(),
|
|
1073
|
+
provider: zod.z.literal("Transport Canada")
|
|
1074
|
+
});
|
|
1075
|
+
var nhtsaRecallSummarySchema = zod.z.object({
|
|
1076
|
+
manufacturer: zod.z.string(),
|
|
1077
|
+
nhtsaCampaignNumber: zod.z.string(),
|
|
1078
|
+
parkIt: zod.z.boolean(),
|
|
1079
|
+
parkOutSide: zod.z.boolean(),
|
|
1080
|
+
overTheAirUpdate: zod.z.boolean(),
|
|
1081
|
+
nhtsaActionNumber: zod.z.string().optional(),
|
|
1082
|
+
reportReceivedDate: zod.z.string(),
|
|
1083
|
+
component: zod.z.string(),
|
|
1084
|
+
summary: zod.z.string(),
|
|
1085
|
+
consequence: zod.z.string(),
|
|
1086
|
+
remedy: zod.z.string(),
|
|
1087
|
+
notes: zod.z.string(),
|
|
1088
|
+
modelYear: zod.z.string(),
|
|
1089
|
+
make: zod.z.string(),
|
|
1090
|
+
model: zod.z.string(),
|
|
1091
|
+
provider: zod.z.literal("NHTSA")
|
|
1092
|
+
});
|
|
1093
|
+
var recallResponseSchema = zod.z.object({
|
|
1094
|
+
success: zod.z.boolean(),
|
|
1095
|
+
provider: zod.z.enum(["Transport Canada", "NHTSA"]).optional(),
|
|
1096
|
+
data: zod.z.array(
|
|
1097
|
+
zod.z.discriminatedUnion("provider", [
|
|
1098
|
+
transportCanadaRecallDetailSchema,
|
|
1099
|
+
nhtsaRecallSummarySchema
|
|
1100
|
+
])
|
|
1101
|
+
),
|
|
1102
|
+
meta: zod.z.object({
|
|
1103
|
+
make: zod.z.string().optional(),
|
|
1104
|
+
model: zod.z.string().optional(),
|
|
1105
|
+
startYear: zod.z.number().optional(),
|
|
1106
|
+
endYear: zod.z.number().optional(),
|
|
1107
|
+
modelYear: zod.z.number().optional(),
|
|
1108
|
+
recallNumber: zod.z.string().optional(),
|
|
1109
|
+
campaignNumber: zod.z.string().optional(),
|
|
1110
|
+
count: zod.z.number()
|
|
1111
|
+
})
|
|
1112
|
+
});
|
|
1113
|
+
zod.z.object({
|
|
1114
|
+
success: zod.z.boolean(),
|
|
1115
|
+
vin: zod.z.string(),
|
|
1116
|
+
vehicle: zod.z.object({
|
|
1117
|
+
make: zod.z.string(),
|
|
1118
|
+
model: zod.z.string(),
|
|
1119
|
+
year: zod.z.number()
|
|
1120
|
+
}),
|
|
1121
|
+
results: zod.z.array(recallResponseSchema),
|
|
1122
|
+
meta: zod.z.object({
|
|
1123
|
+
totalResults: zod.z.number(),
|
|
1124
|
+
providersSearched: zod.z.array(zod.z.string())
|
|
1125
|
+
})
|
|
1126
|
+
});
|
|
1127
|
+
var powertrainTypeSchema = zod.z.enum([
|
|
1128
|
+
"ice",
|
|
1129
|
+
"bev",
|
|
1130
|
+
"phev",
|
|
1131
|
+
"hev",
|
|
1132
|
+
"mhev",
|
|
1133
|
+
"fcev"
|
|
1134
|
+
]);
|
|
1135
|
+
var testCycleSchema = zod.z.enum(["epa", "wltp", "mixed"]);
|
|
1136
|
+
var efficiencySourceSchema = zod.z.enum(["epa", "tc", "uk-vca", "eu-eea"]);
|
|
1137
|
+
zod.z.object({
|
|
1138
|
+
makes: zod.z.array(zod.z.string().transform((val) => val.toUpperCase())).optional(),
|
|
1139
|
+
models: zod.z.array(zod.z.string().transform((val) => val.toUpperCase())).optional(),
|
|
1140
|
+
year: rangeSchema(1900, 2050).optional(),
|
|
1141
|
+
powertrainTypes: zod.z.array(powertrainTypeSchema).optional(),
|
|
1142
|
+
fuelTypes: zod.z.array(zod.z.string()).optional(),
|
|
1143
|
+
sources: zod.z.array(efficiencySourceSchema).optional(),
|
|
1144
|
+
testCycles: zod.z.array(testCycleSchema).optional(),
|
|
1145
|
+
limit: zod.z.coerce.number().min(1).max(250).optional(),
|
|
1146
|
+
offset: zod.z.coerce.number().min(0).optional(),
|
|
1147
|
+
sort: zod.z.enum([
|
|
1148
|
+
"make",
|
|
1149
|
+
"model",
|
|
1150
|
+
"year",
|
|
1151
|
+
"combined_l_per_100km",
|
|
1152
|
+
"combined_kwh_per_100km",
|
|
1153
|
+
"co2_grams_per_km",
|
|
1154
|
+
"electric_range_km"
|
|
1155
|
+
]).optional(),
|
|
1156
|
+
order: zod.z.enum(["asc", "desc"]).optional()
|
|
1157
|
+
});
|
|
1158
|
+
var efficiencyDetailSchema = zod.z.object({
|
|
1159
|
+
id: zod.z.number(),
|
|
1160
|
+
source: efficiencySourceSchema,
|
|
1161
|
+
sourceId: zod.z.string(),
|
|
1162
|
+
year: zod.z.number(),
|
|
1163
|
+
make: zod.z.string(),
|
|
1164
|
+
model: zod.z.string(),
|
|
1165
|
+
variant: zod.z.string().nullable(),
|
|
1166
|
+
powertrainType: powertrainTypeSchema,
|
|
1167
|
+
fuelType: zod.z.string(),
|
|
1168
|
+
transmission: zod.z.string().nullable(),
|
|
1169
|
+
driveType: zod.z.string().nullable(),
|
|
1170
|
+
// Engine specs
|
|
1171
|
+
engineDisplacementCc: zod.z.number().nullable(),
|
|
1172
|
+
enginePowerKw: zod.z.number().nullable(),
|
|
1173
|
+
cylinders: zod.z.number().nullable(),
|
|
1174
|
+
// Fuel consumption (L/100km)
|
|
1175
|
+
combinedLPer100km: zod.z.number().nullable(),
|
|
1176
|
+
cityLPer100km: zod.z.number().nullable(),
|
|
1177
|
+
highwayLPer100km: zod.z.number().nullable(),
|
|
1178
|
+
// Electric consumption (kWh/100km)
|
|
1179
|
+
combinedKwhPer100km: zod.z.number().nullable(),
|
|
1180
|
+
cityKwhPer100km: zod.z.number().nullable(),
|
|
1181
|
+
highwayKwhPer100km: zod.z.number().nullable(),
|
|
1182
|
+
// Emissions & Range
|
|
1183
|
+
co2GramsPerKm: zod.z.number().nullable(),
|
|
1184
|
+
electricRangeKm: zod.z.number().nullable(),
|
|
1185
|
+
totalRangeKm: zod.z.number().nullable(),
|
|
1186
|
+
// Vehicle specs
|
|
1187
|
+
massKg: zod.z.number().nullable(),
|
|
1188
|
+
wheelbaseMm: zod.z.number().nullable(),
|
|
1189
|
+
// Test info
|
|
1190
|
+
testCycle: testCycleSchema
|
|
1191
|
+
});
|
|
1192
|
+
var efficiencyStatsSchema = zod.z.object({
|
|
1193
|
+
totalRecords: zod.z.number(),
|
|
1194
|
+
bySource: zod.z.array(
|
|
1195
|
+
zod.z.object({
|
|
1196
|
+
source: efficiencySourceSchema,
|
|
1197
|
+
count: zod.z.number()
|
|
1198
|
+
})
|
|
1199
|
+
),
|
|
1200
|
+
byPowertrain: zod.z.array(
|
|
1201
|
+
zod.z.object({
|
|
1202
|
+
powertrainType: zod.z.string(),
|
|
1203
|
+
count: zod.z.number()
|
|
1204
|
+
})
|
|
1205
|
+
),
|
|
1206
|
+
byTestCycle: zod.z.array(
|
|
1207
|
+
zod.z.object({
|
|
1208
|
+
testCycle: zod.z.string(),
|
|
1209
|
+
count: zod.z.number()
|
|
1210
|
+
})
|
|
1211
|
+
),
|
|
1212
|
+
yearRange: zod.z.object({
|
|
1213
|
+
min: zod.z.number(),
|
|
1214
|
+
max: zod.z.number()
|
|
1215
|
+
}),
|
|
1216
|
+
topMakes: zod.z.array(
|
|
1217
|
+
zod.z.object({
|
|
1218
|
+
make: zod.z.string(),
|
|
1219
|
+
count: zod.z.number()
|
|
1220
|
+
})
|
|
1221
|
+
)
|
|
1222
|
+
});
|
|
1223
|
+
zod.z.object({
|
|
1224
|
+
makes: zod.z.array(zod.z.string().transform((val) => val.toUpperCase())).optional(),
|
|
1225
|
+
models: zod.z.array(zod.z.string().transform((val) => val.toUpperCase())).optional(),
|
|
1226
|
+
year: rangeSchema(1900, 2050).optional(),
|
|
1227
|
+
vehicleClasses: zod.z.array(zod.z.string()).optional(),
|
|
1228
|
+
bodyStyles: zod.z.array(zod.z.string()).optional(),
|
|
1229
|
+
overallStars: zod.z.array(zod.z.string()).optional(),
|
|
1230
|
+
frontalRatings: zod.z.array(zod.z.string()).optional(),
|
|
1231
|
+
sideRatings: zod.z.array(zod.z.string()).optional(),
|
|
1232
|
+
rolloverRatings: zod.z.array(zod.z.string()).optional(),
|
|
1233
|
+
hasAdvancedSafety: zod.z.boolean().optional(),
|
|
1234
|
+
limit: zod.z.coerce.number().optional(),
|
|
1235
|
+
offset: zod.z.coerce.number().optional(),
|
|
1236
|
+
sort: zod.z.enum([
|
|
1237
|
+
"make",
|
|
1238
|
+
"model",
|
|
1239
|
+
"model_year",
|
|
1240
|
+
"overall_stars",
|
|
1241
|
+
"frontal_driver_stars",
|
|
1242
|
+
"side_driver_stars",
|
|
1243
|
+
"rollover_stars",
|
|
1244
|
+
"vehicle_class"
|
|
1245
|
+
]).optional(),
|
|
1246
|
+
order: zod.z.enum(["asc", "desc"]).optional()
|
|
1247
|
+
});
|
|
1248
|
+
zod.z.object({
|
|
1249
|
+
id: zod.z.number(),
|
|
1250
|
+
make: zod.z.string(),
|
|
1251
|
+
model: zod.z.string(),
|
|
1252
|
+
modelYear: zod.z.number().nullable(),
|
|
1253
|
+
bodyStyle: zod.z.string().nullable(),
|
|
1254
|
+
vehicleClass: zod.z.string().nullable(),
|
|
1255
|
+
// Core Safety Ratings
|
|
1256
|
+
overallStars: zod.z.string().nullable(),
|
|
1257
|
+
frontalDriverStars: zod.z.string().nullable(),
|
|
1258
|
+
frontalPassengerStars: zod.z.string().nullable(),
|
|
1259
|
+
overallFrontalStars: zod.z.string().nullable(),
|
|
1260
|
+
sideDriverStars: zod.z.string().nullable(),
|
|
1261
|
+
sidePassengerStars: zod.z.string().nullable(),
|
|
1262
|
+
overallSideStars: zod.z.string().nullable(),
|
|
1263
|
+
sidePoleStars: zod.z.string().nullable(),
|
|
1264
|
+
rolloverStars: zod.z.string().nullable(),
|
|
1265
|
+
rolloverPossibility: zod.z.number().nullable(),
|
|
1266
|
+
// Advanced Safety Features
|
|
1267
|
+
frontCollisionWarning: zod.z.string().nullable(),
|
|
1268
|
+
laneDepartureWarning: zod.z.string().nullable(),
|
|
1269
|
+
crashImminentBrake: zod.z.string().nullable(),
|
|
1270
|
+
blindSpotDetection: zod.z.string().nullable(),
|
|
1271
|
+
backupCamera: zod.z.string().nullable(),
|
|
1272
|
+
abs: zod.z.string().nullable(),
|
|
1273
|
+
nhtsaEsc: zod.z.string().nullable(),
|
|
1274
|
+
// Airbag Information
|
|
1275
|
+
headSideAirbag: zod.z.string().nullable(),
|
|
1276
|
+
torsoSideAirbag: zod.z.string().nullable(),
|
|
1277
|
+
// Test Information
|
|
1278
|
+
frontalTestNumber: zod.z.number().nullable(),
|
|
1279
|
+
sideTestNumber: zod.z.number().nullable(),
|
|
1280
|
+
poleTestNumber: zod.z.number().nullable(),
|
|
1281
|
+
// Metadata
|
|
1282
|
+
processedAt: zod.z.string().nullable(),
|
|
1283
|
+
provider: zod.z.literal("NHTSA")
|
|
1284
|
+
});
|
|
1285
|
+
zod.z.object({
|
|
1286
|
+
totalReviews: zod.z.number(),
|
|
1287
|
+
reviewsWithOverallRating: zod.z.number(),
|
|
1288
|
+
topMakes: zod.z.array(
|
|
1289
|
+
zod.z.object({
|
|
1290
|
+
make: zod.z.string(),
|
|
1291
|
+
count: zod.z.number()
|
|
1292
|
+
})
|
|
1293
|
+
),
|
|
1294
|
+
topVehicleClasses: zod.z.array(
|
|
1295
|
+
zod.z.object({
|
|
1296
|
+
vehicleClass: zod.z.string(),
|
|
1297
|
+
count: zod.z.number()
|
|
1298
|
+
})
|
|
1299
|
+
),
|
|
1300
|
+
ratingDistribution: zod.z.array(
|
|
1301
|
+
zod.z.object({
|
|
1302
|
+
stars: zod.z.string(),
|
|
1303
|
+
count: zod.z.number()
|
|
1304
|
+
})
|
|
1305
|
+
),
|
|
1306
|
+
advancedSafetyFeatures: zod.z.object({
|
|
1307
|
+
frontCollisionWarning: zod.z.number(),
|
|
1308
|
+
laneDepartureWarning: zod.z.number(),
|
|
1309
|
+
crashImminentBrake: zod.z.number(),
|
|
1310
|
+
blindSpotDetection: zod.z.number(),
|
|
1311
|
+
backupCamera: zod.z.number()
|
|
1312
|
+
})
|
|
1313
|
+
});
|
|
1314
|
+
|
|
1315
|
+
// ../contracts/src/codecs/base.codecs.ts
|
|
1316
|
+
function createSchemaWithCodec(schema, codec) {
|
|
1317
|
+
return {
|
|
1318
|
+
...schema,
|
|
1319
|
+
encode: codec.encode,
|
|
1320
|
+
decode: codec.decode,
|
|
1321
|
+
schema
|
|
1322
|
+
// Original schema for validation
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
var URLParamsBuilder = class {
|
|
1326
|
+
constructor() {
|
|
1327
|
+
this.params = new URLSearchParams();
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Set a single key-value pair
|
|
1331
|
+
* @param key - The parameter key
|
|
1332
|
+
* @param value - The value to set (undefined values are ignored)
|
|
1333
|
+
* @returns This builder instance for chaining
|
|
1334
|
+
*/
|
|
1335
|
+
set(key, value) {
|
|
1336
|
+
if (value !== void 0) {
|
|
1337
|
+
this.params.set(key, encodeURIComponent(value.toString()));
|
|
1338
|
+
}
|
|
1339
|
+
return this;
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Set an array parameter as a comma-separated string
|
|
1343
|
+
* @param key - The parameter key
|
|
1344
|
+
* @param values - Array of strings to join (undefined/empty arrays are ignored)
|
|
1345
|
+
* @returns This builder instance for chaining
|
|
1346
|
+
*/
|
|
1347
|
+
setArray(key, values) {
|
|
1348
|
+
if (values?.length) {
|
|
1349
|
+
this.set(key, values.join(","));
|
|
1350
|
+
}
|
|
1351
|
+
return this;
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Set a range parameter as separate min/max keys
|
|
1355
|
+
* @param key - The base parameter key
|
|
1356
|
+
* @param range - Object with optional min/max properties
|
|
1357
|
+
* @returns This builder instance for chaining
|
|
1358
|
+
*/
|
|
1359
|
+
setRange(key, range) {
|
|
1360
|
+
if (range?.min !== void 0) {
|
|
1361
|
+
this.set(`${key}Min`, range.min);
|
|
1362
|
+
}
|
|
1363
|
+
if (range?.max !== void 0) {
|
|
1364
|
+
this.set(`${key}Max`, range.max);
|
|
1365
|
+
}
|
|
1366
|
+
return this;
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Build the final URLSearchParams object
|
|
1370
|
+
* @returns The constructed URLSearchParams instance
|
|
1371
|
+
*/
|
|
1372
|
+
build() {
|
|
1373
|
+
return this.params;
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
var URLParamsParser = class {
|
|
1377
|
+
constructor(params) {
|
|
1378
|
+
this.params = params;
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* Get a single string parameter with proper URL decoding
|
|
1382
|
+
* @param key - The parameter key
|
|
1383
|
+
* @returns The decoded string value or undefined if not present
|
|
1384
|
+
*/
|
|
1385
|
+
get(key) {
|
|
1386
|
+
const value = this.params.get(key);
|
|
1387
|
+
return value ? decodeURIComponent(value.replace(/\+/g, " ")) : void 0;
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Get a numeric parameter with type conversion
|
|
1391
|
+
* @param key - The parameter key
|
|
1392
|
+
* @param type - Whether to parse as integer or float
|
|
1393
|
+
* @returns The parsed number or undefined if not present/invalid
|
|
1394
|
+
*/
|
|
1395
|
+
getNumber(key, type = "int") {
|
|
1396
|
+
const value = this.get(key);
|
|
1397
|
+
if (!value) return void 0;
|
|
1398
|
+
return type === "float" ? parseFloat(value) : parseInt(value);
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Get an array parameter by splitting on comma
|
|
1402
|
+
* @param key - The parameter key
|
|
1403
|
+
* @returns Array of trimmed strings or undefined if not present
|
|
1404
|
+
*/
|
|
1405
|
+
getArray(key) {
|
|
1406
|
+
const value = this.get(key);
|
|
1407
|
+
return value?.split(",").map((s) => s.trim());
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Get a range parameter by looking for {key}Min and {key}Max
|
|
1411
|
+
* @param key - The base parameter key
|
|
1412
|
+
* @returns Object with min/max properties or undefined if neither present
|
|
1413
|
+
*/
|
|
1414
|
+
getRange(key) {
|
|
1415
|
+
const min = this.getNumber(`${key}Min`);
|
|
1416
|
+
const max = this.getNumber(`${key}Max`);
|
|
1417
|
+
return min !== void 0 || max !== void 0 ? { min, max } : void 0;
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
1420
|
+
|
|
1421
|
+
// ../contracts/src/codecs/listings.codecs.ts
|
|
1422
|
+
var MAKE_MODEL_DELIMITER = ";";
|
|
1423
|
+
var MODEL_DELIMITER = "|";
|
|
1424
|
+
var SUB_MODEL_DELIMITER = ",";
|
|
1425
|
+
var ListingFiltersCodec = class {
|
|
1426
|
+
/**
|
|
1427
|
+
* Encode listing filters to URLSearchParams
|
|
1428
|
+
* @param filters - The filters object to encode
|
|
1429
|
+
* @returns URLSearchParams representation
|
|
1430
|
+
*/
|
|
1431
|
+
encode(filters) {
|
|
1432
|
+
const builder = new URLParamsBuilder();
|
|
1433
|
+
builder.setArray("ids", filters.ids);
|
|
1434
|
+
builder.setArray("makes", filters.makes);
|
|
1435
|
+
builder.setArray("trims", filters.trims);
|
|
1436
|
+
builder.setArray("saleTypes", filters.saleTypes);
|
|
1437
|
+
builder.setArray("bodyStyles", filters.bodyStyles);
|
|
1438
|
+
builder.setArray("fuelTypes", filters.fuelTypes);
|
|
1439
|
+
builder.setArray("exteriorColors", filters.exteriorColors);
|
|
1440
|
+
builder.setArray("interiorColors", filters.interiorColors);
|
|
1441
|
+
builder.setArray("sellers", filters.sellers);
|
|
1442
|
+
if (filters.models) {
|
|
1443
|
+
const modelsString = Object.entries(filters.models).map(
|
|
1444
|
+
([make, models]) => `${make}${MODEL_DELIMITER}${models.join(SUB_MODEL_DELIMITER)}`
|
|
1445
|
+
).join(MAKE_MODEL_DELIMITER);
|
|
1446
|
+
builder.set("models", modelsString);
|
|
1447
|
+
}
|
|
1448
|
+
builder.setRange("year", filters.year);
|
|
1449
|
+
builder.setRange("price", filters.price);
|
|
1450
|
+
builder.setRange("odometer", filters.odometer);
|
|
1451
|
+
if (filters.location) {
|
|
1452
|
+
builder.set("lat", filters.location.lat);
|
|
1453
|
+
builder.set("lng", filters.location.lng);
|
|
1454
|
+
builder.set("radius", filters.location.radius);
|
|
1455
|
+
}
|
|
1456
|
+
return builder.build();
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Decode URLSearchParams back to listing filters
|
|
1460
|
+
* @param params - The URLSearchParams to decode
|
|
1461
|
+
* @returns The decoded filters object
|
|
1462
|
+
* @throws z.ZodError if the parameters don't match the expected schema
|
|
1463
|
+
*/
|
|
1464
|
+
decode(params) {
|
|
1465
|
+
const parser = new URLParamsParser(params);
|
|
1466
|
+
const rawFilters = {
|
|
1467
|
+
ids: parser.getArray("ids"),
|
|
1468
|
+
makes: parser.getArray("makes"),
|
|
1469
|
+
models: this.parseModels(parser.get("models")),
|
|
1470
|
+
trims: parser.getArray("trims"),
|
|
1471
|
+
year: parser.getRange("year"),
|
|
1472
|
+
price: parser.getRange("price"),
|
|
1473
|
+
odometer: parser.getRange("odometer"),
|
|
1474
|
+
saleTypes: parser.getArray("saleTypes"),
|
|
1475
|
+
bodyStyles: parser.getArray("bodyStyles"),
|
|
1476
|
+
fuelTypes: parser.getArray("fuelTypes"),
|
|
1477
|
+
exteriorColors: parser.getArray("exteriorColors"),
|
|
1478
|
+
interiorColors: parser.getArray("interiorColors"),
|
|
1479
|
+
sellers: parser.getArray("sellers")
|
|
1480
|
+
};
|
|
1481
|
+
const lat = parser.getNumber("lat", "float");
|
|
1482
|
+
const lng = parser.getNumber("lng", "float");
|
|
1483
|
+
if (lat !== void 0 && lng !== void 0) {
|
|
1484
|
+
rawFilters.location = {
|
|
1485
|
+
lat,
|
|
1486
|
+
lng,
|
|
1487
|
+
radius: parser.getNumber("radius") ?? 50
|
|
1488
|
+
// Default radius
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
return listingFiltersSchema.parse(rawFilters);
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Parse the complex models string format
|
|
1495
|
+
* @param value - The encoded models string
|
|
1496
|
+
* @returns Parsed models object or undefined
|
|
1497
|
+
* @private
|
|
1498
|
+
*/
|
|
1499
|
+
parseModels(value) {
|
|
1500
|
+
if (!value) return void 0;
|
|
1501
|
+
return value.split(MAKE_MODEL_DELIMITER).reduce(
|
|
1502
|
+
(acc, makeModelPair) => {
|
|
1503
|
+
const [make, models] = makeModelPair.split(MODEL_DELIMITER);
|
|
1504
|
+
if (make && models) {
|
|
1505
|
+
acc[make] = models.split(SUB_MODEL_DELIMITER);
|
|
1506
|
+
}
|
|
1507
|
+
return acc;
|
|
1508
|
+
},
|
|
1509
|
+
{}
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1512
|
+
};
|
|
1513
|
+
var ListingQueryCodec = class {
|
|
1514
|
+
constructor() {
|
|
1515
|
+
this.filtersCodec = new ListingFiltersCodec();
|
|
1516
|
+
}
|
|
1517
|
+
encode(query) {
|
|
1518
|
+
const params = new URLSearchParams();
|
|
1519
|
+
if (query.filters) {
|
|
1520
|
+
const filterParams = this.filtersCodec.encode(query.filters);
|
|
1521
|
+
filterParams.forEach((value, key) => {
|
|
1522
|
+
params.set(key, value);
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
if (query.pagination) {
|
|
1526
|
+
if (query.pagination.page !== void 0) {
|
|
1527
|
+
params.set("page", query.pagination.page.toString());
|
|
1528
|
+
}
|
|
1529
|
+
if (query.pagination.limit !== void 0) {
|
|
1530
|
+
params.set("limit", query.pagination.limit.toString());
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
if (query.sort) {
|
|
1534
|
+
params.set("sort", query.sort.field);
|
|
1535
|
+
params.set("order", query.sort.direction);
|
|
1536
|
+
}
|
|
1537
|
+
return params;
|
|
1538
|
+
}
|
|
1539
|
+
decode(params) {
|
|
1540
|
+
const parser = new URLParamsParser(params);
|
|
1541
|
+
const query = {};
|
|
1542
|
+
const filters = this.filtersCodec.decode(params);
|
|
1543
|
+
if (Object.keys(filters).length > 0) {
|
|
1544
|
+
query.filters = filters;
|
|
1545
|
+
}
|
|
1546
|
+
const page = parser.getNumber("page");
|
|
1547
|
+
const limit = parser.getNumber("limit");
|
|
1548
|
+
query.pagination = {
|
|
1549
|
+
page: page ?? 1,
|
|
1550
|
+
limit: limit ?? 25
|
|
1551
|
+
};
|
|
1552
|
+
const sort = parser.get("sort");
|
|
1553
|
+
const order = parser.get("order");
|
|
1554
|
+
if (sort) {
|
|
1555
|
+
query.sort = {
|
|
1556
|
+
field: sort,
|
|
1557
|
+
// Will be validated by schema
|
|
1558
|
+
direction: order ?? "desc"
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
return listingQuerySchema.parse(query);
|
|
1562
|
+
}
|
|
1563
|
+
};
|
|
1564
|
+
createSchemaWithCodec(
|
|
1565
|
+
listingFiltersSchema,
|
|
1566
|
+
new ListingFiltersCodec()
|
|
1567
|
+
);
|
|
1568
|
+
createSchemaWithCodec(
|
|
1569
|
+
listingQuerySchema,
|
|
1570
|
+
new ListingQueryCodec()
|
|
1571
|
+
);
|
|
1572
|
+
|
|
1573
|
+
// src/routes/vin.ts
|
|
1574
|
+
var vinKeys = {
|
|
1575
|
+
all: ["vin"],
|
|
1576
|
+
image: (base64) => [...vinKeys.all, "image", base64],
|
|
1577
|
+
decode: (vin) => [...vinKeys.all, "decode", vin]
|
|
1578
|
+
};
|
|
1579
|
+
|
|
1580
|
+
// src/routes/market.ts
|
|
1581
|
+
var marketKeys = {
|
|
1582
|
+
all: ["market"],
|
|
1583
|
+
analysis: (vin) => [...marketKeys.all, "analysis", vin],
|
|
1584
|
+
overview: (make, model, year) => [...marketKeys.all, "overview", make, model, year],
|
|
1585
|
+
pricing: (make, model, year) => [...marketKeys.all, "pricing", make, model, year],
|
|
1586
|
+
breakdown: (make, model, year) => [...marketKeys.all, "breakdown", make, model, year],
|
|
1587
|
+
odometer: (make, model, year) => [...marketKeys.all, "odometer", make, model, year],
|
|
1588
|
+
geography: (make, model, year) => [...marketKeys.all, "geography", make, model, year],
|
|
1589
|
+
trends: (make, model, year, period) => [...marketKeys.all, "trends", make, model, year, period],
|
|
1590
|
+
similar: (listingId, limit) => [...marketKeys.all, "similar", listingId, limit],
|
|
1591
|
+
position: (listingId) => [...marketKeys.all, "position", listingId],
|
|
1592
|
+
pulse: (options) => [...marketKeys.all, "pulse", options],
|
|
1593
|
+
byVin: (vin) => [...marketKeys.all, "byVin", vin],
|
|
1594
|
+
local: (params) => [...marketKeys.all, "local", params],
|
|
1595
|
+
demand: (make, model, year) => [...marketKeys.all, "demand", make, model, year]
|
|
1596
|
+
};
|
|
1597
|
+
|
|
1598
|
+
// src/routes/listings.ts
|
|
1599
|
+
var listingsKeys = {
|
|
1600
|
+
all: ["listings"],
|
|
1601
|
+
search: (params) => [...listingsKeys.all, "search", params],
|
|
1602
|
+
count: (params) => [...listingsKeys.all, "count", params],
|
|
1603
|
+
facets: (params) => [...listingsKeys.all, "facets", params],
|
|
1604
|
+
getById: (id) => [...listingsKeys.all, "getById", id]
|
|
1605
|
+
};
|
|
1606
|
+
zod.z.object({
|
|
1607
|
+
results: zod.z.array(locationResultSchema),
|
|
1608
|
+
meta: zod.z.any().optional()
|
|
1609
|
+
});
|
|
1610
|
+
var locationsKeys = {
|
|
1611
|
+
all: ["locations"],
|
|
1612
|
+
search: (params) => [...locationsKeys.all, "search", params],
|
|
1613
|
+
detail: (id) => [...locationsKeys.all, "detail", id],
|
|
1614
|
+
bySlug: (slug) => [...locationsKeys.all, "slug", slug]
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1617
|
+
// src/routes/charging.ts
|
|
1618
|
+
var chargingKeys = {
|
|
1619
|
+
all: ["charging"],
|
|
1620
|
+
stations: (params) => [...chargingKeys.all, "stations", params],
|
|
1621
|
+
station: (id) => [...chargingKeys.all, "station", id]
|
|
1622
|
+
};
|
|
1623
|
+
|
|
1624
|
+
// src/routes/fuel.ts
|
|
1625
|
+
var fuelKeys = {
|
|
1626
|
+
all: ["fuel"],
|
|
1627
|
+
search: (params) => [...fuelKeys.all, "search", params]
|
|
1628
|
+
};
|
|
1629
|
+
|
|
1630
|
+
// src/routes/research.ts
|
|
1631
|
+
var researchKeys = {
|
|
1632
|
+
all: ["research"],
|
|
1633
|
+
lineup: (make, params) => [...researchKeys.all, "lineup", make, params],
|
|
1634
|
+
byMake: (make) => [...researchKeys.all, "make", make],
|
|
1635
|
+
byId: (id) => [...researchKeys.all, "id", id],
|
|
1636
|
+
byListingId: (listingId) => [...researchKeys.all, "listing", listingId],
|
|
1637
|
+
byVin: (vin) => [...researchKeys.all, "vin", vin],
|
|
1638
|
+
byModel: (make, model) => [...researchKeys.all, "model", make, model],
|
|
1639
|
+
byYear: (make, year) => [...researchKeys.all, "year", make, year],
|
|
1640
|
+
byModelYear: (make, model, year) => [...researchKeys.all, "modelYear", make, model, year],
|
|
1641
|
+
images: (params) => [...researchKeys.all, "images", params],
|
|
1642
|
+
profileImages: (params) => [...researchKeys.all, "profileImages", params],
|
|
1643
|
+
colors: (params) => [...researchKeys.all, "colors", params]
|
|
1644
|
+
};
|
|
1645
|
+
|
|
1646
|
+
// src/routes/recalls.ts
|
|
1647
|
+
var recallKeys = {
|
|
1648
|
+
all: ["recalls"],
|
|
1649
|
+
search: (params) => [
|
|
1650
|
+
...recallKeys.all,
|
|
1651
|
+
"search",
|
|
1652
|
+
params.country,
|
|
1653
|
+
params.makes,
|
|
1654
|
+
params.models,
|
|
1655
|
+
params.year
|
|
1656
|
+
]
|
|
1657
|
+
};
|
|
1658
|
+
zod.z.object({
|
|
1659
|
+
success: zod.z.boolean(),
|
|
1660
|
+
data: zod.z.array(efficiencyDetailSchema),
|
|
1661
|
+
meta: zod.z.object({
|
|
1662
|
+
filter: zod.z.any().optional(),
|
|
1663
|
+
make: zod.z.string().optional(),
|
|
1664
|
+
model: zod.z.string().optional(),
|
|
1665
|
+
year: zod.z.number().optional(),
|
|
1666
|
+
trim: zod.z.string().optional(),
|
|
1667
|
+
count: zod.z.number(),
|
|
1668
|
+
fallback: zod.z.boolean().optional()
|
|
1669
|
+
})
|
|
1670
|
+
});
|
|
1671
|
+
zod.z.object({
|
|
1672
|
+
success: zod.z.boolean(),
|
|
1673
|
+
data: efficiencyStatsSchema
|
|
1674
|
+
});
|
|
1675
|
+
var efficiencyKeys = {
|
|
1676
|
+
all: ["efficiency"],
|
|
1677
|
+
search: (params) => [...efficiencyKeys.all, "search", params],
|
|
1678
|
+
byVehicle: (make, model, year) => [...efficiencyKeys.all, "vehicle", make, model, year],
|
|
1679
|
+
byVehicleTrim: (make, model, year, trim) => [...efficiencyKeys.all, "vehicle", make, model, year, trim],
|
|
1680
|
+
stats: () => [...efficiencyKeys.all, "stats"]
|
|
1681
|
+
};
|
|
1682
|
+
var complaintSchema = zod.z.object({
|
|
1683
|
+
complaintId: zod.z.number(),
|
|
1684
|
+
odiNumber: zod.z.string().nullable().optional(),
|
|
1685
|
+
manufacturerName: zod.z.string().nullable().optional(),
|
|
1686
|
+
make: zod.z.string(),
|
|
1687
|
+
model: zod.z.string(),
|
|
1688
|
+
year: zod.z.number(),
|
|
1689
|
+
vin: zod.z.string().nullable().optional(),
|
|
1690
|
+
crashInvolved: zod.z.boolean().nullable().optional(),
|
|
1691
|
+
incidentDate: zod.z.string().nullable().optional(),
|
|
1692
|
+
fireInvolved: zod.z.boolean().nullable().optional(),
|
|
1693
|
+
injuredCount: zod.z.number().nullable().optional(),
|
|
1694
|
+
deathsCount: zod.z.number().nullable().optional(),
|
|
1695
|
+
componentDescription: zod.z.string().nullable().optional(),
|
|
1696
|
+
consumerCity: zod.z.string().nullable().optional(),
|
|
1697
|
+
consumerState: zod.z.string().nullable().optional(),
|
|
1698
|
+
dateAdded: zod.z.string().nullable().optional(),
|
|
1699
|
+
dateReceived: zod.z.string().nullable().optional(),
|
|
1700
|
+
mileage: zod.z.number().nullable().optional(),
|
|
1701
|
+
occurrences: zod.z.number().nullable().optional(),
|
|
1702
|
+
complaintDescription: zod.z.string().nullable().optional(),
|
|
1703
|
+
complaintType: zod.z.string().nullable().optional(),
|
|
1704
|
+
policeReportFiled: zod.z.boolean().nullable().optional(),
|
|
1705
|
+
purchaseDate: zod.z.string().nullable().optional(),
|
|
1706
|
+
originalOwner: zod.z.boolean().nullable().optional(),
|
|
1707
|
+
productType: zod.z.string().nullable().optional(),
|
|
1708
|
+
repaired: zod.z.boolean().nullable().optional(),
|
|
1709
|
+
medicalAttention: zod.z.boolean().nullable().optional(),
|
|
1710
|
+
vehicleTowed: zod.z.boolean().nullable().optional(),
|
|
1711
|
+
processedAt: zod.z.string().nullable().optional(),
|
|
1712
|
+
provider: zod.z.string().nullable().optional()
|
|
1713
|
+
});
|
|
1714
|
+
zod.z.object({
|
|
1715
|
+
success: zod.z.boolean(),
|
|
1716
|
+
provider: zod.z.string(),
|
|
1717
|
+
data: zod.z.array(complaintSchema),
|
|
1718
|
+
meta: zod.z.object({
|
|
1719
|
+
filter: zod.z.any().optional(),
|
|
1720
|
+
count: zod.z.number()
|
|
1721
|
+
})
|
|
1722
|
+
});
|
|
1723
|
+
var complaintsKeys = {
|
|
1724
|
+
all: ["complaints"],
|
|
1725
|
+
search: (params) => [...complaintsKeys.all, "search", params]
|
|
1726
|
+
};
|
|
1727
|
+
|
|
1728
|
+
// src/index.ts
|
|
1729
|
+
var queryKeys = {
|
|
1730
|
+
vin: vinKeys,
|
|
1731
|
+
market: marketKeys,
|
|
1732
|
+
listings: listingsKeys,
|
|
1733
|
+
locations: locationsKeys,
|
|
1734
|
+
charging: chargingKeys,
|
|
1735
|
+
fuel: fuelKeys,
|
|
1736
|
+
research: researchKeys,
|
|
1737
|
+
recalls: recallKeys,
|
|
1738
|
+
efficiency: efficiencyKeys,
|
|
1739
|
+
complaints: complaintsKeys
|
|
1740
|
+
};
|
|
1741
|
+
|
|
1742
|
+
// src/react/hooks.ts
|
|
1743
|
+
function createHooks(client) {
|
|
1744
|
+
return {
|
|
1745
|
+
useVinDecode(vin, options) {
|
|
1746
|
+
return reactQuery.useQuery({
|
|
1747
|
+
queryKey: queryKeys.vin.decode(vin),
|
|
1748
|
+
queryFn: () => client.vin.decode(vin),
|
|
1749
|
+
...options
|
|
1750
|
+
});
|
|
1751
|
+
},
|
|
1752
|
+
useVinImage(base64, options) {
|
|
1753
|
+
return reactQuery.useQuery({
|
|
1754
|
+
queryKey: queryKeys.vin.image(base64),
|
|
1755
|
+
queryFn: () => client.vin.image(base64),
|
|
1756
|
+
...options
|
|
1757
|
+
});
|
|
1758
|
+
},
|
|
1759
|
+
useMarketAnalysis(vin, options) {
|
|
1760
|
+
return reactQuery.useQuery({
|
|
1761
|
+
queryKey: queryKeys.market.byVin(vin),
|
|
1762
|
+
queryFn: () => client.market.byVin(vin),
|
|
1763
|
+
...options
|
|
1764
|
+
});
|
|
1765
|
+
},
|
|
1766
|
+
useMarketOverview(params, options) {
|
|
1767
|
+
return reactQuery.useQuery({
|
|
1768
|
+
queryKey: queryKeys.market.overview(params.make, params.model, params.year),
|
|
1769
|
+
queryFn: () => client.market.overview(params.make, params.model, params.year),
|
|
1770
|
+
...options
|
|
1771
|
+
});
|
|
1772
|
+
},
|
|
1773
|
+
useMarketPricing(make, model, year, options) {
|
|
1774
|
+
return reactQuery.useQuery({
|
|
1775
|
+
queryKey: queryKeys.market.pricing(make, model, year),
|
|
1776
|
+
queryFn: () => client.market.pricing(make, model, year),
|
|
1777
|
+
...options
|
|
1778
|
+
});
|
|
1779
|
+
},
|
|
1780
|
+
useMarketBreakdown(make, model, year, options) {
|
|
1781
|
+
return reactQuery.useQuery({
|
|
1782
|
+
queryKey: queryKeys.market.breakdown(make, model, year),
|
|
1783
|
+
queryFn: () => client.market.breakdown(make, model, year),
|
|
1784
|
+
...options
|
|
1785
|
+
});
|
|
1786
|
+
},
|
|
1787
|
+
useMarketOdometer(make, model, year, options) {
|
|
1788
|
+
return reactQuery.useQuery({
|
|
1789
|
+
queryKey: queryKeys.market.odometer(make, model, year),
|
|
1790
|
+
queryFn: () => client.market.odometer(make, model, year),
|
|
1791
|
+
...options
|
|
1792
|
+
});
|
|
1793
|
+
},
|
|
1794
|
+
useMarketGeography(make, model, year, options) {
|
|
1795
|
+
return reactQuery.useQuery({
|
|
1796
|
+
queryKey: queryKeys.market.geography(make, model, year),
|
|
1797
|
+
queryFn: () => client.market.geography(make, model, year),
|
|
1798
|
+
...options
|
|
1799
|
+
});
|
|
1800
|
+
},
|
|
1801
|
+
useMarketTrends(make, model, year, period, options) {
|
|
1802
|
+
return reactQuery.useQuery({
|
|
1803
|
+
queryKey: queryKeys.market.trends(make, model, year, period),
|
|
1804
|
+
queryFn: () => client.market.trends(make, model, year, period),
|
|
1805
|
+
...options
|
|
1806
|
+
});
|
|
1807
|
+
},
|
|
1808
|
+
useMarketPosition(listingId, options) {
|
|
1809
|
+
return reactQuery.useQuery({
|
|
1810
|
+
queryKey: queryKeys.market.position(listingId),
|
|
1811
|
+
queryFn: () => client.market.position(listingId),
|
|
1812
|
+
...options
|
|
1813
|
+
});
|
|
1814
|
+
},
|
|
1815
|
+
useMarketPulse(pulseOptions, queryOptions) {
|
|
1816
|
+
return reactQuery.useQuery({
|
|
1817
|
+
queryKey: queryKeys.market.pulse(pulseOptions),
|
|
1818
|
+
queryFn: () => client.market.pulse(pulseOptions),
|
|
1819
|
+
...queryOptions
|
|
1820
|
+
});
|
|
1821
|
+
},
|
|
1822
|
+
useLocalMarket(params, options) {
|
|
1823
|
+
return reactQuery.useQuery({
|
|
1824
|
+
queryKey: queryKeys.market.local(params),
|
|
1825
|
+
queryFn: () => client.market.localMarket(params),
|
|
1826
|
+
enabled: !!(params.make && params.model && params.year && params.lat && params.lng),
|
|
1827
|
+
...options
|
|
1828
|
+
});
|
|
1829
|
+
},
|
|
1830
|
+
useListingsSearch(params, options) {
|
|
1831
|
+
return reactQuery.useQuery({
|
|
1832
|
+
queryKey: queryKeys.listings.search(params),
|
|
1833
|
+
queryFn: () => client.listings.search(params),
|
|
1834
|
+
...options
|
|
1835
|
+
});
|
|
1836
|
+
},
|
|
1837
|
+
useListingsCount(params, options) {
|
|
1838
|
+
return reactQuery.useQuery({
|
|
1839
|
+
queryKey: queryKeys.listings.count(params),
|
|
1840
|
+
queryFn: () => client.listings.count(params),
|
|
1841
|
+
...options
|
|
1842
|
+
});
|
|
1843
|
+
},
|
|
1844
|
+
useInfiniteListingsSearch(params, options) {
|
|
1845
|
+
return reactQuery.useInfiniteQuery({
|
|
1846
|
+
queryKey: queryKeys.listings.search({ ...params, pagination: { page: 1, limit: 30 } }),
|
|
1847
|
+
queryFn: ({ pageParam = 1 }) => client.listings.search({
|
|
1848
|
+
...params,
|
|
1849
|
+
pagination: { page: pageParam, limit: 30 }
|
|
1850
|
+
}),
|
|
1851
|
+
initialPageParam: 1,
|
|
1852
|
+
getNextPageParam: (lastPage) => lastPage.pagination.page + 1,
|
|
1853
|
+
...options
|
|
1854
|
+
});
|
|
1855
|
+
},
|
|
1856
|
+
useListingById(id, options) {
|
|
1857
|
+
return reactQuery.useQuery({
|
|
1858
|
+
queryKey: queryKeys.listings.getById(id),
|
|
1859
|
+
queryFn: () => client.listings.getById(id),
|
|
1860
|
+
...options
|
|
1861
|
+
});
|
|
1862
|
+
},
|
|
1863
|
+
useListingsFacets(params, options) {
|
|
1864
|
+
return reactQuery.useQuery({
|
|
1865
|
+
queryKey: queryKeys.listings.facets(params),
|
|
1866
|
+
queryFn: () => client.listings.facets(params),
|
|
1867
|
+
staleTime: 6e4,
|
|
1868
|
+
...options
|
|
1869
|
+
});
|
|
1870
|
+
},
|
|
1871
|
+
useLocationsSearch(params, options) {
|
|
1872
|
+
return reactQuery.useQuery({
|
|
1873
|
+
queryKey: queryKeys.locations.search(params),
|
|
1874
|
+
queryFn: () => client.locations.search(params),
|
|
1875
|
+
...options
|
|
1876
|
+
});
|
|
1877
|
+
},
|
|
1878
|
+
useLocationById(id, options) {
|
|
1879
|
+
return reactQuery.useQuery({
|
|
1880
|
+
queryKey: queryKeys.locations.detail(id),
|
|
1881
|
+
queryFn: () => client.locations.getById(id),
|
|
1882
|
+
...options
|
|
1883
|
+
});
|
|
1884
|
+
},
|
|
1885
|
+
useFuelSearch(params, options) {
|
|
1886
|
+
return reactQuery.useQuery({
|
|
1887
|
+
queryKey: queryKeys.fuel.search(params),
|
|
1888
|
+
queryFn: () => client.fuel.search(params),
|
|
1889
|
+
...options
|
|
1890
|
+
});
|
|
1891
|
+
},
|
|
1892
|
+
useChargingStations(params, options) {
|
|
1893
|
+
return reactQuery.useQuery({
|
|
1894
|
+
queryKey: queryKeys.charging.stations(params),
|
|
1895
|
+
// @ts-ignore
|
|
1896
|
+
queryFn: () => client.charging.getStations(params),
|
|
1897
|
+
...options
|
|
1898
|
+
});
|
|
1899
|
+
},
|
|
1900
|
+
useResearchLineup(make, options) {
|
|
1901
|
+
return reactQuery.useQuery({
|
|
1902
|
+
queryKey: queryKeys.research.lineup(make),
|
|
1903
|
+
queryFn: () => client.research.lineup(make),
|
|
1904
|
+
...options
|
|
1905
|
+
});
|
|
1906
|
+
},
|
|
1907
|
+
useResearchByMake(make, options) {
|
|
1908
|
+
return reactQuery.useQuery({
|
|
1909
|
+
queryKey: queryKeys.research.byMake(make),
|
|
1910
|
+
queryFn: () => client.research.byMake(make),
|
|
1911
|
+
...options
|
|
1912
|
+
});
|
|
1913
|
+
},
|
|
1914
|
+
useResearchById(id, options) {
|
|
1915
|
+
return reactQuery.useQuery({
|
|
1916
|
+
queryKey: queryKeys.research.byId(id),
|
|
1917
|
+
queryFn: () => client.research.byId(id),
|
|
1918
|
+
...options
|
|
1919
|
+
});
|
|
1920
|
+
},
|
|
1921
|
+
useResearchByModel(make, model, options) {
|
|
1922
|
+
return reactQuery.useQuery({
|
|
1923
|
+
queryKey: queryKeys.research.byModel(make, model),
|
|
1924
|
+
queryFn: () => client.research.byModel(make, model),
|
|
1925
|
+
...options
|
|
1926
|
+
});
|
|
1927
|
+
},
|
|
1928
|
+
useResearchByModelYear(make, model, year, options) {
|
|
1929
|
+
return reactQuery.useQuery({
|
|
1930
|
+
queryKey: queryKeys.research.byModelYear(make, model, year),
|
|
1931
|
+
queryFn: () => client.research.byModelYear(make, model, year),
|
|
1932
|
+
...options
|
|
1933
|
+
});
|
|
1934
|
+
},
|
|
1935
|
+
useResearchImages(params, options) {
|
|
1936
|
+
return reactQuery.useQuery({
|
|
1937
|
+
queryKey: queryKeys.research.images(params),
|
|
1938
|
+
queryFn: () => client.research.getImages(params),
|
|
1939
|
+
...options
|
|
1940
|
+
});
|
|
1941
|
+
},
|
|
1942
|
+
useResearchColors(params, options) {
|
|
1943
|
+
return reactQuery.useQuery({
|
|
1944
|
+
queryKey: queryKeys.research.colors(params),
|
|
1945
|
+
queryFn: () => client.research.getColors(params),
|
|
1946
|
+
...options
|
|
1947
|
+
});
|
|
1948
|
+
},
|
|
1949
|
+
useRecalls(params, options) {
|
|
1950
|
+
return reactQuery.useQuery({
|
|
1951
|
+
queryKey: queryKeys.recalls.search(params),
|
|
1952
|
+
queryFn: () => client.recalls.search(params),
|
|
1953
|
+
...options
|
|
1954
|
+
});
|
|
1955
|
+
},
|
|
1956
|
+
useComplaints(params, options) {
|
|
1957
|
+
return reactQuery.useQuery({
|
|
1958
|
+
queryKey: queryKeys.complaints.search(params),
|
|
1959
|
+
queryFn: () => client.complaints.search(params),
|
|
1960
|
+
...options
|
|
1961
|
+
});
|
|
1962
|
+
}
|
|
1963
|
+
};
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
exports.createHooks = createHooks;
|
|
1967
|
+
exports.queryKeys = queryKeys;
|