@propertysimple/client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/API.md +79 -0
  2. package/README.md +348 -0
  3. package/client/src/directory-sync.d.ts +123 -0
  4. package/client/src/directory-sync.js +404 -0
  5. package/client/src/index.d.ts +5123 -0
  6. package/client/src/index.js +285 -0
  7. package/client/src/managed-sync.d.ts +129 -0
  8. package/client/src/managed-sync.js +410 -0
  9. package/contracts/src/catalog-derived.d.ts +7 -0
  10. package/contracts/src/catalog-derived.js +78 -0
  11. package/contracts/src/catalog-fields.d.ts +231 -0
  12. package/contracts/src/catalog-fields.js +194 -0
  13. package/contracts/src/catalog-inventory.d.ts +14 -0
  14. package/contracts/src/catalog-inventory.js +10 -0
  15. package/contracts/src/directory-execution.d.ts +320 -0
  16. package/contracts/src/directory-execution.js +122 -0
  17. package/contracts/src/directory-identity.d.ts +1255 -0
  18. package/contracts/src/directory-identity.js +129 -0
  19. package/contracts/src/directory-sales.d.ts +333 -0
  20. package/contracts/src/directory-sales.js +102 -0
  21. package/contracts/src/directory.d.ts +1088 -0
  22. package/contracts/src/directory.js +179 -0
  23. package/contracts/src/index.d.ts +18 -0
  24. package/contracts/src/index.js +18 -0
  25. package/contracts/src/intelligence.d.ts +366 -0
  26. package/contracts/src/intelligence.js +157 -0
  27. package/contracts/src/location-serving.d.ts +13 -0
  28. package/contracts/src/location-serving.js +89 -0
  29. package/contracts/src/location.d.ts +73 -0
  30. package/contracts/src/location.js +75 -0
  31. package/contracts/src/openapi.d.ts +22 -0
  32. package/contracts/src/openapi.js +109 -0
  33. package/contracts/src/operations.d.ts +8316 -0
  34. package/contracts/src/operations.js +56 -0
  35. package/contracts/src/opportunity-events.d.ts +38 -0
  36. package/contracts/src/opportunity-events.js +69 -0
  37. package/contracts/src/platform-api.d.ts +12 -0
  38. package/contracts/src/platform-api.js +1 -0
  39. package/contracts/src/professional-intelligence.d.ts +256 -0
  40. package/contracts/src/professional-intelligence.js +90 -0
  41. package/contracts/src/property-features.d.ts +94 -0
  42. package/contracts/src/property-features.js +398 -0
  43. package/contracts/src/publication.d.ts +44 -0
  44. package/contracts/src/publication.js +42 -0
  45. package/contracts/src/routes.d.ts +437 -0
  46. package/contracts/src/routes.js +496 -0
  47. package/contracts/src/schemas.d.ts +3198 -0
  48. package/contracts/src/schemas.js +674 -0
  49. package/contracts/src/search.d.ts +2630 -0
  50. package/contracts/src/search.js +223 -0
  51. package/contracts/src/smart-feed.d.ts +3731 -0
  52. package/contracts/src/smart-feed.js +109 -0
  53. package/openapi.json +43542 -0
  54. package/package.json +60 -0
@@ -0,0 +1,398 @@
1
+ import { z } from 'zod';
2
+ /** Stable product vocabulary. Availability describes an implemented inference path,
3
+ * not measured model accuracy or whether a particular feed supplies the field. */
4
+ export const PROPERTY_DISCOVERY_REGISTRY_VERSION = 'property-discovery-v1';
5
+ export const PropertyFeatureDefinitionSchema = z.strictObject({
6
+ id: z.string().regex(/^[a-z][a-z0-9_]{1,79}$/),
7
+ family: z.number().int().min(1).max(52),
8
+ label: z.string().min(1).max(160),
9
+ definition: z.string().min(1).max(1600),
10
+ type: z.enum(['boolean', 'string', 'number']),
11
+ values: z.record(z.string(), z.string()).optional(),
12
+ synonyms: z.array(z.string().min(1).max(100)).max(20),
13
+ applicability: z.enum(['any', 'dwelling', 'sale', 'rental']),
14
+ source_paths: z.array(z.string().min(1)).min(1),
15
+ operators: z.array(z.enum(['eq', 'neq', 'in', 'not_in', 'gt', 'gte', 'lt', 'lte'])),
16
+ availability: z.enum(['source_and_interpretation', 'source_only']),
17
+ consequence: z.enum(['ordinary', 'consequential']),
18
+ status: z.literal('experimental'),
19
+ });
20
+ export const PropertyFeatureRegistrySchema = z.strictObject({
21
+ version: z.literal(PROPERTY_DISCOVERY_REGISTRY_VERSION),
22
+ features: z.array(PropertyFeatureDefinitionSchema),
23
+ });
24
+ export const PROPERTY_FEATURE_FAMILIES = [
25
+ 'Outdoor living',
26
+ 'Laundry',
27
+ 'Energy efficiency',
28
+ 'Storage',
29
+ 'Single-level living',
30
+ 'Garage',
31
+ 'Pools and spas',
32
+ 'Water amenities',
33
+ 'Accessory living spaces',
34
+ 'Fenced yard',
35
+ 'Fireplace and wood stove',
36
+ 'Architecture',
37
+ 'Land and farm facilities',
38
+ 'Furnishing',
39
+ 'Pet rules',
40
+ 'Workspaces',
41
+ 'Gardens',
42
+ 'Solar',
43
+ 'Architectural details',
44
+ 'HVAC',
45
+ 'Roof replacement',
46
+ 'System replacement',
47
+ 'Condition',
48
+ 'Association',
49
+ 'Outbuildings',
50
+ 'RV and boat facilities',
51
+ 'Basement',
52
+ 'Views',
53
+ 'Layout and daylight',
54
+ 'Kitchen and bath',
55
+ 'Access features',
56
+ 'Security equipment',
57
+ 'Outdoor cooking and gathering',
58
+ 'EV charging',
59
+ 'Backup power',
60
+ 'Architect involvement',
61
+ 'Seller financing',
62
+ 'Seller incentives',
63
+ 'Assumable mortgage',
64
+ 'Lease purchase',
65
+ 'Short-term rental claim',
66
+ 'Occupancy claim',
67
+ 'Off-grid operation',
68
+ 'Water and sewer',
69
+ 'Shelter',
70
+ 'Historic status',
71
+ 'Private wellness',
72
+ 'Sports courts',
73
+ 'Internet service',
74
+ 'Landscaping',
75
+ 'Resilience specifications',
76
+ 'Land tenure',
77
+ ].map((label, index) => ({ id: index + 1, label }));
78
+ const source = (fields) => [
79
+ ...fields.map((field) => `property_details.features.${field}`),
80
+ 'description',
81
+ ];
82
+ function feature(family, id, label, definition, fields, options = {}) {
83
+ return {
84
+ family,
85
+ id,
86
+ label,
87
+ definition,
88
+ type: options.values ? 'string' : 'boolean',
89
+ synonyms: [],
90
+ applicability: [
91
+ 7, 8, 13, 17, 18, 21, 24, 25, 26, 28, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
92
+ 48, 49, 50, 51, 52,
93
+ ].includes(family)
94
+ ? 'any'
95
+ : 'dwelling',
96
+ source_paths: [`attributes.${id}`, ...source(fields)],
97
+ operators: options.values ? ['eq', 'neq', 'in', 'not_in'] : ['eq', 'neq'],
98
+ availability: 'source_and_interpretation',
99
+ consequence: 'ordinary',
100
+ status: 'experimental',
101
+ ...options,
102
+ };
103
+ }
104
+ const exact = (family, id, label, definition, type, paths) => ({
105
+ family,
106
+ id,
107
+ label,
108
+ definition,
109
+ type,
110
+ synonyms: [],
111
+ applicability: 'any',
112
+ source_paths: paths,
113
+ operators: type === 'number' ? ['eq', 'neq', 'gt', 'gte', 'lt', 'lte'] : ['eq', 'neq', 'in', 'not_in'],
114
+ availability: 'source_only',
115
+ consequence: 'ordinary',
116
+ status: 'experimental',
117
+ });
118
+ const consequential = { consequence: 'consequential', applicability: 'any' };
119
+ const offered = {
120
+ offered: 'The source explicitly advertises this offer without a stated conditional qualifier.',
121
+ conditional: 'The source explicitly offers this only subject to approval, terms, qualification or another stated condition.',
122
+ not_offered: 'The source explicitly states this offer is not available.',
123
+ };
124
+ /** Never reuse an existing ID for a narrower claim: the legacy coarse pantry,
125
+ * laundry and style definitions remain alongside precise discovery attributes. */
126
+ export const PROPERTY_FEATURE_REGISTRY = [
127
+ feature(1, 'private_yard', 'Private yard', 'An existing yard exclusively for this property; shared grounds or room for a yard is insufficient.', ['ExteriorFeatures', 'LotFeatures']),
128
+ feature(1, 'patio', 'Patio', 'An existing private patio serving this property; a shared patio is insufficient.', ['PatioAndPorchFeatures', 'ExteriorFeatures']),
129
+ feature(1, 'deck', 'Deck', 'An existing private deck serving this property.', [
130
+ 'PatioAndPorchFeatures',
131
+ ]),
132
+ feature(1, 'covered_porch', 'Covered porch', 'An existing covered porch, not a merely covered patio or proposed porch.', ['PatioAndPorchFeatures']),
133
+ feature(1, 'outdoor_living', 'Outdoor living', 'An explicitly described patio, deck, terrace or outdoor entertaining space belonging to the property.', ['PatioAndPorchFeatures', 'ExteriorFeatures']),
134
+ feature(1, 'covered_outdoor_space', 'Covered outdoor space', 'An explicitly roofed or covered patio, porch, deck or terrace on this property.', ['PatioAndPorchFeatures']),
135
+ feature(1, 'balcony', 'Balcony', 'A balcony belonging to this property, explicitly stated.', [
136
+ 'PatioAndPorchFeatures',
137
+ 'ExteriorFeatures',
138
+ ]),
139
+ feature(2, 'laundry_room', 'Laundry room', 'A dedicated existing laundry room; a closet, shared facility or hookup alone does not establish a room.', ['LaundryFeatures', 'Rooms', 'RoomType', 'InteriorFeatures']),
140
+ feature(2, 'laundry_appliances_installed', 'Installed laundry appliances', 'Both a washer and dryer explicitly installed and included inside the dwelling; hookups, negotiable appliances and communal laundry are insufficient.', ['Appliances', 'LaundryFeatures']),
141
+ feature(2, 'laundry_hookups', 'Laundry hookups', 'Installed washer/dryer hookups in the dwelling; does not establish included appliances.', ['LaundryFeatures', 'InteriorFeatures']),
142
+ feature(2, 'laundry_in_unit', 'In-unit laundry facilities', 'Laundry appliances or hookups explicitly inside the dwelling or unit; shared laundry is insufficient.', ['LaundryFeatures', 'Appliances']),
143
+ feature(3, 'efficient_windows', 'Energy-efficient windows', 'Source explicitly specifies energy-efficient or ENERGY STAR windows; new or double-pane alone is not an efficiency certification.', ['WindowFeatures', 'GreenEnergyEfficient']),
144
+ feature(3, 'efficient_appliances', 'Energy-efficient appliances', 'Source explicitly specifies energy-efficient or ENERGY STAR appliances; no predicted savings.', ['Appliances', 'GreenEnergyEfficient']),
145
+ feature(3, 'insulation_upgrade', 'Insulation upgrade', 'An explicit installed insulation upgrade or named enhanced insulation specification; generic efficient home claims are insufficient.', ['GreenEnergyEfficient']),
146
+ feature(4, 'walk_in_pantry', 'Walk-in pantry', 'An explicitly walk-in pantry; a pantry without walk-in specification and ordinary cabinets are insufficient.', ['InteriorFeatures', 'Rooms']),
147
+ feature(4, 'pantry', 'Pantry', 'An explicitly described pantry; ordinary kitchen cabinets alone are insufficient.', ['InteriorFeatures', 'Rooms']),
148
+ feature(4, 'walk_in_closet', 'Walk-in closet', 'An explicitly described walk-in closet.', [
149
+ 'InteriorFeatures',
150
+ ]),
151
+ feature(4, 'garage_storage', 'Garage storage', 'Dedicated installed shelving, cabinetry or storage space in a garage; garage presence alone is insufficient.', ['ParkingFeatures', 'InteriorFeatures']),
152
+ feature(4, 'built_in_storage', 'Built-in storage', 'Explicitly described built-in shelving, cabinetry or storage beyond ordinary kitchen cabinets.', ['InteriorFeatures']),
153
+ feature(5, 'single_level', 'Single-level dwelling', 'The entire dwelling is explicitly single-story or single-level; a single room on the ground floor is insufficient.', ['InteriorFeatures', 'Stories']),
154
+ feature(5, 'main_level_primary_bedroom', 'Main-level primary bedroom', 'An existing primary bedroom explicitly on the main or entry living level; does not establish step-free entry.', ['InteriorFeatures', 'Rooms', 'RoomType']),
155
+ feature(5, 'main_level_full_bath', 'Main-level full bathroom', 'An existing full bathroom explicitly on the main or entry living level; a powder room is insufficient.', ['InteriorFeatures', 'Rooms', 'RoomType']),
156
+ feature(6, 'garage', 'Garage', 'A garage explicitly included with this property; street parking or a carport is insufficient.', ['ParkingFeatures']),
157
+ feature(6, 'oversized_garage', 'Oversized garage', 'The source explicitly calls the garage oversized; do not infer this from vehicle capacity.', ['ParkingFeatures']),
158
+ exact(6, 'garage_capacity', 'Garage capacity', 'Explicit garage vehicle spaces; no capacity inferred from prose or area.', 'number', ['property_details.garage_spaces']),
159
+ feature(7, 'private_pool', 'Private pool', 'A swimming pool belonging exclusively to this property, not a shared community pool.', ['PoolFeatures']),
160
+ feature(7, 'community_pool', 'Community pool', 'A shared community swimming pool available to this property, not a private pool.', ['CommunityFeatures', 'AssociationAmenities']),
161
+ feature(7, 'private_spa', 'Private spa or hot tub', 'An installed private spa or hot tub included with the property; community spa access is insufficient.', ['SpaFeatures']),
162
+ feature(8, 'water_frontage', 'Water frontage', 'The property itself directly borders a body of water; a view or nearby access alone is insufficient.', ['WaterfrontFeatures']),
163
+ feature(8, 'water_view', 'Water view', 'A water view explicitly described from the property; nearby water alone is insufficient.', ['View']),
164
+ feature(8, 'water_access', 'Water access', 'Explicit access rights or direct access to water associated with the property; nearby water alone is insufficient and no ownership is implied.', ['WaterfrontFeatures', 'AssociationAmenities'], { ...consequential }),
165
+ feature(8, 'dock', 'Dock present', 'An existing dock reported for this property; private ownership and access rights are not implied.', ['Dock'], { applicability: 'any' }),
166
+ feature(8, 'private_dock', 'Private dock', 'An existing dock explicitly for exclusive property use; shared docks, availability and dock permits alone are insufficient.', ['Dock', 'ExteriorFeatures', 'WaterfrontFeatures']),
167
+ feature(9, 'accessory_dwelling', 'Accessory dwelling', 'An explicitly described separate accessory dwelling or guest house; this does not establish legal permit or rental status.', ['OtherStructures', 'InteriorFeatures']),
168
+ feature(9, 'detached_guest_house', 'Detached guest house', 'An existing detached guest dwelling, not a room, attached suite or future conversion; no permit claim.', ['OtherStructures']),
169
+ feature(9, 'guest_suite', 'Guest suite', 'An explicitly separate guest suite within the property; spare bedrooms alone are insufficient.', ['InteriorFeatures', 'Rooms']),
170
+ feature(9, 'in_law_suite', 'In-law suite', 'An existing suite explicitly described as an in-law or multigenerational suite; no legal separate-unit claim.', ['InteriorFeatures', 'Rooms']),
171
+ feature(9, 'separate_entrance', 'Separate entrance', 'An existing separate entrance to a described suite, living space or basement; not merely the dwelling front door.', ['InteriorFeatures', 'ExteriorFeatures', 'Basement']),
172
+ feature(10, 'fenced_yard', 'Fenced yard', 'An explicitly fenced private yard; a fence elsewhere or suggested fencing is insufficient.', ['Fencing', 'ExteriorFeatures']),
173
+ feature(10, 'fully_fenced_yard', 'Fully fenced yard', 'The private yard is explicitly fully fenced or enclosed on all sides; partial fencing or a gate alone is insufficient.', ['Fencing', 'ExteriorFeatures']),
174
+ feature(11, 'fireplace', 'Fireplace', 'An installed fireplace explicitly part of the property.', [
175
+ 'FireplaceFeatures',
176
+ ]),
177
+ feature(11, 'wood_stove', 'Wood stove', 'An installed wood-burning stove; a fireplace or wood-stove-ready connection is insufficient.', ['Heating', 'FireplaceFeatures']),
178
+ feature(12, 'architectural_style', 'Architectural style', 'The architectural style explicitly named in the source; do not guess a style from location, age or price.', ['ArchitecturalStyle'], {
179
+ values: {
180
+ contemporary: 'Explicit contemporary or modern architectural design.',
181
+ craftsman: 'Explicit Craftsman architecture.',
182
+ colonial: 'Explicit Colonial architecture.',
183
+ mediterranean: 'Explicit Mediterranean or Spanish design.',
184
+ ranch: 'Explicit ranch architectural style, not ranch land.',
185
+ victorian: 'Explicit Victorian architecture.',
186
+ other: 'An explicitly named style outside the supplied values.',
187
+ },
188
+ }),
189
+ ...Object.entries({
190
+ midcentury: 'midcentury or mid-century modern',
191
+ tudor: 'Tudor',
192
+ a_frame: 'A-frame',
193
+ cottage: 'cottage',
194
+ loft: 'loft',
195
+ cabin: 'cabin',
196
+ }).map(([id, style]) => feature(12, `style_${id}`, `${style} style`, `The source explicitly describes the dwelling as ${style} architecture or form; do not guess from photographs, age or a nearby place name.`, ['ArchitecturalStyle', 'StructureType'])),
197
+ exact(13, 'lot_area_acres', 'Lot area in acres', 'Exact normalized source lot area with a known conversion unit; unknown units stay unavailable.', 'number', ['lot_size']),
198
+ feature(13, 'barn', 'Barn', 'An existing barn on this property; barn-style decoration and proposed barns are insufficient.', ['OtherStructures'], { applicability: 'any' }),
199
+ feature(13, 'horse_facilities', 'Horse facilities', 'Existing stalls, stables, paddocks or an equestrian arena; horse-friendly zoning or room for horses alone is insufficient.', ['OtherStructures', 'LotFeatures'], { applicability: 'any' }),
200
+ feature(13, 'farm_buildings', 'Farm buildings', 'Existing agricultural outbuildings explicitly on the property; acreage or farmland alone is insufficient.', ['OtherStructures'], { applicability: 'any' }),
201
+ feature(14, 'furnishing', 'Furnishing terms', 'The explicitly advertised furnishing arrangement for this property; staged photographs prove nothing.', [], {
202
+ values: {
203
+ furnished: 'Furniture explicitly included with the advertised transaction.',
204
+ partially_furnished: 'Only some furniture explicitly included.',
205
+ negotiable: 'Furniture explicitly negotiable or separately purchasable, not promised included.',
206
+ unfurnished: 'Explicitly unfurnished or furniture excluded.',
207
+ },
208
+ }),
209
+ feature(15, 'pet_policy', 'Pet policy', 'The advertised property pet rule; this is a source claim, not legal advice or an assistance-animal policy.', ['PetsAllowed'], {
210
+ ...consequential,
211
+ applicability: 'rental',
212
+ values: {
213
+ allowed: 'Pets explicitly allowed without stated restrictions.',
214
+ conditional: 'Pets require approval, conditions or restrictions.',
215
+ prohibited: 'Pets explicitly prohibited.',
216
+ },
217
+ }),
218
+ feature(15, 'cats_allowed', 'Cats allowed', 'Cats explicitly allowed for this rental; conditional approval or generic pets considered is not unconditional permission.', ['PetsAllowed'], { ...consequential, applicability: 'rental' }),
219
+ feature(15, 'dogs_allowed', 'Dogs allowed', 'Dogs explicitly allowed for this rental; conditional approval or generic pets considered is not unconditional permission.', ['PetsAllowed'], { ...consequential, applicability: 'rental' }),
220
+ feature(15, 'pet_restrictions_stated', 'Pet restrictions stated', 'The rental source explicitly states species, breed, size, number or approval restrictions; do not invent their exact terms.', ['PetsAllowed'], { ...consequential, applicability: 'rental' }),
221
+ feature(16, 'dedicated_workspace', 'Dedicated workspace', 'A dedicated office or workspace described as part of the property, rather than a suggested conversion.', ['Rooms', 'RoomType', 'InteriorFeatures', 'OtherStructures']),
222
+ feature(16, 'enclosed_study', 'Enclosed study', 'An existing enclosed study or office room; a desk nook or convertible bedroom is insufficient.', ['Rooms', 'InteriorFeatures']),
223
+ feature(16, 'detached_work_studio', 'Detached work studio', 'An existing detached workspace or studio; a shed suitable for conversion is insufficient.', ['OtherStructures']),
224
+ feature(17, 'garden', 'Garden', 'An existing planted garden belonging to the property; garden tub, garden-level unit and space for a garden are insufficient.', ['ExteriorFeatures', 'LotFeatures', 'Vegetation']),
225
+ feature(17, 'raised_garden_beds', 'Raised garden beds', 'Existing raised garden beds on the property; proposed beds are insufficient.', ['ExteriorFeatures', 'LotFeatures']),
226
+ feature(17, 'greenhouse', 'Greenhouse', 'An existing greenhouse on the property; green home or a proposed greenhouse is insufficient.', ['OtherStructures']),
227
+ feature(17, 'orchard', 'Orchard', 'An existing orchard on the property, not a subdivision or street name.', ['Vegetation', 'LotFeatures']),
228
+ feature(17, 'fruit_trees', 'Fruit trees', 'Existing fruit-bearing trees on the property; decorative trees or a fruit-themed street name are insufficient.', ['Vegetation', 'LotFeatures', 'ExteriorFeatures']),
229
+ feature(18, 'solar_panels', 'Solar panels', 'Installed solar panels explicitly serving the property; suitability or solar-ready wiring is insufficient.', ['GreenEnergyGeneration']),
230
+ feature(18, 'solar_ownership', 'Solar ownership', 'The explicitly stated tenure of the installed solar system; presence alone proves no ownership.', ['GreenEnergyGeneration'], {
231
+ ...consequential,
232
+ values: {
233
+ owned: 'Explicitly owned outright.',
234
+ leased: 'Explicitly leased system.',
235
+ financed: 'Explicitly financed system or outstanding solar loan.',
236
+ },
237
+ }),
238
+ feature(19, 'exposed_beams', 'Exposed beams', 'Explicitly described exposed ceiling or structural beams.', ['InteriorFeatures']),
239
+ feature(19, 'exposed_interior_brick', 'Exposed interior brick', 'Visible exposed brick explicitly inside the dwelling; brick exterior is insufficient.', ['InteriorFeatures']),
240
+ feature(19, 'interior_arches', 'Interior arches', 'Existing architectural arches explicitly inside the dwelling.', ['InteriorFeatures']),
241
+ feature(19, 'original_vintage_details', 'Original vintage details', 'Explicit original or retained historic interior details; generic charm, age or reproduction finishes are insufficient.', ['InteriorFeatures']),
242
+ feature(20, 'central_air_conditioning', 'Central air conditioning', 'Central air conditioning explicitly present; ceiling fans or an unspecified cooling system are insufficient.', ['Cooling']),
243
+ feature(20, 'heat_pump', 'Heat pump', 'An installed heat pump for space conditioning; a heat-pump-ready connection or water heater alone is insufficient.', ['Heating', 'Cooling']),
244
+ feature(20, 'zoned_hvac', 'Zoned HVAC', 'An explicitly zoned heating or cooling system; multiple units alone do not establish independent zones.', ['Heating', 'Cooling']),
245
+ feature(20, 'smart_thermostat', 'Smart thermostat', 'An installed smart or connected thermostat; programmable alone is insufficient.', ['InteriorFeatures', 'GreenEnergyEfficient']),
246
+ feature(21, 'roof_replaced', 'Roof replaced', 'A completed roof replacement explicitly stated; servicing, a warranty, material type or planned replacement is insufficient.', ['Roof']),
247
+ exact(21, 'roof_replacement_year', 'Roof replacement year', 'An explicitly normalized source year for completed roof replacement; never infer a year from relative recency.', 'number', ['attributes.roof_replacement_year']),
248
+ exact(21, 'roof_material', 'Roof material', 'Explicit normalized source roof material; does not establish replacement or condition.', 'string', ['property_details.features.Roof']),
249
+ ...[
250
+ ['hvac', 'HVAC'],
251
+ ['water_heater', 'Water heater'],
252
+ ['windows', 'Windows'],
253
+ ].flatMap(([id, label]) => [
254
+ feature(22, `${id}_replaced`, `${label} replaced`, `A completed ${label.toLowerCase()} replacement explicitly stated; servicing, a warranty and planned work are insufficient.`, id === 'windows' ? ['WindowFeatures'] : ['Heating', 'Cooling', 'Appliances']),
255
+ exact(22, `${id}_replacement_year`, `${label} replacement year`, `An explicitly normalized source year for completed ${label.toLowerCase()} replacement; no date extraction by Jev.`, 'number', [`attributes.${id}_replacement_year`]),
256
+ ]),
257
+ feature(23, 'described_condition', 'Described condition', 'The condition explicitly described in the source, not an inference from photographs, price or generic promotional adjectives.', ['PropertyCondition'], {
258
+ values: {
259
+ new_construction: 'Explicitly newly built or new construction, not merely new to market.',
260
+ renovated: 'Explicitly renovated or remodeled; cosmetic adjectives alone are insufficient.',
261
+ needs_renovation: 'Explicitly needs renovation, repair or substantial work.',
262
+ },
263
+ }),
264
+ feature(23, 'renovated_kitchen', 'Renovated kitchen', 'A completed kitchen renovation or remodel explicitly stated; generic updated finishes or planned work are insufficient.', ['InteriorFeatures', 'PropertyCondition']),
265
+ feature(23, 'renovated_bathroom', 'Renovated bathroom', 'A completed bathroom renovation or remodel explicitly stated; generic updated finishes or planned work are insufficient.', ['InteriorFeatures', 'PropertyCondition']),
266
+ feature(24, 'association_present', 'Association present', 'An owners association explicitly applies to the property; zero or missing fees do not establish no association.', ['AssociationAmenities', 'AssociationFeeIncludes'], { ...consequential }),
267
+ feature(24, 'special_assessment_mentioned', 'Special assessment mentioned', 'An association special assessment is explicitly mentioned; ordinary recurring fees and special listing conditions are insufficient.', ['AssociationFeeIncludes'], { ...consequential }),
268
+ exact(24, 'association_fee_amount', 'Association fee amount', 'Exact primary association amount, used with known currency and period; zero does not prove no association.', 'number', ['property_details.association_fees']),
269
+ exact(24, 'association_fee_currency', 'Association fee currency', 'Explicit supported currency for the primary association fee; never inferred from the listing price.', 'string', ['property_details.association_fees']),
270
+ exact(24, 'association_fee_period', 'Association fee period', 'Exact known primary association billing period; unspecified frequency is unknown.', 'string', ['property_details.association_fees']),
271
+ feature(25, 'workshop', 'Workshop', 'An existing workshop on the property; space suitable for a workshop is insufficient.', ['OtherStructures', 'Rooms']),
272
+ feature(25, 'powered_outbuilding', 'Powered outbuilding', 'An existing outbuilding explicitly supplied with electricity; electric service to the main property alone is insufficient.', ['OtherStructures', 'Utilities']),
273
+ feature(25, 'insulated_outbuilding', 'Insulated outbuilding', 'An existing outbuilding explicitly insulated; potential conversion is insufficient.', ['OtherStructures']),
274
+ feature(26, 'rv_parking', 'RV parking', 'Existing space explicitly designated for RV parking; does not establish hookup or legal permission.', ['ParkingFeatures', 'ExteriorFeatures'], { applicability: 'any' }),
275
+ feature(26, 'boat_parking', 'Boat parking', 'Existing space explicitly designated for boat parking; does not establish water access.', ['ParkingFeatures', 'ExteriorFeatures'], { applicability: 'any' }),
276
+ feature(26, 'covered_vehicle_storage', 'Covered vehicle storage', 'Existing covered RV or boat storage; ordinary garage or uncovered space alone is insufficient.', ['ParkingFeatures', 'OtherStructures'], { applicability: 'any' }),
277
+ feature(26, 'rv_hookup', 'RV hookup', 'An installed RV utility hookup; parking space or general utilities alone are insufficient.', ['ExteriorFeatures', 'Utilities'], { applicability: 'any' }),
278
+ feature(27, 'finished_basement', 'Finished basement', 'Basement explicitly finished in whole or part; no legal bedroom or rental-unit claim.', ['Basement']),
279
+ feature(27, 'walkout_basement', 'Walkout basement', 'Basement explicitly has a walkout to the exterior; an interior stair alone is insufficient.', ['Basement']),
280
+ feature(28, 'mountain_view', 'Mountain view', 'A mountain view explicitly described from the property; geographic proximity alone is insufficient.', ['View']),
281
+ feature(28, 'city_view', 'City view', 'A city or skyline view explicitly described from the property.', ['View']),
282
+ feature(28, 'golf_view', 'Golf view', 'A golf course view explicitly from the property; nearby golf is insufficient.', ['View']),
283
+ feature(28, 'ocean_view', 'Ocean view', 'An ocean view explicitly from the property; proximity or a generic water view is insufficient.', ['View']),
284
+ feature(29, 'open_layout', 'Open layout', 'An explicitly open-plan or open-concept living layout; an open house event is insufficient.', ['InteriorFeatures']),
285
+ feature(29, 'high_ceilings', 'High ceilings', 'Explicitly high, vaulted or cathedral ceilings; do not estimate ceiling height from photos.', ['InteriorFeatures']),
286
+ feature(29, 'skylights', 'Skylights', 'Installed skylights explicitly serving the dwelling; natural-light adjectives alone are insufficient.', ['WindowFeatures', 'InteriorFeatures']),
287
+ feature(30, 'kitchen_island', 'Kitchen island', 'An existing kitchen island; portable furniture or room for an island is insufficient.', ['InteriorFeatures']),
288
+ feature(30, 'eat_in_kitchen', 'Eat-in kitchen', 'An explicitly eat-in kitchen or dedicated dining area inside the kitchen.', ['InteriorFeatures', 'Rooms']),
289
+ feature(30, 'double_vanity', 'Double vanity', 'An installed double-sink bathroom vanity; two separate bathrooms are insufficient.', ['InteriorFeatures']),
290
+ feature(31, 'step_free_entry', 'Step-free entry', 'An explicitly step-free or zero-step entrance to the dwelling; do not infer legal accessibility compliance.', ['AccessibilityFeatures']),
291
+ feature(31, 'entrance_ramp', 'Entrance ramp', 'An existing ramp serving a dwelling entrance; no whole-home accessibility certification.', ['AccessibilityFeatures']),
292
+ feature(31, 'elevator_access', 'Elevator access', 'An elevator explicitly serves the unit or is installed inside the dwelling; do not infer accessibility certification.', ['AccessibilityFeatures', 'InteriorFeatures']),
293
+ feature(31, 'curbless_shower', 'Curbless shower', 'An explicitly curbless or roll-in shower; walk-in shower alone is insufficient.', ['AccessibilityFeatures', 'InteriorFeatures']),
294
+ feature(32, 'security_system', 'Security system', 'An installed security alarm system; monitoring subscription and neighborhood safety are not implied.', ['SecurityFeatures']),
295
+ feature(32, 'security_cameras', 'Security cameras', 'Installed security cameras included with the property; no operating or subscription guarantee.', ['SecurityFeatures']),
296
+ feature(32, 'gated_property', 'Gated property', 'A private gate controlling entry to this property; a gated community alone is insufficient.', ['SecurityFeatures', 'ExteriorFeatures']),
297
+ feature(32, 'community_security', 'Community access control', 'An explicitly described staffed, gated or access-controlled community; this is not a safety or crime claim.', ['SecurityFeatures', 'CommunityFeatures']),
298
+ feature(33, 'outdoor_kitchen', 'Outdoor kitchen', 'An existing private outdoor kitchen; a portable grill alone is insufficient.', ['ExteriorFeatures']),
299
+ feature(33, 'built_in_grill', 'Built-in grill', 'An existing installed private outdoor grill; portable or communal grills are insufficient.', ['ExteriorFeatures']),
300
+ feature(33, 'fire_pit', 'Fire pit', 'An existing private fire pit included with the property; communal access and proposed installation are insufficient.', ['ExteriorFeatures']),
301
+ feature(34, 'ev_charging', 'Installed EV charging', 'An installed electric vehicle charging facility explicitly available to this property; EV-ready wiring alone is insufficient.', ['ParkingFeatures', 'Electric']),
302
+ feature(34, 'ev_ready_wiring', 'EV-ready wiring', 'Installed dedicated EV-ready wiring or prewiring explicitly stated; no installed charger is implied.', ['Electric', 'ParkingFeatures']),
303
+ feature(35, 'generator', 'Generator', 'An installed generator included with the property; generator-ready hookup alone is insufficient.', ['Electric', 'OtherEquipment']),
304
+ feature(35, 'home_battery', 'Home battery', 'An installed home electrical battery storage system; solar alone is insufficient.', ['GreenEnergyGeneration', 'Electric']),
305
+ feature(35, 'backup_power_connection', 'Backup power connection', 'An installed generator inlet, transfer switch or dedicated backup-power connection; no generator is implied.', ['Electric']),
306
+ ...[
307
+ ['designed', 'designed'],
308
+ ['built', 'built'],
309
+ ['owned', 'owned'],
310
+ ].map(([id, verb]) => feature(36, `architect_${id}`, `Architect-${verb}`, `The source explicitly says an architect ${verb} this property; architectural style, architect-quality adjectives or builder name alone are insufficient.`, [], { consequence: 'consequential' })),
311
+ exact(36, 'architect_name', 'Architect name', 'An explicitly normalized public architect credit; names are not generated or guessed by Jev.', 'string', ['attributes.architect_name']),
312
+ feature(37, 'seller_financing', 'Seller financing', 'The seller explicitly offers owner carry or seller financing; buyer financing availability is insufficient.', ['ListingTerms'], {
313
+ ...consequential,
314
+ applicability: 'sale',
315
+ values: offered,
316
+ synonyms: ['owner carry', 'owner financing'],
317
+ }),
318
+ feature(38, 'seller_credit', 'Seller credit', 'An explicitly advertised seller credit or concession; asking-price reductions alone are insufficient.', ['ListingTerms'], { ...consequential, applicability: 'sale', values: offered }),
319
+ feature(38, 'closing_cost_contribution', 'Closing-cost contribution', 'Seller explicitly offers a contribution toward buyer closing costs.', ['ListingTerms'], { ...consequential, applicability: 'sale', values: offered }),
320
+ feature(38, 'rate_buydown', 'Rate buydown', 'An explicitly advertised seller or builder mortgage rate buydown; financing or low-rate adjectives alone are insufficient.', ['ListingTerms'], { ...consequential, applicability: 'sale', values: offered }),
321
+ feature(39, 'assumable_mortgage', 'Assumable mortgage claim', 'An assumable mortgage is explicitly advertised; no guarantee of approval, transferability or rate.', ['ListingTerms'], { ...consequential, applicability: 'sale', values: offered }),
322
+ feature(40, 'lease_purchase_type', 'Lease purchase proposal', 'An explicit rent-to-own arrangement; an ordinary rental does not qualify.', ['ListingTerms'], {
323
+ ...consequential,
324
+ values: {
325
+ lease_option: 'Explicit option to purchase under a lease.',
326
+ lease_purchase: 'Explicit lease-purchase agreement or obligation.',
327
+ rent_to_own: 'Explicit rent-to-own without sufficient subtype detail.',
328
+ not_offered: 'Explicitly no rent-to-own or lease purchase.',
329
+ },
330
+ }),
331
+ feature(41, 'short_term_rental_claim', 'Short-term rental source claim', 'Explicit advertised permission or restriction for short-term rentals; zoning, income potential and current operation do not establish legality.', ['ListingTerms'], {
332
+ ...consequential,
333
+ values: {
334
+ allowed: 'Explicit source claim that short-term rental use is allowed.',
335
+ conditional: 'Explicitly subject to approval, permit or stated conditions.',
336
+ prohibited: 'Explicit source claim that short-term rental use is prohibited.',
337
+ },
338
+ synonyms: ['STR', 'vacation rental'],
339
+ }),
340
+ feature(42, 'occupancy_claim', 'Occupancy source claim', 'Explicit current occupancy or delivery commitment; no exact future date or lease terms inferred.', [], {
341
+ ...consequential,
342
+ values: {
343
+ tenant_occupied: 'Explicitly occupied by a tenant now.',
344
+ lease_in_place: 'An existing lease explicitly remains in force.',
345
+ delivered_vacant: 'Explicit commitment to deliver vacant.',
346
+ vacant: 'Explicitly vacant now.',
347
+ },
348
+ }),
349
+ exact(42, 'vacancy_date', 'Vacancy date', 'An explicitly normalized source vacancy date; relative promises are not converted by Jev.', 'string', ['attributes.vacancy_date']),
350
+ feature(43, 'off_grid_status', 'Off-grid status', 'Explicit operation independent of utility grid service; solar, well and septic alone do not establish off-grid operation.', ['Utilities'], {
351
+ ...consequential,
352
+ values: {
353
+ operating_off_grid: 'The existing property explicitly operates off-grid.',
354
+ grid_optional: 'Existing off-grid operation with an optional grid connection explicitly available.',
355
+ potential: 'Only off-grid potential or proposed conversion is described.',
356
+ },
357
+ }),
358
+ feature(44, 'well', 'Well', 'An installed water well serving the property; does not establish potable water, yield or rights.', ['WaterSource'], { applicability: 'any' }),
359
+ feature(44, 'septic', 'Septic system', 'An installed septic system serving the property; a septic permit or soil suitability is insufficient.', ['Sewer'], { applicability: 'any' }),
360
+ feature(44, 'rainwater_collection', 'Rainwater collection', 'An installed rainwater collection system; no potable-water or capacity claim.', ['WaterSource', 'ExteriorFeatures'], { applicability: 'any' }),
361
+ feature(44, 'cistern', 'Cistern', 'An installed water cistern; no potable-water or capacity claim.', ['WaterSource'], { applicability: 'any' }),
362
+ feature(45, 'storm_shelter', 'Storm shelter', 'An existing space explicitly described as a storm shelter; basement alone is insufficient and no protection certification is implied.', ['OtherStructures', 'SecurityFeatures']),
363
+ feature(45, 'safe_room', 'Safe room', 'An existing room explicitly described as a safe room; generic security does not suffice and no certification is implied.', ['SecurityFeatures', 'Rooms']),
364
+ feature(45, 'underground_bunker', 'Underground bunker', 'An existing underground bunker explicitly stated; basement or shelter alone is insufficient.', ['OtherStructures']),
365
+ feature(46, 'historic_designation_claim', 'Historic designation claim', 'The source explicitly claims an official historic designation or register listing; age and historic character alone are insufficient.', ['SpecialListingConditions'], { consequence: 'consequential' }),
366
+ feature(46, 'historic_character', 'Historic character', 'Explicit historic or period architectural character; does not establish an official designation.', ['ArchitecturalStyle', 'InteriorFeatures']),
367
+ feature(47, 'private_sauna', 'Private sauna', 'An installed private sauna; community sauna access is insufficient.', ['InteriorFeatures', 'OtherStructures']),
368
+ feature(47, 'private_cold_plunge', 'Private cold plunge', 'An installed private cold plunge; pool or communal facility is insufficient.', ['InteriorFeatures', 'ExteriorFeatures']),
369
+ feature(47, 'home_gym', 'Home gym', 'An existing dedicated private gym space; suggested conversion and community fitness are insufficient.', ['Rooms', 'InteriorFeatures']),
370
+ feature(47, 'home_theater', 'Home theater', 'An existing dedicated home theater or media room; an ordinary living-room television is insufficient.', ['Rooms', 'InteriorFeatures']),
371
+ feature(47, 'community_fitness', 'Community fitness', 'An explicitly available shared community fitness center or gym, not a nearby commercial gym.', ['CommunityFeatures', 'AssociationAmenities']),
372
+ ...['tennis', 'pickleball', 'basketball'].flatMap((sport) => ['private', 'community'].map((scope) => feature(48, `${scope}_${sport}_court`, `${scope} ${sport} court`, `An existing ${sport} court ${scope === 'private' ? 'exclusively belonging to this property' : 'available as a shared community amenity'}; nearby facilities and room to build are insufficient.`, scope === 'private'
373
+ ? ['ExteriorFeatures', 'LotFeatures']
374
+ : ['AssociationAmenities', 'CommunityFeatures']))),
375
+ feature(49, 'fiber_internet_advertised', 'Fiber internet advertised', 'Fiber internet service explicitly advertised as available to this property; no active subscription or guaranteed speed.', ['Utilities', 'InteriorFeatures']),
376
+ feature(49, 'high_speed_internet_advertised', 'High-speed internet advertised', 'High-speed internet explicitly advertised as available; no guaranteed speed, uptime or active connection.', ['Utilities', 'InteriorFeatures']),
377
+ feature(50, 'irrigation_system', 'Irrigation system', 'An installed landscape irrigation system; irrigation rights or nearby water alone are insufficient.', ['ExteriorFeatures', 'LotFeatures']),
378
+ feature(50, 'low_maintenance_landscaping', 'Low-maintenance landscaping claim', 'The source explicitly describes existing landscaping as low maintenance; no cost or labor savings estimate.', ['LotFeatures', 'ExteriorFeatures']),
379
+ feature(50, 'xeriscaping', 'Xeriscaping', 'Existing xeriscaping explicitly described; a dry climate or sparse yard is insufficient.', ['LotFeatures', 'ExteriorFeatures']),
380
+ feature(51, 'impact_windows', 'Impact windows', 'Explicit impact-resistant windows; ordinary double glazing is insufficient and no insurance or compliance claim is implied.', ['WindowFeatures']),
381
+ feature(51, 'hurricane_shutters', 'Hurricane shutters', 'Existing hurricane or storm shutters explicitly installed or included; no protection rating implied.', ['WindowFeatures', 'ExteriorFeatures']),
382
+ feature(51, 'fire_resistant_materials', 'Fire-resistant material claim', 'Explicit named fire-resistant construction materials; ordinary material names alone do not establish fire resistance or compliance.', ['ConstructionMaterials', 'Roof']),
383
+ feature(52, 'land_tenure', 'Land tenure claim', 'Explicit land ownership or lease tenure; property subtype and absence of a fee are insufficient.', ['ListingTerms'], {
384
+ ...consequential,
385
+ values: {
386
+ owned: 'Source explicitly states land is owned with the property.',
387
+ leased: 'Source explicitly states land is leased or subject to a ground lease.',
388
+ },
389
+ }),
390
+ exact(52, 'ground_lease_amount', 'Ground lease amount', 'Exact source ground-lease amount with separately preserved currency and frequency.', 'number', ['attributes.ground_lease_amount']),
391
+ exact(52, 'ground_lease_currency', 'Ground lease currency', 'Explicit supported currency for the ground-lease amount; never inferred from the listing price.', 'string', ['attributes.ground_lease_currency']),
392
+ exact(52, 'ground_lease_period', 'Ground lease period', 'Explicit canonical ground-lease billing period; missing frequency stays unknown.', 'string', ['attributes.ground_lease_period']),
393
+ exact(52, 'ground_lease_expiry', 'Ground lease expiry', 'Exact normalized source date of ground-lease expiry; no date extraction by Jev.', 'string', ['attributes.ground_lease_expiry']),
394
+ ].map((definition) => PropertyFeatureDefinitionSchema.parse(definition));
395
+ const propertyFeatureById = new Map(PROPERTY_FEATURE_REGISTRY.map((feature) => [feature.id, feature]));
396
+ export function propertyFeature(id) {
397
+ return propertyFeatureById.get(id);
398
+ }
@@ -0,0 +1,44 @@
1
+ import { z } from 'zod';
2
+ export declare const PublicationReportRequest: z.ZodObject<{
3
+ dataset_id: z.ZodString;
4
+ listing_id: z.ZodString;
5
+ sequence: z.ZodString;
6
+ state: z.ZodEnum<{
7
+ unavailable: "unavailable";
8
+ available: "available";
9
+ }>;
10
+ url: z.ZodNullable<z.ZodURL>;
11
+ listing_revision: z.ZodString;
12
+ listing_published_at: z.ZodISODateTime;
13
+ observed_at: z.ZodISODateTime;
14
+ }, z.core.$strict>;
15
+ export declare const PublicationReceipt: z.ZodObject<{
16
+ listing_id: z.ZodString;
17
+ product_id: z.ZodString;
18
+ sequence: z.ZodString;
19
+ state: z.ZodEnum<{
20
+ unavailable: "unavailable";
21
+ available: "available";
22
+ }>;
23
+ expires_at: z.ZodISODateTime;
24
+ }, z.core.$strict>;
25
+ export declare const DestinationQuery: z.ZodObject<{
26
+ id: z.ZodString;
27
+ dataset_id: z.ZodString;
28
+ product_id: z.ZodString;
29
+ }, z.core.$strict>;
30
+ export declare const DestinationResponse: z.ZodObject<{
31
+ listing_id: z.ZodString;
32
+ product_id: z.ZodString;
33
+ url: z.ZodNullable<z.ZodString>;
34
+ available: z.ZodBoolean;
35
+ reason: z.ZodEnum<{
36
+ unavailable: "unavailable";
37
+ expired: "expired";
38
+ available: "available";
39
+ not_reported: "not_reported";
40
+ listing_changed: "listing_changed";
41
+ source_stale: "source_stale";
42
+ }>;
43
+ checked_at: z.ZodISODateTime;
44
+ }, z.core.$strict>;
@@ -0,0 +1,42 @@
1
+ import { z } from 'zod';
2
+ // Products report their own publication state. This is not a license to publish a listing.
3
+ const Identifier = z.string().min(1).max(256);
4
+ export const PublicationReportRequest = z
5
+ .strictObject({
6
+ dataset_id: Identifier,
7
+ listing_id: Identifier,
8
+ sequence: z.string().regex(/^[1-9]\d{0,17}$/),
9
+ state: z.enum(['available', 'unavailable']),
10
+ url: z.url().max(2048).nullable(),
11
+ listing_revision: z.string().min(1).max(64),
12
+ listing_published_at: z.iso.datetime({ offset: true }),
13
+ observed_at: z.iso.datetime({ offset: true }),
14
+ })
15
+ .refine((input) => (input.state === 'unavailable' ? input.url === null : input.url !== null), 'Available publications need a URL; unavailable publications must clear it.');
16
+ export const PublicationReceipt = z.strictObject({
17
+ listing_id: Identifier,
18
+ product_id: Identifier,
19
+ sequence: z.string(),
20
+ state: z.enum(['available', 'unavailable']),
21
+ expires_at: z.iso.datetime({ offset: true }),
22
+ });
23
+ export const DestinationQuery = z.strictObject({
24
+ id: Identifier,
25
+ dataset_id: Identifier,
26
+ product_id: Identifier,
27
+ });
28
+ export const DestinationResponse = z.strictObject({
29
+ listing_id: Identifier,
30
+ product_id: Identifier,
31
+ url: z.string().nullable(),
32
+ available: z.boolean(),
33
+ reason: z.enum([
34
+ 'available',
35
+ 'not_reported',
36
+ 'unavailable',
37
+ 'expired',
38
+ 'listing_changed',
39
+ 'source_stale',
40
+ ]),
41
+ checked_at: z.iso.datetime({ offset: true }),
42
+ });