@land-catalyst/batch-data-sdk 1.5.1 → 1.5.3

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/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export * from "./property-field/display";
16
16
  export * from "./property-field/search-criteria-filter-context";
17
17
  export type { SearchCriteriaFilterContext, SearchCriteriaFilterType, } from "./property-field/search-criteria-filter-context";
18
18
  export * from "./property-field/search-criteria-ai-context";
19
+ export * from "./property-field/property-data-ai-context";
19
20
  export { type PropertyFieldPathType, type PropertyFieldValueType, type FieldMetadataForPath, } from "./property-field/types";
20
21
  export type { SearchCriteriaFieldMapping, SearchCriteriaFieldMetadata, } from "./property-field/utils";
21
22
  export type { RequestMiddleware, ResponseMiddleware, ErrorMiddleware, HttpMiddleware, } from "./client/client";
package/dist/index.js CHANGED
@@ -31,3 +31,4 @@ __exportStar(require("./property-field/utils"), exports);
31
31
  __exportStar(require("./property-field/display"), exports);
32
32
  __exportStar(require("./property-field/search-criteria-filter-context"), exports);
33
33
  __exportStar(require("./property-field/search-criteria-ai-context"), exports);
34
+ __exportStar(require("./property-field/property-data-ai-context"), exports);
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Property Data AI Context Builder
3
+ *
4
+ * Builds context for AI services to analyze and discuss property data.
5
+ * Provides field descriptions, interpretations, and investment insights.
6
+ *
7
+ * This module focuses on Property RESPONSE fields (data returned from searches),
8
+ * not SearchCriteria filter fields. Use search-criteria-ai-context.ts for search filters.
9
+ */
10
+ import type { Property } from "../core/types";
11
+ /**
12
+ * Property data domain with description and investment relevance
13
+ */
14
+ export interface PropertyDataDomain {
15
+ /** Domain name (e.g., "valuation", "permit", "owner") */
16
+ name: string;
17
+ /** Human-readable description */
18
+ description: string;
19
+ /** Why this domain matters for investment analysis */
20
+ investmentRelevance: string;
21
+ /** Key fields to highlight in this domain */
22
+ keyFields?: string[];
23
+ }
24
+ /**
25
+ * All property data domains with descriptions and investment relevance
26
+ */
27
+ export declare const PROPERTY_DATA_DOMAINS: PropertyDataDomain[];
28
+ /**
29
+ * Options for building property data AI context
30
+ */
31
+ export interface PropertyDataAIContextOptions {
32
+ /** Domains to include (defaults to all) */
33
+ domains?: string[];
34
+ /** Whether to include raw field values */
35
+ includeRawValues?: boolean;
36
+ /** Whether to include field metadata descriptions */
37
+ includeFieldDescriptions?: boolean;
38
+ /** Maximum fields per domain to include */
39
+ maxFieldsPerDomain?: number;
40
+ }
41
+ /**
42
+ * Extracted property data with AI-friendly formatting
43
+ */
44
+ export interface PropertyDataContext {
45
+ /** The property address formatted for display */
46
+ address: string;
47
+ /** Key property metrics for quick reference */
48
+ summary: {
49
+ estimatedValue?: number;
50
+ equity?: number;
51
+ equityPercent?: number;
52
+ ltv?: number;
53
+ salePropensity?: number;
54
+ salePropensityCategory?: string;
55
+ yearBuilt?: number;
56
+ sqft?: number;
57
+ bedrooms?: number;
58
+ bathrooms?: number;
59
+ propertyType?: string;
60
+ ownerName?: string;
61
+ ownerType?: string;
62
+ permitCount?: number;
63
+ ownerPortfolioSize?: number;
64
+ };
65
+ /** Motivation signals detected */
66
+ motivationSignals: string[];
67
+ /** Investment considerations */
68
+ considerations: string[];
69
+ /** Domain-specific data */
70
+ domains: Record<string, Record<string, unknown>>;
71
+ }
72
+ /**
73
+ * Build comprehensive property data context for AI
74
+ * @param property The property object to analyze
75
+ * @param options Configuration options
76
+ * @returns Structured context for AI consumption
77
+ * @example
78
+ * ```typescript
79
+ * const context = buildPropertyDataContext(property);
80
+ * // Use context.summary for quick metrics
81
+ * // Use context.motivationSignals for seller motivation
82
+ * // Use context.considerations for investment analysis
83
+ * ```
84
+ */
85
+ export declare function buildPropertyDataContext(property: Property, options?: PropertyDataAIContextOptions): PropertyDataContext;
86
+ /**
87
+ * Build AI system prompt section for property data context
88
+ * @param context The property data context
89
+ * @returns Formatted string for AI system prompt
90
+ */
91
+ export declare function formatPropertyContextForAI(context: PropertyDataContext): string;
92
+ /**
93
+ * Get domain descriptions for AI context
94
+ * @param domainNames Optional list of domains to include
95
+ * @returns Formatted domain descriptions
96
+ */
97
+ export declare function getPropertyDomainDescriptions(domainNames?: string[]): string;
@@ -0,0 +1,464 @@
1
+ "use strict";
2
+ /**
3
+ * Property Data AI Context Builder
4
+ *
5
+ * Builds context for AI services to analyze and discuss property data.
6
+ * Provides field descriptions, interpretations, and investment insights.
7
+ *
8
+ * This module focuses on Property RESPONSE fields (data returned from searches),
9
+ * not SearchCriteria filter fields. Use search-criteria-ai-context.ts for search filters.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.PROPERTY_DATA_DOMAINS = void 0;
13
+ exports.buildPropertyDataContext = buildPropertyDataContext;
14
+ exports.formatPropertyContextForAI = formatPropertyContextForAI;
15
+ exports.getPropertyDomainDescriptions = getPropertyDomainDescriptions;
16
+ const utils_1 = require("./utils");
17
+ /**
18
+ * All property data domains with descriptions and investment relevance
19
+ */
20
+ exports.PROPERTY_DATA_DOMAINS = [
21
+ {
22
+ name: "address",
23
+ description: "Property location and address details",
24
+ investmentRelevance: "Location drives value appreciation, rental rates, and exit strategy options. Neighborhood, school districts, and proximity to amenities affect marketability.",
25
+ keyFields: ["street", "city", "state", "zip", "county"],
26
+ },
27
+ {
28
+ name: "building",
29
+ description: "Building characteristics, size, and features",
30
+ investmentRelevance: "Building specs determine renovation costs, rental potential, and buyer appeal. Year built affects maintenance costs; square footage and bedroom/bath count drive value.",
31
+ keyFields: [
32
+ "yearBuilt",
33
+ "size",
34
+ "bedroomCount",
35
+ "bathCount",
36
+ "generalPropertyType",
37
+ "buildingCondition",
38
+ ],
39
+ },
40
+ {
41
+ name: "valuation",
42
+ description: "Property value estimates including AVM, equity, and loan-to-value",
43
+ investmentRelevance: "AVM provides baseline value for offer calculations. Equity indicates owner flexibility; high equity owners may accept creative deals. LTV over 80% suggests potential distress.",
44
+ keyFields: [
45
+ "estimatedValue",
46
+ "equityCurrentEstimatedBalance",
47
+ "equityPercent",
48
+ "ltv",
49
+ "confidenceScore",
50
+ ],
51
+ },
52
+ {
53
+ name: "permit",
54
+ description: "Building permit history and renovation activity",
55
+ investmentRelevance: "Recent permits indicate property condition and improvements. High permit activity may signal deferred maintenance being addressed or active renovation. Solar/HVAC permits suggest energy efficiency upgrades.",
56
+ keyFields: [
57
+ "permitCount",
58
+ "totalJobValue",
59
+ "latestDate",
60
+ "allTags",
61
+ "tags",
62
+ ],
63
+ },
64
+ {
65
+ name: "propertyOwnerProfile",
66
+ description: "Owner portfolio size and financial position across all owned properties",
67
+ investmentRelevance: "Portfolio owners may be more sophisticated sellers but also more motivated if over-leveraged. High mortgage balance across portfolio suggests potential cash flow pressure. Multiple properties indicate experienced investor who may want quick, clean deals.",
68
+ keyFields: [
69
+ "propertiesCount",
70
+ "propertiesTotalEquity",
71
+ "propertiesTotalEstimatedValue",
72
+ "mortgagesTotalBalance",
73
+ "mortgagesCount",
74
+ ],
75
+ },
76
+ {
77
+ name: "owner",
78
+ description: "Property owner information and contact details",
79
+ investmentRelevance: "Owner type (individual vs corporate vs trust) affects negotiation approach. Absentee owners may be more motivated. Length of ownership indicates attachment level.",
80
+ keyFields: ["fullName", "type", "mailingAddress", "phoneNumbers", "emails"],
81
+ },
82
+ {
83
+ name: "intel",
84
+ description: "Predictive analytics including sale propensity",
85
+ investmentRelevance: "Sale propensity score (0-100) predicts likelihood to sell. Scores above 70 indicate high motivation. Combined with other signals (length of residence, life events), helps prioritize outreach.",
86
+ keyFields: [
87
+ "salePropensity",
88
+ "salePropensityCategory",
89
+ "lastSoldDate",
90
+ "lastSoldPrice",
91
+ ],
92
+ },
93
+ {
94
+ name: "openLien",
95
+ description: "Current mortgages and liens on the property",
96
+ investmentRelevance: "Mortgage balance vs value determines equity and seller flexibility. Multiple liens may indicate financial stress. High interest rates on existing mortgages may motivate seller.",
97
+ keyFields: [
98
+ "totalOpenLienCount",
99
+ "totalOpenLienBalance",
100
+ "mortgages",
101
+ "firstLoanAmount",
102
+ "firstLoanInterestRate",
103
+ ],
104
+ },
105
+ {
106
+ name: "assessment",
107
+ description: "Tax assessment values and market value estimates",
108
+ investmentRelevance: "Assessed value vs market value gap indicates potential appreciation not yet taxed. Assessment increases may pressure cash-strapped owners. Useful for estimating property taxes.",
109
+ keyFields: [
110
+ "totalAssessedValue",
111
+ "totalMarketValue",
112
+ "assessmentYear",
113
+ "landValue",
114
+ "improvementValue",
115
+ ],
116
+ },
117
+ {
118
+ name: "quickLists",
119
+ description: "Pre-computed property flags and characteristics",
120
+ investmentRelevance: "Quick indicators of motivated seller situations. Vacant, pre-foreclosure, tax delinquent, and inherited properties often have motivated sellers. Free-and-clear properties have maximum flexibility.",
121
+ keyFields: [
122
+ "vacant",
123
+ "preforeclosure",
124
+ "taxDefault",
125
+ "inherited",
126
+ "freeAndClear",
127
+ "highEquity",
128
+ "absenteeOwner",
129
+ ],
130
+ },
131
+ {
132
+ name: "foreclosure",
133
+ description: "Foreclosure status and auction information",
134
+ investmentRelevance: "Active foreclosure indicates highly motivated seller with timeline pressure. Auction dates create urgency. Pre-foreclosure is often best window for negotiation.",
135
+ keyFields: ["status", "auctionDate", "defaultAmount", "filingDate"],
136
+ },
137
+ {
138
+ name: "sale",
139
+ description: "Sale history and transaction records",
140
+ investmentRelevance: "Recent sale price establishes baseline. Rapid appreciation or depreciation indicates market trends. Multiple sales in short period may indicate flipper activity or problem property.",
141
+ keyFields: [
142
+ "lastSaleDate",
143
+ "lastSalePrice",
144
+ "lastSaleType",
145
+ "priorSaleDate",
146
+ "priorSalePrice",
147
+ ],
148
+ },
149
+ {
150
+ name: "demographics",
151
+ description: "Owner demographic information",
152
+ investmentRelevance: "Demographics inform communication approach. Senior owners may be considering downsizing. Income and net worth estimates help gauge financial position and deal size capability.",
153
+ keyFields: ["estimatedAge", "estimatedIncome", "estimatedNetWorth"],
154
+ },
155
+ ];
156
+ /**
157
+ * Extract key motivation signals from property data
158
+ */
159
+ function extractMotivationSignals(property) {
160
+ const signals = [];
161
+ const ql = property.quickLists;
162
+ const intel = property.intel;
163
+ const valuation = property.valuation;
164
+ const ownerProfile = property
165
+ .propertyOwnerProfile;
166
+ // QuickList signals
167
+ if (ql?.vacant)
168
+ signals.push("Property appears vacant");
169
+ if (ql?.preforeclosure)
170
+ signals.push("Property is in pre-foreclosure");
171
+ if (ql?.taxDefault)
172
+ signals.push("Property taxes are delinquent");
173
+ if (ql?.inherited)
174
+ signals.push("Property was inherited");
175
+ if (ql?.absenteeOwner)
176
+ signals.push("Owner does not live at property");
177
+ if (ql?.outOfStateOwner)
178
+ signals.push("Owner lives out of state");
179
+ if (ql?.seniorOwner)
180
+ signals.push("Owner is a senior (65+)");
181
+ if (ql?.freeAndClear)
182
+ signals.push("Property is free and clear (no mortgage)");
183
+ if (ql?.highEquity)
184
+ signals.push("High equity position");
185
+ if (ql?.lowEquity)
186
+ signals.push("Low equity position");
187
+ // Sale propensity
188
+ const salePropensity = intel?.salePropensity;
189
+ if (salePropensity !== undefined) {
190
+ if (salePropensity >= 80) {
191
+ signals.push(`Very high sale propensity (${salePropensity}%)`);
192
+ }
193
+ else if (salePropensity >= 60) {
194
+ signals.push(`High sale propensity (${salePropensity}%)`);
195
+ }
196
+ }
197
+ // LTV signals
198
+ const ltv = valuation?.ltv;
199
+ if (ltv !== undefined) {
200
+ if (ltv > 100) {
201
+ signals.push(`Underwater property (LTV: ${ltv.toFixed(0)}%)`);
202
+ }
203
+ else if (ltv > 80) {
204
+ signals.push(`High LTV may indicate financial pressure (${ltv.toFixed(0)}%)`);
205
+ }
206
+ }
207
+ // Portfolio stress signals
208
+ const portfolioMortgages = ownerProfile?.mortgagesTotalBalance;
209
+ const portfolioValue = ownerProfile?.propertiesTotalEstimatedValue;
210
+ if (portfolioMortgages && portfolioValue && portfolioMortgages > 0) {
211
+ const portfolioLtv = (portfolioMortgages / portfolioValue) * 100;
212
+ if (portfolioLtv > 70) {
213
+ signals.push(`Owner portfolio is leveraged (${portfolioLtv.toFixed(0)}% across all properties)`);
214
+ }
215
+ }
216
+ return signals;
217
+ }
218
+ /**
219
+ * Generate investment considerations based on property data
220
+ */
221
+ function generateConsiderations(property) {
222
+ const considerations = [];
223
+ const valuation = property.valuation;
224
+ const permit = property.permit;
225
+ const building = property.building;
226
+ // Equity-based considerations
227
+ const equity = valuation?.equityCurrentEstimatedBalance;
228
+ const estimatedValue = valuation?.estimatedValue;
229
+ if (equity && estimatedValue) {
230
+ const equityPercent = (equity / estimatedValue) * 100;
231
+ if (equityPercent > 50) {
232
+ considerations.push("High equity position gives seller flexibility on terms");
233
+ }
234
+ else if (equityPercent < 20) {
235
+ considerations.push("Low equity may limit seller's ability to negotiate on price");
236
+ }
237
+ }
238
+ // Permit-based considerations
239
+ const permitCount = permit?.permitCount;
240
+ const permitTags = permit?.tags;
241
+ if (permitCount && permitCount > 0) {
242
+ considerations.push(`${permitCount} permits on file indicate renovation history`);
243
+ if (permitTags?.solar) {
244
+ considerations.push("Solar installation may reduce operating costs");
245
+ }
246
+ if (permitTags?.remodel || permitTags?.kitchen || permitTags?.bathroom) {
247
+ considerations.push("Recent remodel permits suggest updated interior");
248
+ }
249
+ if (permitTags?.roofing) {
250
+ considerations.push("Roofing permit suggests recent roof work");
251
+ }
252
+ }
253
+ // Building condition considerations
254
+ const yearBuilt = building?.yearBuilt;
255
+ if (yearBuilt) {
256
+ const age = new Date().getFullYear() - yearBuilt;
257
+ if (age > 50) {
258
+ considerations.push(`Built ${age} years ago - may need significant updates`);
259
+ }
260
+ else if (age > 30) {
261
+ considerations.push(`Built ${age} years ago - likely needs some updates`);
262
+ }
263
+ else if (age < 10) {
264
+ considerations.push("Newer construction - likely lower maintenance costs");
265
+ }
266
+ }
267
+ // Confidence considerations
268
+ const confidence = valuation?.confidenceScore;
269
+ if (confidence !== undefined) {
270
+ if (confidence < 50) {
271
+ considerations.push(`Low AVM confidence (${confidence}) - value estimate may be unreliable`);
272
+ }
273
+ else if (confidence >= 80) {
274
+ considerations.push(`High AVM confidence (${confidence}) - value estimate is reliable`);
275
+ }
276
+ }
277
+ return considerations;
278
+ }
279
+ /**
280
+ * Format address from property data
281
+ */
282
+ function formatAddress(property) {
283
+ const addr = property.address;
284
+ if (!addr)
285
+ return "Unknown Address";
286
+ const street = addr.street ||
287
+ [
288
+ addr.houseNumber,
289
+ addr.streetName,
290
+ addr.streetSuffix,
291
+ ]
292
+ .filter(Boolean)
293
+ .join(" ");
294
+ const city = addr.city || "";
295
+ const state = addr.state || "";
296
+ const zip = addr.zip || "";
297
+ const formatted = `${street}, ${city}, ${state} ${zip}`.trim();
298
+ return formatted.replace(/[,\s]+$/, "") || "Unknown Address";
299
+ }
300
+ /**
301
+ * Extract summary metrics from property data
302
+ */
303
+ function extractSummary(property) {
304
+ const building = property.building;
305
+ const valuation = property.valuation;
306
+ const intel = property.intel;
307
+ const permit = property.permit;
308
+ const ownerProfile = property
309
+ .propertyOwnerProfile;
310
+ const owner = property.owner;
311
+ return {
312
+ estimatedValue: valuation?.estimatedValue,
313
+ equity: valuation?.equityCurrentEstimatedBalance,
314
+ equityPercent: valuation?.equityPercent,
315
+ ltv: valuation?.ltv,
316
+ salePropensity: intel?.salePropensity,
317
+ salePropensityCategory: intel?.salePropensityCategory,
318
+ yearBuilt: building?.yearBuilt,
319
+ sqft: building?.size ||
320
+ building?.livingSquareFeet,
321
+ bedrooms: building?.bedroomCount,
322
+ bathrooms: building?.bathCount,
323
+ propertyType: building?.generalPropertyType,
324
+ ownerName: owner?.fullName,
325
+ ownerType: owner?.type,
326
+ permitCount: permit?.permitCount,
327
+ ownerPortfolioSize: ownerProfile?.propertiesCount,
328
+ };
329
+ }
330
+ /**
331
+ * Extract domain-specific data from property
332
+ */
333
+ function extractDomainData(property, domainName, options) {
334
+ const data = {};
335
+ const domain = exports.PROPERTY_DATA_DOMAINS.find((d) => d.name === domainName);
336
+ if (!domain)
337
+ return data;
338
+ // Get fields for this domain
339
+ const fields = (0, utils_1.getPropertyGroupFields)(domainName);
340
+ const keyFields = new Set(domain.keyFields || []);
341
+ // Prioritize key fields, then add others up to limit
342
+ const sortedFields = [...fields].sort((a, b) => {
343
+ const aKey = keyFields.has(a.fieldPath.split(".").pop() || "");
344
+ const bKey = keyFields.has(b.fieldPath.split(".").pop() || "");
345
+ if (aKey && !bKey)
346
+ return -1;
347
+ if (!aKey && bKey)
348
+ return 1;
349
+ return 0;
350
+ });
351
+ const limit = options.maxFieldsPerDomain || 20;
352
+ const fieldsToProcess = sortedFields.slice(0, limit);
353
+ for (const field of fieldsToProcess) {
354
+ const value = (0, utils_1.getPropertyFieldValue)(property, field.fieldPath);
355
+ if (value !== undefined && value !== null) {
356
+ const fieldName = field.fieldPath.split(".").pop() || field.fieldPath;
357
+ data[fieldName] = value;
358
+ }
359
+ }
360
+ return data;
361
+ }
362
+ /**
363
+ * Build comprehensive property data context for AI
364
+ * @param property The property object to analyze
365
+ * @param options Configuration options
366
+ * @returns Structured context for AI consumption
367
+ * @example
368
+ * ```typescript
369
+ * const context = buildPropertyDataContext(property);
370
+ * // Use context.summary for quick metrics
371
+ * // Use context.motivationSignals for seller motivation
372
+ * // Use context.considerations for investment analysis
373
+ * ```
374
+ */
375
+ function buildPropertyDataContext(property, options = {}) {
376
+ const selectedDomains = options.domains || exports.PROPERTY_DATA_DOMAINS.map((d) => d.name);
377
+ const domains = {};
378
+ for (const domainName of selectedDomains) {
379
+ const domainData = extractDomainData(property, domainName, options);
380
+ if (Object.keys(domainData).length > 0) {
381
+ domains[domainName] = domainData;
382
+ }
383
+ }
384
+ return {
385
+ address: formatAddress(property),
386
+ summary: extractSummary(property),
387
+ motivationSignals: extractMotivationSignals(property),
388
+ considerations: generateConsiderations(property),
389
+ domains,
390
+ };
391
+ }
392
+ /**
393
+ * Build AI system prompt section for property data context
394
+ * @param context The property data context
395
+ * @returns Formatted string for AI system prompt
396
+ */
397
+ function formatPropertyContextForAI(context) {
398
+ const sections = [];
399
+ // Address
400
+ sections.push(`**Address:** ${context.address}`);
401
+ // Summary metrics
402
+ const s = context.summary;
403
+ sections.push("", "## Property Summary");
404
+ if (s.estimatedValue)
405
+ sections.push(`- Estimated Value: $${s.estimatedValue.toLocaleString()}`);
406
+ if (s.equity !== undefined)
407
+ sections.push(`- Equity: $${s.equity.toLocaleString()}`);
408
+ if (s.equityPercent !== undefined)
409
+ sections.push(`- Equity Percent: ${s.equityPercent.toFixed(1)}%`);
410
+ if (s.ltv !== undefined)
411
+ sections.push(`- LTV: ${s.ltv.toFixed(1)}%`);
412
+ if (s.salePropensity !== undefined)
413
+ sections.push(`- Sale Propensity: ${s.salePropensity}% (${s.salePropensityCategory || "Unknown"})`);
414
+ if (s.propertyType)
415
+ sections.push(`- Property Type: ${s.propertyType}`);
416
+ if (s.yearBuilt)
417
+ sections.push(`- Year Built: ${s.yearBuilt}`);
418
+ if (s.sqft)
419
+ sections.push(`- Square Feet: ${s.sqft.toLocaleString()}`);
420
+ if (s.bedrooms !== undefined)
421
+ sections.push(`- Bedrooms: ${s.bedrooms}`);
422
+ if (s.bathrooms !== undefined)
423
+ sections.push(`- Bathrooms: ${s.bathrooms}`);
424
+ if (s.ownerName)
425
+ sections.push(`- Owner: ${s.ownerName}`);
426
+ if (s.ownerType)
427
+ sections.push(`- Owner Type: ${s.ownerType}`);
428
+ if (s.permitCount)
429
+ sections.push(`- Permit Count: ${s.permitCount}`);
430
+ if (s.ownerPortfolioSize)
431
+ sections.push(`- Owner Portfolio Size: ${s.ownerPortfolioSize} properties`);
432
+ // Motivation signals
433
+ if (context.motivationSignals.length > 0) {
434
+ sections.push("", "## Motivation Signals");
435
+ for (const signal of context.motivationSignals) {
436
+ sections.push(`- ${signal}`);
437
+ }
438
+ }
439
+ // Investment considerations
440
+ if (context.considerations.length > 0) {
441
+ sections.push("", "## Investment Considerations");
442
+ for (const consideration of context.considerations) {
443
+ sections.push(`- ${consideration}`);
444
+ }
445
+ }
446
+ return sections.join("\n");
447
+ }
448
+ /**
449
+ * Get domain descriptions for AI context
450
+ * @param domainNames Optional list of domains to include
451
+ * @returns Formatted domain descriptions
452
+ */
453
+ function getPropertyDomainDescriptions(domainNames) {
454
+ const selectedDomains = domainNames
455
+ ? exports.PROPERTY_DATA_DOMAINS.filter((d) => domainNames.includes(d.name))
456
+ : exports.PROPERTY_DATA_DOMAINS;
457
+ const lines = ["## Property Data Domains", ""];
458
+ for (const domain of selectedDomains) {
459
+ lines.push(`**${domain.name}**: ${domain.description}`);
460
+ lines.push(` Investment Relevance: ${domain.investmentRelevance}`);
461
+ lines.push("");
462
+ }
463
+ return lines.join("\n");
464
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@land-catalyst/batch-data-sdk",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "TypeScript SDK for BatchData.io Property API - Types, Builders, and Utilities",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",