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