@propertysimple/client 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +27 -73
- package/README.md +200 -57
- package/client/src/index.d.ts +257 -2422
- package/client/src/index.js +6 -69
- package/contracts/src/index.d.ts +0 -7
- package/contracts/src/index.js +0 -7
- package/contracts/src/openapi.js +1 -1
- package/contracts/src/operations.d.ts +950 -4678
- package/contracts/src/operations.js +6 -36
- package/contracts/src/opportunity-events.d.ts +2 -1
- package/contracts/src/opportunity-events.js +6 -1
- package/contracts/src/property-features.d.ts +2 -2
- package/contracts/src/property-features.js +62 -19
- package/contracts/src/routes.d.ts +28 -305
- package/contracts/src/routes.js +82 -354
- package/contracts/src/schemas.d.ts +1114 -1355
- package/contracts/src/schemas.js +45 -223
- package/contracts/src/search.d.ts +1366 -253
- package/contracts/src/search.js +117 -2
- package/openapi.json +19288 -38596
- package/package.json +1 -9
- package/client/src/directory-sync.d.ts +0 -123
- package/client/src/directory-sync.js +0 -404
- package/client/src/managed-sync.d.ts +0 -129
- package/client/src/managed-sync.js +0 -410
- package/contracts/src/directory-execution.d.ts +0 -320
- package/contracts/src/directory-execution.js +0 -122
- package/contracts/src/directory-identity.d.ts +0 -1255
- package/contracts/src/directory-identity.js +0 -129
- package/contracts/src/directory-sales.d.ts +0 -333
- package/contracts/src/directory-sales.js +0 -102
- package/contracts/src/directory.d.ts +0 -1088
- package/contracts/src/directory.js +0 -179
- package/contracts/src/intelligence.d.ts +0 -366
- package/contracts/src/intelligence.js +0 -157
- package/contracts/src/professional-intelligence.d.ts +0 -256
- package/contracts/src/professional-intelligence.js +0 -90
- package/contracts/src/publication.d.ts +0 -44
- package/contracts/src/publication.js +0 -42
- package/contracts/src/smart-feed.d.ts +0 -3731
- package/contracts/src/smart-feed.js +0 -109
|
@@ -1,28 +1,11 @@
|
|
|
1
|
-
import { directoryOperations } from './directory.js';
|
|
2
|
-
import { smartFeedOperations } from './smart-feed.js';
|
|
3
|
-
import { professionalIntelligenceOperations } from './professional-intelligence.js';
|
|
4
|
-
import { directorySalesOperations } from './directory-sales.js';
|
|
5
|
-
import { directoryIdentityOperations } from './directory-identity.js';
|
|
6
|
-
import { directoryExecutionOperations } from './directory-execution.js';
|
|
7
1
|
import { searchOperations } from './search.js';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
import { Id, Empty, ResourceQuery, DatasetPageQuery, ListingDetailQuery, ListingSchema, ListingContactsSchema, AgentSchema, ListingQuery, IdentityQuery, IdentitySchema, AgentIdentitySchema, AgentEmailSharingSchema, page, CatalogHealthQuery, CatalogHealthSchema, ListingPage, ListingMapQuery, ListingMapSchema, SimilarListingQuery, SimilarListingsSchema, DomainEventSchema, ListingChangeQuery, ListingChangeSchema, CapabilitiesSchema, ReadinessSchema, } from './schemas.js';
|
|
3
|
+
/** One registry drives the interface, HTTP validation and SDK response validation.
|
|
4
|
+
* Retired operations (directory, feed, snapshots, opportunities, judgments) are
|
|
5
|
+
* listed in routes.ts as retiredRoutes and answer 410. */
|
|
12
6
|
export const operations = {
|
|
13
7
|
...searchOperations,
|
|
14
|
-
...directoryOperations,
|
|
15
|
-
...smartFeedOperations,
|
|
16
|
-
...professionalIntelligenceOperations,
|
|
17
|
-
...directorySalesOperations,
|
|
18
|
-
...directoryIdentityOperations,
|
|
19
|
-
...directoryExecutionOperations,
|
|
20
|
-
evaluateJudgment: { input: JudgmentRequest, output: JudgmentSchema },
|
|
21
|
-
getJudgment: { input: ResourceQuery, output: JudgmentSchema },
|
|
22
|
-
intelligenceCapabilities: { input: Empty, output: IntelligenceCapabilitiesSchema },
|
|
23
8
|
capabilities: { input: Empty, output: CapabilitiesSchema },
|
|
24
|
-
reportPublication: { input: PublicationReportRequest, output: PublicationReceipt },
|
|
25
|
-
resolveDestination: { input: DestinationQuery, output: DestinationResponse },
|
|
26
9
|
listListings: { input: ListingQuery, output: ListingPage },
|
|
27
10
|
getCatalogHealth: { input: CatalogHealthQuery, output: CatalogHealthSchema },
|
|
28
11
|
getListing: { input: ListingDetailQuery, output: ListingSchema },
|
|
@@ -34,23 +17,10 @@ export const operations = {
|
|
|
34
17
|
listSimilarListings: { input: SimilarListingQuery, output: SimilarListingsSchema },
|
|
35
18
|
resolveListingIdentity: { input: IdentityQuery, output: IdentitySchema },
|
|
36
19
|
resolveAgentIdentity: { input: IdentityQuery, output: AgentIdentitySchema },
|
|
20
|
+
getAgentEmailSharing: { input: IdentityQuery, output: AgentEmailSharingSchema },
|
|
37
21
|
getAgent: { input: ResourceQuery, output: AgentSchema },
|
|
38
22
|
listAgentListings: { input: ListingQuery.safeExtend({ id: Id }), output: ListingPage },
|
|
39
|
-
classificationSchema: { input: Empty, output: ClassificationDefinitionSchema },
|
|
40
|
-
createSnapshot: { input: SnapshotRequest, output: SnapshotSchema },
|
|
41
|
-
getSnapshot: { input: ResourceQuery, output: SnapshotSchema },
|
|
42
|
-
listSnapshotItems: { input: ResourcePageQuery, output: ListingPage },
|
|
43
|
-
listCatalogChanges: { input: DatasetPageQuery, output: page(CatalogChangeSchema) },
|
|
44
23
|
listEvents: { input: DatasetPageQuery, output: page(DomainEventSchema) },
|
|
45
|
-
|
|
46
|
-
listOpportunities: { input: OpportunityQuery, output: page(OpportunitySchema) },
|
|
47
|
-
createPlan: { input: PlanRequest, output: PlanSchema },
|
|
48
|
-
getPlan: { input: ResourceQuery, output: PlanSchema },
|
|
49
|
-
listPlanItems: { input: ResourcePageQuery, output: page(PlanItemSchema) },
|
|
50
|
-
claimDispatchBatch: { input: DispatchRequest, output: DispatchBatchSchema },
|
|
51
|
-
startAttempt: { input: AttemptRequest, output: AttemptSchema },
|
|
52
|
-
recordActionOutcomes: { input: OutcomesRequest, output: BatchResultSchema },
|
|
53
|
-
recordProductContextEvents: { input: ContextEventsRequest, output: BatchResultSchema },
|
|
54
|
-
createWebhookSubscription: { input: WebhookRequest, output: WebhookSchema },
|
|
24
|
+
listListingChanges: { input: ListingChangeQuery, output: page(ListingChangeSchema) },
|
|
55
25
|
readiness: { input: Empty, output: ReadinessSchema },
|
|
56
26
|
};
|
|
@@ -11,7 +11,7 @@ export declare const MarketAgeEvidenceSchema: z.ZodObject<{
|
|
|
11
11
|
}, z.core.$strict>;
|
|
12
12
|
/** An observed occasion, never a recommendation, consent, send or order permit.
|
|
13
13
|
* received_at is the platform observation clock used for activity charts;
|
|
14
|
-
* occurred_at preserves the source/calculated boundary for enrollment/history. */
|
|
14
|
+
* occurred_at preserves the source/discovery/calculated boundary for enrollment/history. */
|
|
15
15
|
export declare const OpportunityObservationSchema: z.ZodObject<{
|
|
16
16
|
schema_version: z.ZodLiteral<"opportunity-observation-v1">;
|
|
17
17
|
id: z.ZodString;
|
|
@@ -22,6 +22,7 @@ export declare const OpportunityObservationSchema: z.ZodObject<{
|
|
|
22
22
|
new_to_market: "new_to_market";
|
|
23
23
|
price_drop: "price_drop";
|
|
24
24
|
open_house_changed: "open_house_changed";
|
|
25
|
+
open_house_scheduled: "open_house_scheduled";
|
|
25
26
|
market_age_milestone: "market_age_milestone";
|
|
26
27
|
source_removed: "source_removed";
|
|
27
28
|
}>;
|
|
@@ -8,7 +8,7 @@ export const MarketAgeEvidenceSchema = z.strictObject({
|
|
|
8
8
|
});
|
|
9
9
|
/** An observed occasion, never a recommendation, consent, send or order permit.
|
|
10
10
|
* received_at is the platform observation clock used for activity charts;
|
|
11
|
-
* occurred_at preserves the source/calculated boundary for enrollment/history. */
|
|
11
|
+
* occurred_at preserves the source/discovery/calculated boundary for enrollment/history. */
|
|
12
12
|
export const OpportunityObservationSchema = z
|
|
13
13
|
.strictObject({
|
|
14
14
|
schema_version: z.literal('opportunity-observation-v1'),
|
|
@@ -20,6 +20,7 @@ export const OpportunityObservationSchema = z
|
|
|
20
20
|
'new_to_market',
|
|
21
21
|
'price_drop',
|
|
22
22
|
'open_house_changed',
|
|
23
|
+
'open_house_scheduled',
|
|
23
24
|
'market_age_milestone',
|
|
24
25
|
'source_removed',
|
|
25
26
|
]),
|
|
@@ -44,11 +45,15 @@ export const OpportunityObservationSchema = z
|
|
|
44
45
|
* a consumer can mistake for a newly received marketing opportunity. */
|
|
45
46
|
export function opportunityObservation(input) {
|
|
46
47
|
const event = DomainEventSchema.parse(input);
|
|
48
|
+
if (event.type === 'open_house_changed' &&
|
|
49
|
+
event.evidence.notification_policy === 'scheduled_separately')
|
|
50
|
+
return null;
|
|
47
51
|
const type = event.type === 'listing_removed' ? 'source_removed' : event.type;
|
|
48
52
|
if (![
|
|
49
53
|
'new_to_market',
|
|
50
54
|
'price_drop',
|
|
51
55
|
'open_house_changed',
|
|
56
|
+
'open_house_scheduled',
|
|
52
57
|
'market_age_milestone',
|
|
53
58
|
'source_removed',
|
|
54
59
|
].includes(type))
|
|
@@ -16,9 +16,9 @@ export declare const PropertyFeatureDefinitionSchema: z.ZodObject<{
|
|
|
16
16
|
synonyms: z.ZodArray<z.ZodString>;
|
|
17
17
|
applicability: z.ZodEnum<{
|
|
18
18
|
any: "any";
|
|
19
|
-
rental: "rental";
|
|
20
19
|
dwelling: "dwelling";
|
|
21
20
|
sale: "sale";
|
|
21
|
+
rental: "rental";
|
|
22
22
|
}>;
|
|
23
23
|
source_paths: z.ZodArray<z.ZodString>;
|
|
24
24
|
operators: z.ZodArray<z.ZodEnum<{
|
|
@@ -58,9 +58,9 @@ export declare const PropertyFeatureRegistrySchema: z.ZodObject<{
|
|
|
58
58
|
synonyms: z.ZodArray<z.ZodString>;
|
|
59
59
|
applicability: z.ZodEnum<{
|
|
60
60
|
any: "any";
|
|
61
|
-
rental: "rental";
|
|
62
61
|
dwelling: "dwelling";
|
|
63
62
|
sale: "sale";
|
|
63
|
+
rental: "rental";
|
|
64
64
|
}>;
|
|
65
65
|
source_paths: z.ZodArray<z.ZodString>;
|
|
66
66
|
operators: z.ZodArray<z.ZodEnum<{
|
|
@@ -121,6 +121,18 @@ const offered = {
|
|
|
121
121
|
conditional: 'The source explicitly offers this only subject to approval, terms, qualification or another stated condition.',
|
|
122
122
|
not_offered: 'The source explicitly states this offer is not available.',
|
|
123
123
|
};
|
|
124
|
+
/** A feature the catalog resolves from structured source fields alone, with no prose
|
|
125
|
+
* or model interpretation (rules in packages/core/src/catalog/source-features.ts).
|
|
126
|
+
* Its source paths are exactly the fields those rules read. AI classification is
|
|
127
|
+
* retired, so these and the exact `source_only` values are the features search can
|
|
128
|
+
* match (docs/search-portal-parity-2026-10-23.md). */
|
|
129
|
+
const sourced = (definition, paths, synonyms = []) => ({
|
|
130
|
+
...definition,
|
|
131
|
+
source_paths: paths,
|
|
132
|
+
availability: 'source_only',
|
|
133
|
+
synonyms: [...new Set([...definition.synonyms, ...synonyms])],
|
|
134
|
+
});
|
|
135
|
+
const features = (fields) => fields.map((field) => `property_details.features.${field}`);
|
|
124
136
|
/** Never reuse an existing ID for a narrower claim: the legacy coarse pantry,
|
|
125
137
|
* laundry and style definitions remain alongside precise discovery attributes. */
|
|
126
138
|
export const PROPERTY_FEATURE_REGISTRY = [
|
|
@@ -153,14 +165,25 @@ export const PROPERTY_FEATURE_REGISTRY = [
|
|
|
153
165
|
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
166
|
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
167
|
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']),
|
|
168
|
+
sourced(feature(6, 'garage', 'Garage', 'A garage explicitly included with this property; street parking or a carport is insufficient.', ['ParkingFeatures']), [
|
|
169
|
+
'property_details.source_flags.GarageYN',
|
|
170
|
+
'property_details.source_flags.AttachedGarageYN',
|
|
171
|
+
'property_details.garage_spaces',
|
|
172
|
+
...features(['ParkingFeatures']),
|
|
173
|
+
]),
|
|
157
174
|
feature(6, 'oversized_garage', 'Oversized garage', 'The source explicitly calls the garage oversized; do not infer this from vehicle capacity.', ['ParkingFeatures']),
|
|
158
175
|
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']),
|
|
176
|
+
sourced(feature(7, 'private_pool', 'Private pool', 'A swimming pool belonging exclusively to this property, not a shared community pool.', ['PoolFeatures']), [
|
|
177
|
+
'property_details.source_flags.PoolPrivateYN',
|
|
178
|
+
...features(['ExteriorFeatures', 'LotFeatures']),
|
|
179
|
+
], ['pool', 'swimming pool']),
|
|
160
180
|
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
|
-
|
|
163
|
-
|
|
181
|
+
sourced(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']), [
|
|
182
|
+
'property_details.source_flags.SpaYN',
|
|
183
|
+
...features(['ExteriorFeatures', 'InteriorFeatures', 'LotFeatures']),
|
|
184
|
+
], ['spa', 'hot tub']),
|
|
185
|
+
sourced(feature(8, 'water_frontage', 'Water frontage', 'The property itself directly borders a body of water; a view or nearby access alone is insufficient.', ['WaterfrontFeatures']), ['property_details.source_flags.WaterfrontYN', ...features(['WaterfrontFeatures'])], ['waterfront', 'lakefront', 'oceanfront', 'beachfront', 'riverfront']),
|
|
186
|
+
sourced(feature(8, 'water_view', 'Water view', 'A water view explicitly described from the property; nearby water alone is insufficient.', ['View']), features(['View'])),
|
|
164
187
|
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
188
|
feature(8, 'dock', 'Dock present', 'An existing dock reported for this property; private ownership and access rights are not implied.', ['Dock'], { applicability: 'any' }),
|
|
166
189
|
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']),
|
|
@@ -171,9 +194,10 @@ export const PROPERTY_FEATURE_REGISTRY = [
|
|
|
171
194
|
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
195
|
feature(10, 'fenced_yard', 'Fenced yard', 'An explicitly fenced private yard; a fence elsewhere or suggested fencing is insufficient.', ['Fencing', 'ExteriorFeatures']),
|
|
173
196
|
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
|
-
'
|
|
176
|
-
|
|
197
|
+
sourced(feature(11, 'fireplace', 'Fireplace', 'An installed fireplace explicitly part of the property.', ['FireplaceFeatures']), [
|
|
198
|
+
'property_details.source_flags.FireplaceYN',
|
|
199
|
+
...features(['FireplaceFeatures', 'InteriorFeatures', 'Heating']),
|
|
200
|
+
], ['fireplaces']),
|
|
177
201
|
feature(11, 'wood_stove', 'Wood stove', 'An installed wood-burning stove; a fireplace or wood-stove-ready connection is insufficient.', ['Heating', 'FireplaceFeatures']),
|
|
178
202
|
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
203
|
values: {
|
|
@@ -226,7 +250,15 @@ export const PROPERTY_FEATURE_REGISTRY = [
|
|
|
226
250
|
feature(17, 'greenhouse', 'Greenhouse', 'An existing greenhouse on the property; green home or a proposed greenhouse is insufficient.', ['OtherStructures']),
|
|
227
251
|
feature(17, 'orchard', 'Orchard', 'An existing orchard on the property, not a subdivision or street name.', ['Vegetation', 'LotFeatures']),
|
|
228
252
|
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']),
|
|
253
|
+
sourced(feature(18, 'solar_panels', 'Solar panels', 'Installed solar panels explicitly serving the property; suitability or solar-ready wiring is insufficient.', ['GreenEnergyGeneration']), features([
|
|
254
|
+
'GreenEnergyGeneration',
|
|
255
|
+
'Roof',
|
|
256
|
+
'Electric',
|
|
257
|
+
'Utilities',
|
|
258
|
+
'Appliances',
|
|
259
|
+
'ExteriorFeatures',
|
|
260
|
+
'InteriorFeatures',
|
|
261
|
+
]), ['solar']),
|
|
230
262
|
feature(18, 'solar_ownership', 'Solar ownership', 'The explicitly stated tenure of the installed solar system; presence alone proves no ownership.', ['GreenEnergyGeneration'], {
|
|
231
263
|
...consequential,
|
|
232
264
|
values: {
|
|
@@ -239,8 +271,10 @@ export const PROPERTY_FEATURE_REGISTRY = [
|
|
|
239
271
|
feature(19, 'exposed_interior_brick', 'Exposed interior brick', 'Visible exposed brick explicitly inside the dwelling; brick exterior is insufficient.', ['InteriorFeatures']),
|
|
240
272
|
feature(19, 'interior_arches', 'Interior arches', 'Existing architectural arches explicitly inside the dwelling.', ['InteriorFeatures']),
|
|
241
273
|
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(
|
|
243
|
-
feature(20, '
|
|
274
|
+
sourced(feature(19, 'hardwood_floors', 'Hardwood floors', 'Hardwood or solid wood flooring explicitly listed for the property; laminate, vinyl or wood-look flooring is insufficient.', ['Flooring']), features(['Flooring']), ['hardwood', 'wood floors']),
|
|
275
|
+
sourced(feature(20, 'air_conditioning', 'Air conditioning', 'Air conditioning or another installed cooling system as the source states it (a cooling flag or a named system); ceiling or attic fans alone are insufficient.', ['Cooling']), ['property_details.source_flags.CoolingYN', ...features(['Cooling'])], ['a/c', 'air conditioned', 'cooling']),
|
|
276
|
+
sourced(feature(20, 'central_air_conditioning', 'Central air conditioning', 'Central air conditioning explicitly present; ceiling fans or an unspecified cooling system are insufficient.', ['Cooling']), features(['Cooling']), ['central air', 'central ac']),
|
|
277
|
+
sourced(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']), features(['Heating', 'Cooling'])),
|
|
244
278
|
feature(20, 'zoned_hvac', 'Zoned HVAC', 'An explicitly zoned heating or cooling system; multiple units alone do not establish independent zones.', ['Heating', 'Cooling']),
|
|
245
279
|
feature(20, 'smart_thermostat', 'Smart thermostat', 'An installed smart or connected thermostat; programmable alone is insufficient.', ['InteriorFeatures', 'GreenEnergyEfficient']),
|
|
246
280
|
feature(21, 'roof_replaced', 'Roof replaced', 'A completed roof replacement explicitly stated; servicing, a warranty, material type or planned replacement is insufficient.', ['Roof']),
|
|
@@ -271,16 +305,18 @@ export const PROPERTY_FEATURE_REGISTRY = [
|
|
|
271
305
|
feature(25, 'workshop', 'Workshop', 'An existing workshop on the property; space suitable for a workshop is insufficient.', ['OtherStructures', 'Rooms']),
|
|
272
306
|
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
307
|
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' }),
|
|
308
|
+
sourced(feature(26, 'rv_parking', 'RV parking', 'Existing space explicitly designated for RV parking; does not establish hookup or legal permission.', ['ParkingFeatures', 'ExteriorFeatures'], { applicability: 'any' }), features(['ParkingFeatures', 'ExteriorFeatures']), ['rv']),
|
|
275
309
|
feature(26, 'boat_parking', 'Boat parking', 'Existing space explicitly designated for boat parking; does not establish water access.', ['ParkingFeatures', 'ExteriorFeatures'], { applicability: 'any' }),
|
|
276
310
|
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
311
|
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, '
|
|
279
|
-
feature(27, '
|
|
280
|
-
feature(
|
|
281
|
-
feature(28, '
|
|
282
|
-
feature(28, '
|
|
283
|
-
feature(28, '
|
|
312
|
+
sourced(feature(27, 'basement', 'Basement', 'A basement of any kind explicitly part of the property; a crawl space or slab is insufficient.', ['Basement']), ['property_details.source_flags.BasementYN', ...features(['Basement'])]),
|
|
313
|
+
sourced(feature(27, 'finished_basement', 'Finished basement', 'Basement explicitly finished in whole or part; no legal bedroom or rental-unit claim.', ['Basement']), features(['Basement'])),
|
|
314
|
+
sourced(feature(27, 'walkout_basement', 'Walkout basement', 'Basement explicitly has a walkout to the exterior; an interior stair alone is insufficient.', ['Basement']), features(['Basement'])),
|
|
315
|
+
sourced(feature(28, 'view', 'View', 'Any view explicitly listed for the property (water, mountain, city, golf, territorial and the like); proximity alone is insufficient.', ['View']), features(['View']), ['views']),
|
|
316
|
+
sourced(feature(28, 'mountain_view', 'Mountain view', 'A mountain view explicitly described from the property; geographic proximity alone is insufficient.', ['View']), features(['View'])),
|
|
317
|
+
sourced(feature(28, 'city_view', 'City view', 'A city or skyline view explicitly described from the property.', ['View']), features(['View'])),
|
|
318
|
+
sourced(feature(28, 'golf_view', 'Golf view', 'A golf course view explicitly from the property; nearby golf is insufficient.', ['View']), features(['View'])),
|
|
319
|
+
sourced(feature(28, 'ocean_view', 'Ocean view', 'An ocean view explicitly from the property; proximity or a generic water view is insufficient.', ['View']), features(['View'])),
|
|
284
320
|
feature(29, 'open_layout', 'Open layout', 'An explicitly open-plan or open-concept living layout; an open house event is insufficient.', ['InteriorFeatures']),
|
|
285
321
|
feature(29, 'high_ceilings', 'High ceilings', 'Explicitly high, vaulted or cathedral ceilings; do not estimate ceiling height from photos.', ['InteriorFeatures']),
|
|
286
322
|
feature(29, 'skylights', 'Skylights', 'Installed skylights explicitly serving the dwelling; natural-light adjectives alone are insufficient.', ['WindowFeatures', 'InteriorFeatures']),
|
|
@@ -298,7 +334,14 @@ export const PROPERTY_FEATURE_REGISTRY = [
|
|
|
298
334
|
feature(33, 'outdoor_kitchen', 'Outdoor kitchen', 'An existing private outdoor kitchen; a portable grill alone is insufficient.', ['ExteriorFeatures']),
|
|
299
335
|
feature(33, 'built_in_grill', 'Built-in grill', 'An existing installed private outdoor grill; portable or communal grills are insufficient.', ['ExteriorFeatures']),
|
|
300
336
|
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']),
|
|
337
|
+
sourced(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']), features([
|
|
338
|
+
'ParkingFeatures',
|
|
339
|
+
'Electric',
|
|
340
|
+
'Utilities',
|
|
341
|
+
'GreenEnergyEfficient',
|
|
342
|
+
'ExteriorFeatures',
|
|
343
|
+
'InteriorFeatures',
|
|
344
|
+
]), ['ev charger', 'ev charging', 'electric vehicle charger']),
|
|
302
345
|
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
346
|
feature(35, 'generator', 'Generator', 'An installed generator included with the property; generator-ready hookup alone is insufficient.', ['Electric', 'OtherEquipment']),
|
|
304
347
|
feature(35, 'home_battery', 'Home battery', 'An installed home electrical battery storage system; solar alone is insufficient.', ['GreenEnergyGeneration', 'Electric']),
|