@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.
@@ -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;