@land-catalyst/batch-data-sdk 1.2.5 → 1.2.8

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.
@@ -16,7 +16,7 @@
16
16
  * .build();
17
17
  * ```
18
18
  */
19
- import { StringFilter, NumericRangeFilter, DateRangeFilter, GeoLocationDistance, GeoLocationBoundingBox, GeoLocationPolygon, AddressSearchCriteria, AssessmentSearchCriteria, BuildingSearchCriteria, CompAddressSearchCriteria, DemographicsSearchCriteria, ForeclosureSearchCriteria, GeneralSearchCriteria, IdsSearchCriteria, IntelSearchCriteria, InvoluntaryLienSearchCriteria, LegalSearchCriteria, ListingSearchCriteria, LotSearchCriteria, OpenLienSearchCriteria, OwnerSearchCriteria, PermitSearchCriteria, PropertyOwnerProfileSearchCriteria, SaleSearchCriteria, TaxSearchCriteria, ValuationSearchCriteria, OrSearchCriteria, SearchCriteria, DeliveryConfig, EventHubConfig, PropertySubscriptionRequest, QuickListValueWithNot, PropertyLookupRequest, PropertyLookupRequestItem, PropertyLookupRequestAddress, PropertyLookupOptions, PropertyPermitRequest, PropertySearchRequest, PropertySearchAsyncRequest, PropertyLookupAsyncRequest, GeoPoint } from "../core/types";
19
+ import { StringFilter, NumericRangeFilter, DateRangeFilter, GeoLocationDistance, GeoLocationBoundingBox, GeoLocationPolygon, AddressSearchCriteria, AssessmentSearchCriteria, BuildingSearchCriteria, CompAddressSearchCriteria, DemographicsSearchCriteria, ForeclosureSearchCriteria, GeneralSearchCriteria, IdsSearchCriteria, IntelSearchCriteria, InvoluntaryLienSearchCriteria, LegalSearchCriteria, ListingSearchCriteria, LotSearchCriteria, OpenLienSearchCriteria, OwnerSearchCriteria, PermitSearchCriteria, PropertyOwnerProfileSearchCriteria, SaleSearchCriteria, TaxSearchCriteria, ValuationSearchCriteria, OrSearchCriteria, SearchCriteria, DeliveryConfig, EventHubConfig, PropertySubscriptionRequest, QuickListValueWithNot, PropertyLookupRequest, PropertyLookupRequestItem, PropertyLookupRequestAddress, PropertyLookupOptions, PropertyPermitRequest, PropertyCountRequest, PropertySearchRequest, PropertySearchAsyncRequest, PropertyLookupAsyncRequest, GeoPoint } from "../core/types";
20
20
  import type { PropertyFieldMetadata } from "../property-field/metadata";
21
21
  /**
22
22
  * Base interface for all builders
@@ -813,6 +813,17 @@ export declare class PropertyLookupRequestBuilder extends BaseBuilder<PropertyLo
813
813
  options(configurator: (builder: PropertyLookupOptionsBuilder) => void): this;
814
814
  build(): PropertyLookupRequest;
815
815
  }
816
+ /**
817
+ * Builder for property count requests
818
+ *
819
+ * Used specifically for count-only requests that should never fetch property data.
820
+ */
821
+ export declare class PropertyCountRequestBuilder extends BaseBuilder<PropertyCountRequest> {
822
+ static from(request: PropertyCountRequest): PropertyCountRequestBuilder;
823
+ searchCriteria(criteria: SearchCriteria): this;
824
+ searchCriteria(configurator: (builder: SearchCriteriaBuilder) => void): this;
825
+ build(): PropertyCountRequest;
826
+ }
816
827
  /**
817
828
  * Builder for property search requests
818
829
  */
@@ -18,7 +18,7 @@
18
18
  * ```
19
19
  */
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.PropertyPermitRequestBuilder = exports.PropertyLookupAsyncRequestBuilder = exports.PropertySearchAsyncRequestBuilder = exports.PropertySearchRequestBuilder = exports.PropertyLookupRequestBuilder = exports.AsyncPropertyLookupOptionsBuilder = exports.PropertyLookupOptionsBuilder = exports.PropertyLookupRequestItemBuilder = exports.PropertySubscriptionBuilder = exports.DeliveryConfigBuilder = exports.SearchCriteriaBuilder = exports.OrSearchCriteriaBuilder = exports.ValuationSearchCriteriaBuilder = exports.TaxSearchCriteriaBuilder = exports.SaleSearchCriteriaBuilder = exports.PropertyOwnerProfileSearchCriteriaBuilder = exports.PermitSearchCriteriaBuilder = exports.OwnerSearchCriteriaBuilder = exports.OpenLienSearchCriteriaBuilder = exports.LotSearchCriteriaBuilder = exports.ListingSearchCriteriaBuilder = exports.LegalSearchCriteriaBuilder = exports.InvoluntaryLienSearchCriteriaBuilder = exports.IntelSearchCriteriaBuilder = exports.IdsSearchCriteriaBuilder = exports.GeneralSearchCriteriaBuilder = exports.ForeclosureSearchCriteriaBuilder = exports.DemographicsSearchCriteriaBuilder = exports.CompAddressSearchCriteriaBuilder = exports.BuildingSearchCriteriaBuilder = exports.AssessmentSearchCriteriaBuilder = exports.AddressSearchCriteriaBuilder = exports.GeoLocationFactory = exports.DateRangeFilterBuilder = exports.NumericRangeFilterBuilder = exports.StringFilterBuilder = void 0;
21
+ exports.PropertyPermitRequestBuilder = exports.PropertyLookupAsyncRequestBuilder = exports.PropertySearchAsyncRequestBuilder = exports.PropertySearchRequestBuilder = exports.PropertyCountRequestBuilder = exports.PropertyLookupRequestBuilder = exports.AsyncPropertyLookupOptionsBuilder = exports.PropertyLookupOptionsBuilder = exports.PropertyLookupRequestItemBuilder = exports.PropertySubscriptionBuilder = exports.DeliveryConfigBuilder = exports.SearchCriteriaBuilder = exports.OrSearchCriteriaBuilder = exports.ValuationSearchCriteriaBuilder = exports.TaxSearchCriteriaBuilder = exports.SaleSearchCriteriaBuilder = exports.PropertyOwnerProfileSearchCriteriaBuilder = exports.PermitSearchCriteriaBuilder = exports.OwnerSearchCriteriaBuilder = exports.OpenLienSearchCriteriaBuilder = exports.LotSearchCriteriaBuilder = exports.ListingSearchCriteriaBuilder = exports.LegalSearchCriteriaBuilder = exports.InvoluntaryLienSearchCriteriaBuilder = exports.IntelSearchCriteriaBuilder = exports.IdsSearchCriteriaBuilder = exports.GeneralSearchCriteriaBuilder = exports.ForeclosureSearchCriteriaBuilder = exports.DemographicsSearchCriteriaBuilder = exports.CompAddressSearchCriteriaBuilder = exports.BuildingSearchCriteriaBuilder = exports.AssessmentSearchCriteriaBuilder = exports.AddressSearchCriteriaBuilder = exports.GeoLocationFactory = exports.DateRangeFilterBuilder = exports.NumericRangeFilterBuilder = exports.StringFilterBuilder = void 0;
22
22
  const metadata_1 = require("../property-field/metadata");
23
23
  /**
24
24
  * Abstract base class for builders that store nested builders
@@ -2421,6 +2421,40 @@ class PropertyLookupRequestBuilder extends BaseBuilder {
2421
2421
  }
2422
2422
  }
2423
2423
  exports.PropertyLookupRequestBuilder = PropertyLookupRequestBuilder;
2424
+ /**
2425
+ * Builder for property count requests
2426
+ *
2427
+ * Used specifically for count-only requests that should never fetch property data.
2428
+ */
2429
+ class PropertyCountRequestBuilder extends BaseBuilder {
2430
+ static from(request) {
2431
+ const builder = new PropertyCountRequestBuilder();
2432
+ builder.searchCriteria(request.searchCriteria);
2433
+ return builder;
2434
+ }
2435
+ searchCriteria(criteriaOrConfigurator) {
2436
+ if (typeof criteriaOrConfigurator === "function") {
2437
+ const builder = new SearchCriteriaBuilder("");
2438
+ criteriaOrConfigurator(builder);
2439
+ this.criteria.searchCriteria = builder.build();
2440
+ this.builders.searchCriteria = undefined;
2441
+ }
2442
+ else {
2443
+ this.criteria.searchCriteria = criteriaOrConfigurator;
2444
+ this.builders.searchCriteria = undefined;
2445
+ }
2446
+ return this;
2447
+ }
2448
+ build() {
2449
+ if (!this.criteria.searchCriteria) {
2450
+ throw new Error("Search criteria is required");
2451
+ }
2452
+ return {
2453
+ searchCriteria: this.criteria.searchCriteria,
2454
+ };
2455
+ }
2456
+ }
2457
+ exports.PropertyCountRequestBuilder = PropertyCountRequestBuilder;
2424
2458
  /**
2425
2459
  * Builder for property search requests
2426
2460
  */
@@ -1,7 +1,7 @@
1
1
  import { AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from "axios";
2
2
  import { IBatchDataClient } from "./client.interface";
3
3
  import { ILogger } from "../core/logger.interface";
4
- import { PropertySubscriptionRequest, PropertySubscriptionResponse, PropertySearchRequest, PropertySearchResponse, AddressVerifyRequest, AddressVerifyResponse, AddressAutocompleteRequest, AddressAutocompleteResponse, AddressGeocodeRequest, AddressGeocodeResponse, AddressReverseGeocodeRequest, AddressReverseGeocodeResponse, PropertyLookupRequest, PropertyLookupResponse, PropertyLookupAsyncRequest, PropertyLookupAsyncResponse, PropertySearchAsyncRequest, PropertySearchAsyncResponse, PropertySkipTraceRequest, PropertySkipTraceResponse, PropertySkipTraceAsyncRequest, PropertySkipTraceAsyncResponse, PhoneVerificationRequest, PhoneVerificationResponse, PhoneVerificationAsyncRequest, PhoneVerificationAsyncResponse, PhoneDNCRequest, PhoneDNCResponse, PhoneDNCAsyncRequest, PhoneDNCAsyncResponse, PhoneTCPARequest, PhoneTCPAResponse, PhoneTCPAAsyncRequest, PhoneTCPAAsyncResponse, GetPropertySubscriptionsResponse, GetPropertySubscriptionDetailResponse, DeletePropertySubscriptionResponse, PropertyPermitRequest, PropertyPermitResponse, PropertySkipTraceV3Request, PropertySkipTraceV3Response, PropertySkipTraceV3AsyncRequest, PropertySkipTraceV3AsyncResponse } from "../core/types";
4
+ import { PropertySubscriptionRequest, PropertySubscriptionResponse, PropertyCountRequest, PropertySearchRequest, PropertySearchResponse, AddressVerifyRequest, AddressVerifyResponse, AddressAutocompleteRequest, AddressAutocompleteResponse, AddressGeocodeRequest, AddressGeocodeResponse, AddressReverseGeocodeRequest, AddressReverseGeocodeResponse, PropertyLookupRequest, PropertyLookupResponse, PropertyLookupAsyncRequest, PropertyLookupAsyncResponse, PropertySearchAsyncRequest, PropertySearchAsyncResponse, PropertySkipTraceRequest, PropertySkipTraceResponse, PropertySkipTraceAsyncRequest, PropertySkipTraceAsyncResponse, PhoneVerificationRequest, PhoneVerificationResponse, PhoneVerificationAsyncRequest, PhoneVerificationAsyncResponse, PhoneDNCRequest, PhoneDNCResponse, PhoneDNCAsyncRequest, PhoneDNCAsyncResponse, PhoneTCPARequest, PhoneTCPAResponse, PhoneTCPAAsyncRequest, PhoneTCPAAsyncResponse, GetPropertySubscriptionsResponse, GetPropertySubscriptionDetailResponse, DeletePropertySubscriptionResponse, PropertyPermitRequest, PropertyPermitResponse, PropertySkipTraceV3Request, PropertySkipTraceV3Response, PropertySkipTraceV3AsyncRequest, PropertySkipTraceV3AsyncResponse } from "../core/types";
5
5
  /**
6
6
  * Middleware function that executes before an HTTP request is sent.
7
7
  * Can modify the request config or perform side effects (logging, metrics, etc.).
@@ -258,10 +258,14 @@ export declare class BatchDataClient implements IBatchDataClient {
258
258
  searchProperties(request: PropertySearchRequest): Promise<PropertySearchResponse>;
259
259
  /**
260
260
  * Get the count of properties matching the search criteria
261
- * @param searchCriteria Search criteria to match properties
261
+ *
262
+ * Uses PropertyCountRequest to ensure no property data is fetched (count-only).
263
+ * This prevents accidental charges for property data retrieval.
264
+ *
265
+ * @param searchRequest Count request with search criteria (no options allowed)
262
266
  * @returns Number of matching properties, or null if the endpoint is unavailable
263
267
  */
264
- getPropertyCount(searchRequest: PropertySearchRequest): Promise<number | null>;
268
+ getPropertyCount(searchRequest: PropertyCountRequest): Promise<number | null>;
265
269
  /**
266
270
  * Verify and normalize addresses (v1 API)
267
271
  * POST /api/v1/address/verify
@@ -1,4 +1,4 @@
1
- import { PropertySubscriptionRequest, PropertySubscriptionResponse, PropertySearchRequest, PropertySearchResponse, AddressVerifyRequest, AddressVerifyResponse, AddressAutocompleteRequest, AddressAutocompleteResponse, AddressGeocodeRequest, AddressGeocodeResponse, AddressReverseGeocodeRequest, AddressReverseGeocodeResponse, PropertyLookupRequest, PropertyLookupResponse, PropertyLookupAsyncRequest, PropertyLookupAsyncResponse, PropertySearchAsyncRequest, PropertySearchAsyncResponse, PropertySkipTraceRequest, PropertySkipTraceResponse, PropertySkipTraceAsyncRequest, PropertySkipTraceAsyncResponse, PhoneVerificationRequest, PhoneVerificationResponse, PhoneVerificationAsyncRequest, PhoneVerificationAsyncResponse, PhoneDNCRequest, PhoneDNCResponse, PhoneDNCAsyncRequest, PhoneDNCAsyncResponse, PhoneTCPARequest, PhoneTCPAResponse, PhoneTCPAAsyncRequest, PhoneTCPAAsyncResponse, GetPropertySubscriptionsResponse, GetPropertySubscriptionDetailResponse, DeletePropertySubscriptionResponse, PropertyPermitRequest, PropertyPermitResponse, PropertySkipTraceV3Request, PropertySkipTraceV3Response, PropertySkipTraceV3AsyncRequest, PropertySkipTraceV3AsyncResponse } from "../core/types";
1
+ import { PropertySubscriptionRequest, PropertySubscriptionResponse, PropertyCountRequest, PropertySearchRequest, PropertySearchResponse, AddressVerifyRequest, AddressVerifyResponse, AddressAutocompleteRequest, AddressAutocompleteResponse, AddressGeocodeRequest, AddressGeocodeResponse, AddressReverseGeocodeRequest, AddressReverseGeocodeResponse, PropertyLookupRequest, PropertyLookupResponse, PropertyLookupAsyncRequest, PropertyLookupAsyncResponse, PropertySearchAsyncRequest, PropertySearchAsyncResponse, PropertySkipTraceRequest, PropertySkipTraceResponse, PropertySkipTraceAsyncRequest, PropertySkipTraceAsyncResponse, PhoneVerificationRequest, PhoneVerificationResponse, PhoneVerificationAsyncRequest, PhoneVerificationAsyncResponse, PhoneDNCRequest, PhoneDNCResponse, PhoneDNCAsyncRequest, PhoneDNCAsyncResponse, PhoneTCPARequest, PhoneTCPAResponse, PhoneTCPAAsyncRequest, PhoneTCPAAsyncResponse, GetPropertySubscriptionsResponse, GetPropertySubscriptionDetailResponse, DeletePropertySubscriptionResponse, PropertyPermitRequest, PropertyPermitResponse, PropertySkipTraceV3Request, PropertySkipTraceV3Response, PropertySkipTraceV3AsyncRequest, PropertySkipTraceV3AsyncResponse } from "../core/types";
2
2
  /**
3
3
  * BatchData API Client Interface
4
4
  *
@@ -26,10 +26,14 @@ export interface IBatchDataClient {
26
26
  searchProperties(request: PropertySearchRequest): Promise<PropertySearchResponse>;
27
27
  /**
28
28
  * Get the count of properties matching the search criteria
29
- * @param searchCriteria Search criteria to match properties
29
+ *
30
+ * Uses PropertyCountRequest to ensure no property data is fetched (count-only).
31
+ * This prevents accidental charges for property data retrieval.
32
+ *
33
+ * @param searchRequest Count request with search criteria (no options allowed)
30
34
  * @returns Number of matching properties, or null if the endpoint is unavailable
31
35
  */
32
- getPropertyCount(searchRequest: PropertySearchRequest): Promise<number | null>;
36
+ getPropertyCount(searchRequest: PropertyCountRequest): Promise<number | null>;
33
37
  /**
34
38
  * Verify and normalize addresses (v1 API)
35
39
  * POST /api/v1/address/verify
@@ -321,14 +321,17 @@ class BatchDataClient {
321
321
  }
322
322
  /**
323
323
  * Get the count of properties matching the search criteria
324
- * @param searchCriteria Search criteria to match properties
324
+ *
325
+ * Uses PropertyCountRequest to ensure no property data is fetched (count-only).
326
+ * This prevents accidental charges for property data retrieval.
327
+ *
328
+ * @param searchRequest Count request with search criteria (no options allowed)
325
329
  * @returns Number of matching properties, or null if the endpoint is unavailable
326
330
  */
327
331
  async getPropertyCount(searchRequest) {
328
- const { searchCriteria, options } = searchRequest;
329
- const lookupOptions = options
330
- ? builders_1.PropertyLookupOptionsBuilder.from(options).take(0)
331
- : new builders_1.PropertyLookupOptionsBuilder();
332
+ const { searchCriteria } = searchRequest;
333
+ // Always use take(0) to ensure no property data is fetched
334
+ const lookupOptions = new builders_1.PropertyLookupOptionsBuilder().take(0);
332
335
  const response = await this.searchProperties({
333
336
  searchCriteria,
334
337
  options: lookupOptions.build(),
@@ -1654,6 +1654,22 @@ export interface PropertySearchRequest {
1654
1654
  searchCriteria: SearchCriteria;
1655
1655
  options?: PropertyLookupOptions;
1656
1656
  }
1657
+ /**
1658
+ * Property count request
1659
+ *
1660
+ * Used specifically for getting property counts without fetching property data.
1661
+ * This type does NOT include options to prevent accidental property data fetching
1662
+ * (which incurs charges). For count-only requests, use this type instead of
1663
+ * PropertySearchRequest to ensure no property data is retrieved.
1664
+ *
1665
+ * Note: All filtering needed for an accurate count should be specified in
1666
+ * searchCriteria. PropertyLookupOptions contains some duplicate filter fields
1667
+ * (useBedrooms, useBathrooms, useYearBuilt, etc.) that mirror SearchCriteria fields,
1668
+ * but these are redundant and should not be needed for accurate counts.
1669
+ */
1670
+ export interface PropertyCountRequest {
1671
+ searchCriteria: SearchCriteria;
1672
+ }
1657
1673
  /**
1658
1674
  * Property lookup request
1659
1675
  */
@@ -53,6 +53,10 @@ export interface PropertyFieldMetadata {
53
53
  * Whether this field is an array element (indicated by [n] in the path)
54
54
  */
55
55
  isArrayElement: boolean;
56
+ /**
57
+ * Optional array of possible values for this field (for enum-like fields)
58
+ */
59
+ possibleValues?: string[];
56
60
  }
57
61
  /**
58
62
  * Registry of all property field metadata, indexed by field path
@@ -47,6 +47,7 @@ exports.PROPERTY_FIELD_METADATA = {
47
47
  dataType: "string",
48
48
  description: "The validity of the address (e.g. Valid, Invalid, Partially Valid)",
49
49
  isArrayElement: false,
50
+ possibleValues: ["Valid", "Invalid", "Partially Valid"],
50
51
  },
51
52
  "address.city": {
52
53
  fieldPath: "address.city",
@@ -187,6 +188,7 @@ exports.PROPERTY_FIELD_METADATA = {
187
188
  dataType: "string",
188
189
  description: "The validity of the address (e.g. Valid, Invalid, Partially Valid)",
189
190
  isArrayElement: false,
191
+ possibleValues: ["Valid", "Invalid", "Partially Valid"],
190
192
  },
191
193
  "owner.names.[n].first": {
192
194
  fieldPath: "owner.names.[n].first",
@@ -78,7 +78,7 @@ exports.SEARCH_CRITERIA_DOMAINS = [
78
78
  {
79
79
  name: "intel",
80
80
  responseGroup: "intel",
81
- description: "Intelligence and predictive analytics (sale propensity, last sold information)",
81
+ description: "Intelligence and predictive analytics (sale propensity score 0-100 predicting likelihood to list/sell, last sold date and price derived from assessor and listing data, length of residence)",
82
82
  },
83
83
  {
84
84
  name: "demographics",
@@ -113,12 +113,12 @@ exports.SEARCH_CRITERIA_DOMAINS = [
113
113
  {
114
114
  name: "propertyOwnerProfile",
115
115
  responseGroup: "propertyOwnerProfile",
116
- description: "Property owner profile information (total properties owned, equity, mortgages, etc.)",
116
+ description: "Property owner profile information - aggregate values across ALL properties owned by the owner (total properties owned, total equity, total mortgages, averages, etc.)",
117
117
  },
118
118
  {
119
119
  name: "quickList",
120
120
  responseGroup: "quickList",
121
- description: "Pre-defined quick filters (owner-occupied, vacant, absentee-owner, high-equity, low-equity, free-and-clear, active-listing, recently-sold, preforeclosure, tax-default, etc.). Can be negated with 'not-' prefix.",
121
+ description: "Pre-defined quick filters (owner-occupied, vacant, absentee-owner, high-equity, low-equity, free-and-clear, active-listing, recently-sold, preforeclosure, tax-default, etc.). Available as top-level fields: quickList (single value), quickLists (array, AND logic), orQuickLists (array, OR logic). Values can be negated with 'not-' prefix. Use orQuickLists for conceptual categories (e.g., 'distressed properties' = orQuickLists: ['vacant', 'preforeclosure', 'tax-default']).",
122
122
  },
123
123
  ];
124
124
  /**
@@ -214,8 +214,9 @@ ${domainDocs}
214
214
  FILTER TYPES:
215
215
  - StringFilter: { equals?, contains?, startsWith?, endsWith?, inList?, matches? }
216
216
  - NumericRangeFilter: { min?, max? }
217
- - DateRangeFilter: { minDate?, maxDate? }
217
+ - DateRangeFilter: { minDate?, maxDate? } (Dates in ISO 8601 format YYYY-MM-DD. For "after [year]", use next year's January 1st, e.g., "after 2015" = { minDate: "2016-01-01" })
218
218
  - BooleanFilter: { equals: boolean }
219
+ - QuickListValue: string (can prefix with "not-" to exclude, e.g., "not-vacant")
219
220
  - GeoLocationDistance: { latitude, longitude, distanceMiles }
220
221
  - GeoLocationBoundingBox: { minLat, maxLat, minLon, maxLon }
221
222
  - GeoLocationPolygon: { geoPoints: [{ latitude, longitude }] }
@@ -232,9 +233,23 @@ IMPORTANT RULES:
232
233
  - "over $500,000" = assessment.totalMarketValue: {min: 500000}
233
234
  - "built after 2010" = building.yearBuilt: {min: 2010}
234
235
  - "last sold after 2015" = sale.lastSaleDate: {minDate: "2016-01-01"} (use next year's January 1st for "after [year]")
236
+ - "high sale propensity" = intel.salePropensity: {min: 70} (salePropensity is 0-100, higher = more likely to sell)
237
+ - "flip properties" = properties bought and sold quickly (use sale.flipLength or quickList: "fix-and-flip")
235
238
  5. Extract geographic information and populate both query and address filters appropriately
236
239
  6. Only include domains that are clearly relevant to the prompt
237
240
  7. If modifying existing criteria, merge intelligently - update what's mentioned, keep what's not
241
+ 8. Conceptual groupings and orQuickLists: When prompts describe conceptual categories that map to multiple quickList values with OR logic, use orQuickLists:
242
+ - "distressed properties" or "distressed" = orQuickLists: ["vacant", "preforeclosure", "tax-default"] (properties with financial distress indicators)
243
+ - "motivated sellers" = orQuickLists: ["preforeclosure", "tax-default", "inherited", "vacant"] (properties where owner may be motivated to sell)
244
+ - "investment properties" = orQuickLists: ["absentee-owner", "corporate-owned", "out-of-state-owner"] (non-owner-occupied investment properties)
245
+ - "off-market" = orQuickLists: ["not-active-listing", "not-on-market", "not-pending-listing"] (properties not currently listed)
246
+ - "equity-rich" = orQuickLists: ["high-equity", "free-and-clear"] (properties with significant equity)
247
+ 9. Field-specific notes:
248
+ - building.totalBuildingAreaSquareFeet: Often includes both living and non-living areas (cumulative total)
249
+ - intel.lastSoldDate vs sale.lastSaleDate: intel.lastSoldDate is derived from assessor and listing data, sale.lastSaleDate is from sale records
250
+ - foreclosure.filingDate vs foreclosure.recordingDate: filingDate may differ from recordingDate
251
+ - owner.ownershipStartDate: Date when the current owner took ownership
252
+ - owner.lengthOfResidence*: Based on last sale date from assessor and listing data
238
253
 
239
254
  INPUT FORMAT:
240
255
  You will receive:
@@ -312,9 +327,7 @@ function getDomainContext(domainName, options = {}) {
312
327
  doc += "\n Available fields:\n";
313
328
  for (const field of fields) {
314
329
  doc += ` - ${field.name} (${field.type}): ${field.description}\n`;
315
- if (field.filterGuidance) {
316
- doc += ` Filter: ${field.filterGuidance}\n`;
317
- }
330
+ // Removed filterGuidance - filter types are already defined in FILTER TYPES section
318
331
  if (field.examples && field.examples.length > 0) {
319
332
  doc += ` Examples: ${field.examples.join(", ")}\n`;
320
333
  }
@@ -366,6 +379,9 @@ function buildDomainDocumentation(domainNames, options = {}) {
366
379
  let doc = "";
367
380
  const queryDomainItem = domains.find((d) => d.name === "query");
368
381
  const optionalDomains = domains.filter((d) => d.name !== "query");
382
+ const quickListDomain = optionalDomains.find((d) => d.name === "quickList");
383
+ const otherOptionalDomains = optionalDomains.filter((d) => d.name !== "quickList");
384
+ const hasQuickListDomain = !!quickListDomain;
369
385
  if (queryDomainItem) {
370
386
  doc += "REQUIRED:\n";
371
387
  doc += `- query: ${queryDomainItem.description}\n`;
@@ -376,15 +392,34 @@ function buildDomainDocumentation(domainNames, options = {}) {
376
392
  else if (optionalDomains.length > 0) {
377
393
  doc += "OPTIONAL DOMAINS:\n";
378
394
  }
379
- for (const domain of optionalDomains) {
395
+ // Add QuickList values section once if quickList domain is included
396
+ if (hasQuickListDomain) {
397
+ doc += "\n";
398
+ doc += (0, search_criteria_filter_context_1.getQuickListValuesSection)();
399
+ doc += "\n";
400
+ }
401
+ // Output quickList domain immediately after QUICKLIST VALUES section for clarity
402
+ if (quickListDomain) {
403
+ doc += `\n- ${quickListDomain.name}: ${quickListDomain.description}`;
404
+ if (quickListDomain.fields.length > 0) {
405
+ doc += "\n Available fields:\n";
406
+ for (const field of quickListDomain.fields) {
407
+ doc += ` - ${field.name} (${field.type}): ${field.description}\n`;
408
+ // Removed filterGuidance - filter types are already defined in FILTER TYPES section
409
+ if (field.examples && field.examples.length > 0) {
410
+ doc += ` Examples: ${field.examples.join(", ")}\n`;
411
+ }
412
+ }
413
+ }
414
+ }
415
+ // Output all other domains
416
+ for (const domain of otherOptionalDomains) {
380
417
  doc += `\n- ${domain.name}: ${domain.description}`;
381
418
  if (domain.fields.length > 0) {
382
419
  doc += "\n Available fields:\n";
383
420
  for (const field of domain.fields) {
384
421
  doc += ` - ${field.name} (${field.type}): ${field.description}\n`;
385
- if (field.filterGuidance) {
386
- doc += ` Filter: ${field.filterGuidance}\n`;
387
- }
422
+ // Removed filterGuidance - filter types are already defined in FILTER TYPES section
388
423
  if (field.examples && field.examples.length > 0) {
389
424
  doc += ` Examples: ${field.examples.join(", ")}\n`;
390
425
  }
@@ -70,6 +70,11 @@ export declare function getSearchCriteriaFilterContext(searchCriteriaPath: strin
70
70
  * ```
71
71
  */
72
72
  export declare function getSearchCriteriaFilterContextString(searchCriteriaPath: string): string;
73
+ /**
74
+ * Get formatted QuickList values section for documentation
75
+ * @returns Formatted string with all QuickList values and descriptions
76
+ */
77
+ export declare function getQuickListValuesSection(): string;
73
78
  /**
74
79
  * Get filter context for all fields in a SearchCriteria domain/group
75
80
  * @param domainName The domain name (e.g., "address", "building", "assessment", "quickList")
@@ -8,6 +8,7 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.getSearchCriteriaFilterContext = getSearchCriteriaFilterContext;
10
10
  exports.getSearchCriteriaFilterContextString = getSearchCriteriaFilterContextString;
11
+ exports.getQuickListValuesSection = getQuickListValuesSection;
11
12
  exports.getDomainFilterContexts = getDomainFilterContexts;
12
13
  exports.getDomainFilterContextDocumentation = getDomainFilterContextDocumentation;
13
14
  const metadata_1 = require("./metadata");
@@ -225,14 +226,28 @@ function getExamples(fieldPath, filterType, _propertyMetadata) {
225
226
  else if (fieldPath.includes("status")) {
226
227
  examples.push('{ equals: "active" }');
227
228
  }
228
- else {
229
- examples.push('{ equals: "value" }');
230
- examples.push('{ contains: "substring" }');
229
+ else if (fieldPath.includes("street")) {
230
+ examples.push('{ equals: "123 Main Street" }');
231
+ examples.push('{ contains: "Main" } // streets containing "Main"');
232
+ }
233
+ else if (fieldPath.includes("description")) {
234
+ examples.push('{ contains: "pool" } // listings containing "pool"');
235
+ examples.push('{ contains: "renovated" } // listings containing "renovated"');
236
+ }
237
+ else if (fieldPath.includes("subdivisionName")) {
238
+ examples.push('{ equals: "Sunset Hills" }');
239
+ examples.push('{ contains: "Hills" } // subdivisions containing "Hills"');
240
+ }
241
+ else if (fieldPath.includes("Name") &&
242
+ (fieldPath.includes("firstName") || fieldPath.includes("lastName"))) {
243
+ examples.push('{ equals: "Smith" }');
244
+ examples.push('{ contains: "Smith" } // names containing "Smith"');
231
245
  }
246
+ // Removed generic examples - only include meaningful, field-specific ones
232
247
  break;
233
248
  case "NumericRangeFilter":
234
249
  if (fieldPath.includes("salePropensity")) {
235
- // Sale propensity is a 0-100 score predicting likelihood to go on market and sell
250
+ // Sale propensity is a 0-100 AVM score predicting likelihood to go on market and sell
236
251
  // Higher scores = higher likelihood
237
252
  examples.push("{ min: 70 } // Very high propensity (70-100) - properties most likely to list/sell soon");
238
253
  examples.push("{ min: 80 } // Extremely high propensity (80-100) - highest likelihood properties");
@@ -250,16 +265,29 @@ function getExamples(fieldPath, filterType, _propertyMetadata) {
250
265
  examples.push("{ min: 2010 } // built after 2010");
251
266
  examples.push("{ max: 2000 } // built before 2000");
252
267
  }
268
+ else if (fieldPath.includes("totalBuildingAreaSquareFeet")) {
269
+ // Note: This field is often a cumulative total including both living and non-living areas
270
+ examples.push("{ min: 1500 } // at least 1500 sq ft");
271
+ examples.push("{ max: 2500 } // under 2500 sq ft");
272
+ examples.push("{ min: 2000, max: 3000 } // between 2000 and 3000 sq ft");
273
+ }
274
+ else if (fieldPath.includes("flipLength") ||
275
+ fieldPath.includes("flipProfit")) {
276
+ // Flip properties are those bought and sold within a short timeframe
277
+ if (fieldPath.includes("flipLength")) {
278
+ examples.push("{ max: 12 } // flipped within 12 months (short-term flips)");
279
+ examples.push("{ min: 6, max: 12 } // flipped between 6-12 months");
280
+ }
281
+ else if (fieldPath.includes("flipProfit")) {
282
+ examples.push("{ min: 50000 } // flip profit of at least $50,000");
283
+ examples.push("{ min: 30000, max: 100000 } // flip profit between $30k-$100k");
284
+ }
285
+ }
253
286
  else if (fieldPath.includes("Value") || fieldPath.includes("Price")) {
254
287
  examples.push("{ max: 400000 } // under $400,000");
255
288
  examples.push("{ min: 500000 } // over $500,000");
256
289
  examples.push("{ min: 300000, max: 500000 } // between $300k and $500k");
257
290
  }
258
- else {
259
- examples.push("{ min: 0 }");
260
- examples.push("{ max: 100 }");
261
- examples.push("{ min: 10, max: 50 }");
262
- }
263
291
  break;
264
292
  case "BooleanFilter":
265
293
  if (fieldPath.includes("ownerOccupied")) {
@@ -270,16 +298,23 @@ function getExamples(fieldPath, filterType, _propertyMetadata) {
270
298
  examples.push("{ equals: true } // properties with children");
271
299
  examples.push("{ equals: false } // properties without children");
272
300
  }
273
- else {
274
- examples.push("{ equals: true }");
275
- examples.push("{ equals: false }");
276
- }
277
301
  break;
278
302
  case "DateRangeFilter":
279
- examples.push('{ minDate: "2020-01-01" } // on or after January 1, 2020');
280
- examples.push('{ minDate: "2016-01-01" } // last sold after 2015 (use next year for "after [year]")');
281
- examples.push('{ maxDate: "2023-12-31" } // before December 31, 2023');
282
- examples.push('{ minDate: "2020-01-01", maxDate: "2023-12-31" } // between dates');
303
+ if (fieldPath.includes("ownershipStartDate")) {
304
+ examples.push('{ minDate: "2020-01-01" } // owner took ownership on or after January 1, 2020');
305
+ examples.push('{ maxDate: "2015-12-31" } // owner took ownership before 2016');
306
+ }
307
+ else if (fieldPath.includes("filingDate")) {
308
+ examples.push('{ minDate: "2020-01-01" } // filed on or after January 1, 2020 (filing date may differ from recording date)');
309
+ examples.push('{ minDate: "2020-01-01", maxDate: "2023-12-31" } // filed between dates');
310
+ }
311
+ else {
312
+ // Include one example for general date filtering
313
+ examples.push('{ minDate: "2020-01-01" } // on or after January 1, 2020');
314
+ examples.push('{ minDate: "2016-01-01" } // last sold after 2015 (use next year for "after [year]")');
315
+ examples.push('{ maxDate: "2023-12-31" } // before December 31, 2023');
316
+ examples.push('{ minDate: "2020-01-01", maxDate: "2023-12-31" } // between dates');
317
+ }
283
318
  break;
284
319
  }
285
320
  return examples;
@@ -466,12 +501,17 @@ function getSearchCriteriaFilterContext(searchCriteriaPath) {
466
501
  filterType: "QuickListValue",
467
502
  propertyPath: undefined,
468
503
  propertyMetadata: undefined,
469
- description: `Pre-defined quick filter${searchCriteriaPath === "quickList" ? "" : "s"} for common property characteristics. Values can be prefixed with "not-" to exclude (e.g., "not-vacant" excludes vacant properties). Use ${searchCriteriaPath === "orQuickLists" ? "orQuickLists array for OR logic" : searchCriteriaPath === "quickLists" ? "quickLists array for multiple values" : "quickList for a single value"}.`,
504
+ description: `Pre-defined quick filter${searchCriteriaPath === "quickList" ? "" : "s"} for common property characteristics. Values can be prefixed with "not-" to exclude (e.g., "not-vacant" excludes vacant properties). Use ${searchCriteriaPath === "orQuickLists" ? "orQuickLists array for OR logic (e.g., conceptual categories like 'distressed properties' = ['vacant', 'preforeclosure', 'tax-default'])" : searchCriteriaPath === "quickLists" ? "quickLists array for multiple values (AND logic)" : "quickList for a single value"}. See QUICKLIST VALUES section for all available values.`,
470
505
  examples: [
471
- ...QUICK_LIST_VALUES_WITH_DESCRIPTIONS.slice(0, 5).map((item) => `"${item.value}" // ${item.description}`),
506
+ ...QUICK_LIST_VALUES_WITH_DESCRIPTIONS.slice(0, 3).map((item) => `"${item.value}" // ${item.description}`),
472
507
  '"not-vacant" // Exclude vacant properties',
473
508
  '"not-owner-occupied" // Exclude owner-occupied properties',
474
- `\nAll available QuickList values (${QUICK_LIST_VALUES_WITH_DESCRIPTIONS.length} total):\n${QUICK_LIST_VALUES_WITH_DESCRIPTIONS.map((item) => ` - "${item.value}": ${item.description}`).join("\n")}`,
509
+ ...(searchCriteriaPath === "orQuickLists"
510
+ ? [
511
+ '["vacant", "preforeclosure", "tax-default"] // Distressed properties (OR logic)',
512
+ '["absentee-owner", "corporate-owned", "out-of-state-owner"] // Investment properties (OR logic)',
513
+ ]
514
+ : []),
475
515
  ],
476
516
  filterGuidance: getFilterGuidance("QuickListValue"),
477
517
  };
@@ -480,10 +520,42 @@ function getSearchCriteriaFilterContext(searchCriteriaPath) {
480
520
  // Try to get Property field metadata
481
521
  const propertyMetadata = (0, metadata_1.getFieldMetadata)(searchCriteriaPath);
482
522
  const propertyPath = propertyMetadata ? searchCriteriaPath : undefined;
483
- // Build description
523
+ // Build description with additional context from data dictionary
484
524
  let description;
485
525
  if (propertyMetadata) {
486
526
  description = `Filter on ${propertyMetadata.description}`;
527
+ // Add additional important context for specific fields based on data dictionary
528
+ if (searchCriteriaPath === "building.totalBuildingAreaSquareFeet") {
529
+ description +=
530
+ " (Note: Often includes cumulative total of living and non-living areas when county doesn't differentiate)";
531
+ }
532
+ else if (searchCriteriaPath === "intel.salePropensity") {
533
+ description +=
534
+ " (0-100 score where higher values indicate greater likelihood to list/sell)";
535
+ }
536
+ else if (searchCriteriaPath === "intel.lastSoldDate") {
537
+ description += " (Derived from assessor and listing data)";
538
+ }
539
+ else if (searchCriteriaPath === "owner.ownershipStartDate") {
540
+ description += " (Date current owner took ownership)";
541
+ }
542
+ else if (searchCriteriaPath.includes("lengthOfResidence")) {
543
+ description +=
544
+ " (Based on last sale date from assessor and listing data)";
545
+ }
546
+ else if (searchCriteriaPath === "foreclosure.filingDate") {
547
+ description +=
548
+ " (Preforeclosure filing date, may differ from recording date)";
549
+ }
550
+ else if (searchCriteriaPath === "involuntaryLien.filingDate") {
551
+ description += " (Lien filing date, may differ from recording date)";
552
+ }
553
+ else if (searchCriteriaPath.includes("flipLength")) {
554
+ description += " (Time between purchase and sale for flipped properties)";
555
+ }
556
+ else if (searchCriteriaPath.includes("flipProfit")) {
557
+ description += " (Profit from flipped property transactions)";
558
+ }
487
559
  }
488
560
  else {
489
561
  const parts = searchCriteriaPath.split(".");
@@ -532,6 +604,17 @@ function getSearchCriteriaFilterContextString(searchCriteriaPath) {
532
604
  }
533
605
  return parts.join("\n");
534
606
  }
607
+ /**
608
+ * Get formatted QuickList values section for documentation
609
+ * @returns Formatted string with all QuickList values and descriptions
610
+ */
611
+ function getQuickListValuesSection() {
612
+ let section = `QUICKLIST VALUES (${QUICK_LIST_VALUES_WITH_DESCRIPTIONS.length} total):\n`;
613
+ for (const item of QUICK_LIST_VALUES_WITH_DESCRIPTIONS) {
614
+ section += ` - "${item.value}": ${item.description}\n`;
615
+ }
616
+ return section;
617
+ }
535
618
  /**
536
619
  * Get filter context for all fields in a SearchCriteria domain/group
537
620
  * @param domainName The domain name (e.g., "address", "building", "assessment", "quickList")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@land-catalyst/batch-data-sdk",
3
- "version": "1.2.5",
3
+ "version": "1.2.8",
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",
@@ -21,6 +21,7 @@
21
21
  "generate:metadata": "node scripts/generate-property-field-metadata.js",
22
22
  "generate:docs": "npx tsx scripts/generate-property-type-docs.ts",
23
23
  "add:jsdoc": "node scripts/add-jsdoc-to-types.js",
24
+ "preversion": "npm run build",
24
25
  "v:patch": "npm version patch && git push --follow-tags",
25
26
  "v:minor": "npm version minor && git push --follow-tags",
26
27
  "v:major": "npm version major && git push --follow-tags"