townshipamerica 1.0.0 → 1.0.2

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/README.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # townshipamerica
2
2
 
3
- Official TypeScript SDK for the [Township America API](https://townshipamerica.com/api) — convert US PLSS (Public Land Survey System) legal land descriptions to GPS coordinates and back.
3
+ [![npm](https://img.shields.io/npm/v/townshipamerica)](https://www.npmjs.com/package/townshipamerica)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
5
+
6
+ Official TypeScript SDK for the [Township America API](https://townshipamerica.com/api) — convert US PLSS (Public Land Survey System) and Texas TXSS legal land descriptions to GPS coordinates and back.
7
+
8
+ [Documentation](https://townshipamerica.com/api) · [GitHub](https://github.com/townshipamerica/typescript-sdk) · [npm](https://www.npmjs.com/package/townshipamerica)
4
9
 
5
10
  ## Install
6
11
 
@@ -16,23 +21,27 @@ import { TownshipClient } from "townshipamerica";
16
21
  const client = new TownshipClient({ apiKey: "YOUR_API_KEY" });
17
22
 
18
23
  // PLSS to GPS
19
- const result = await client.search("NW 25 24N 1E 6th Meridian");
20
- console.log(result.latitude, result.longitude); // 41.077932 -104.01924
21
- console.log(result.state); // "Colorado"
22
- console.log(result.county); // "Weld"
24
+ const plss = await client.search("NW 25 24N 1E 6th Meridian");
25
+ console.log(plss.latitude, plss.longitude); // 41.077932 -104.01924
26
+ console.log(plss.surveySystem); // "PLSS"
27
+
28
+ // Texas TXSS to GPS
29
+ const tx = await client.search("A-175 Reeves County");
30
+ console.log(tx.surveySystem); // "TXSS"
31
+ console.log(tx.state); // "TX"
23
32
 
24
- // GPS to PLSS
33
+ // GPS to legal description (PLSS or TXSS depending on location)
25
34
  const reverse = await client.reverse(-104.01924, 41.077932);
26
- console.log(reverse.legalLocation); // "NW 25 24N 1E 6th Meridian"
35
+ console.log(reverse.legalLocation);
27
36
 
28
- // Autocomplete
29
- const suggestions = await client.autocomplete("NW 25", { limit: 5 });
37
+ // Autocomplete (PLSS or TXSS)
38
+ const suggestions = await client.autocomplete("A-175", { limit: 5 });
30
39
  console.log(suggestions.features[0].properties.legal_location);
31
40
 
32
- // Batch (up to 100 per request, auto-chunks larger arrays)
41
+ // Batch — mix PLSS and TXSS in one call (up to 100 per request, auto-chunks larger arrays)
33
42
  const batch = await client.batchSearch([
34
43
  "NW 25 24N 1E 6th Meridian",
35
- "NE 12 4N 5E Indian Meridian"
44
+ "A-175 Reeves County"
36
45
  ]);
37
46
  ```
38
47
 
@@ -50,10 +59,11 @@ const batch = await client.batchSearch([
50
59
 
51
60
  ### `client.search(legalLocation)`
52
61
 
53
- Convert a PLSS legal land description to GPS coordinates.
62
+ Convert a PLSS or Texas TXSS legal land description to GPS coordinates.
54
63
 
55
64
  ```typescript
56
- const result = await client.search("NE 12 4N 5E Indian Meridian");
65
+ const plss = await client.search("NE 12 4N 5E Indian Meridian");
66
+ const tx = await client.search("A-175 Reeves County");
57
67
  ```
58
68
 
59
69
  **Returns:** `SearchResult`
@@ -65,17 +75,19 @@ const result = await client.search("NE 12 4N 5E Indian Meridian");
65
75
  | `longitude` | `number` | Centroid longitude |
66
76
  | `state` | `string` | US state |
67
77
  | `county` | `string` | County |
68
- | `unit` | `string` | `Township`, `First Division`, or `Second Division` |
69
- | `surveySystem` | `string` | `PLSS` |
78
+ | `unit` | `string \| null` | PLSS unit, or `null` for TXSS |
79
+ | `surveySystem` | `"PLSS" \| "TXSS"` | Survey system |
70
80
  | `alternateLegalLocation` | `string` | Alternate description format |
71
- | `boundary` | `GeoJSONPolygon \| null` | Grid boundary polygon |
81
+ | `boundary` | `GeoJSONBoundary \| null` | Grid boundary polygon (Polygon or MultiPolygon) |
72
82
  | `raw` | `GeoJSONFeatureCollection` | Raw API response |
73
83
 
84
+ TXSS responses also include `abstract_no`, `block_no`, `survey_name`, and `acreage` on feature properties when available.
85
+
74
86
  ---
75
87
 
76
88
  ### `client.reverse(longitude, latitude, options?)`
77
89
 
78
- Find the PLSS description at GPS coordinates.
90
+ Find the legal land description at GPS coordinates (PLSS or Texas TXSS).
79
91
 
80
92
  ```typescript
81
93
  const result = await client.reverse(-104.01924, 41.077932, {
@@ -95,7 +107,7 @@ const result = await client.reverse(-104.01924, 41.077932, {
95
107
 
96
108
  ### `client.autocomplete(query, options?)`
97
109
 
98
- Get autocomplete suggestions for a partial PLSS description.
110
+ Get autocomplete suggestions for a partial PLSS or Texas TXSS description.
99
111
 
100
112
  ```typescript
101
113
  const fc = await client.autocomplete("NW 25", { limit: 5 });
@@ -166,7 +178,7 @@ const polygon = await client.boundary("NW 25 24N 1E 6th Meridian");
166
178
  // polygon.coordinates === [[[lng, lat], ...]]
167
179
  ```
168
180
 
169
- **Returns:** `GeoJSONPolygon | null`
181
+ **Returns:** `GeoJSONPolygon | GeoJSONMultiPolygon | null`
170
182
 
171
183
  ---
172
184
 
@@ -212,7 +224,9 @@ try {
212
224
  }
213
225
  ```
214
226
 
215
- ## PLSS Format Examples
227
+ ## Format Examples
228
+
229
+ ### PLSS (30 states)
216
230
 
217
231
  ```
218
232
  NW 25 24N 1E 6th Meridian → Quarter Section (First Division)
@@ -222,6 +236,15 @@ NE 12 4N 5E Indian Meridian → Named meridian
222
236
  7 2N 3E Black Hills Meridian → Section with named meridian
223
237
  ```
224
238
 
239
+ ### Texas TXSS
240
+
241
+ ```
242
+ A-175 Reeves County
243
+ Abstract 175 Reeves County Texas
244
+ Block 25 Section 14 Pecos County
245
+ Survey H&TC, Travis County
246
+ ```
247
+
225
248
  ## License
226
249
 
227
250
  MIT — [Maps & Apps Inc.](https://townshipamerica.com)
package/dist/index.cjs CHANGED
@@ -153,9 +153,9 @@ var TownshipClient = class {
153
153
  }
154
154
  // --- Search ---
155
155
  /**
156
- * Convert a PLSS legal land description to GPS coordinates.
156
+ * Convert a PLSS or Texas TXSS legal land description to GPS coordinates.
157
157
  *
158
- * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian"
158
+ * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian" or "A-175 Reeves County"
159
159
  * @returns A SearchResult with coordinates, boundary, and metadata.
160
160
  * @throws {ValidationError} If the location string is invalid.
161
161
  * @throws {NotFoundError} If no match is found.
@@ -171,11 +171,11 @@ var TownshipClient = class {
171
171
  return toSearchResult(data);
172
172
  }
173
173
  /**
174
- * Find the PLSS legal land description at the given GPS coordinates.
174
+ * Find the legal land description at the given GPS coordinates (PLSS or Texas TXSS).
175
175
  *
176
176
  * @param longitude - Longitude (x) coordinate.
177
177
  * @param latitude - Latitude (y) coordinate.
178
- * @param options - Optional unit filter.
178
+ * @param options - Optional PLSS unit filter (ignored for TXSS results).
179
179
  * @returns A SearchResult or array of SearchResults (when unit is 'all').
180
180
  */
181
181
  async reverse(longitude, latitude, options) {
@@ -207,7 +207,7 @@ var TownshipClient = class {
207
207
  }
208
208
  // --- Autocomplete ---
209
209
  /**
210
- * Get autocomplete suggestions for a partial PLSS description.
210
+ * Get autocomplete suggestions for a partial PLSS or Texas TXSS description.
211
211
  *
212
212
  * @param query - Partial search query (minimum 2 characters).
213
213
  * @param options - Optional limit (1–10, default 3) and proximity.
@@ -225,10 +225,10 @@ var TownshipClient = class {
225
225
  }
226
226
  // --- Batch ---
227
227
  /**
228
- * Convert multiple PLSS descriptions to GPS coordinates in one request.
229
- * Auto-chunks if more than 100 items.
228
+ * Convert multiple legal land descriptions to GPS coordinates in one request.
229
+ * Auto-chunks if more than 100 items. Mix PLSS and Texas TXSS inputs freely.
230
230
  *
231
- * @param locations - Array of PLSS legal land descriptions.
231
+ * @param locations - Array of legal land descriptions.
232
232
  * @param options - Optional chunk size.
233
233
  * @returns Array of SearchResult or null for each input.
234
234
  */
@@ -256,11 +256,11 @@ var TownshipClient = class {
256
256
  return results;
257
257
  }
258
258
  /**
259
- * Find PLSS descriptions for multiple coordinate pairs in one request.
259
+ * Find legal land descriptions for multiple coordinate pairs in one request.
260
260
  * Auto-chunks if more than 100 items.
261
261
  *
262
262
  * @param coordinates - Array of [longitude, latitude] pairs.
263
- * @param options - Optional unit filter and chunk size.
263
+ * @param options - Optional PLSS unit filter and chunk size.
264
264
  * @returns Array of SearchResult or null for each input.
265
265
  */
266
266
  async batchReverse(coordinates, options) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export { TownshipClient } from \"./client.js\";\nexport {\n TownshipError,\n AuthenticationError,\n NotFoundError,\n RateLimitError,\n ValidationError,\n PayloadTooLargeError\n} from \"./errors.js\";\nexport type {\n TownshipClientOptions,\n GeoJSONPoint,\n GeoJSONPolygon,\n GeoJSONFeature,\n GeoJSONFeatureCollection,\n FeatureProperties,\n Unit,\n SearchResult,\n ReverseOptions,\n AutocompleteOptions,\n BatchSearchOptions,\n BatchReverseOptions\n} from \"./types.js\";\n","/**\n * Base error class for all Township SDK errors.\n */\nexport class TownshipError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number | null = null\n ) {\n super(message);\n this.name = \"TownshipError\";\n }\n}\n\n/**\n * Thrown when the API key is missing or invalid (HTTP 401).\n */\nexport class AuthenticationError extends TownshipError {\n constructor(message = \"Invalid or missing API key\") {\n super(message, 401);\n this.name = \"AuthenticationError\";\n }\n}\n\n/**\n * Thrown when no result is found for the given input.\n */\nexport class NotFoundError extends TownshipError {\n constructor(message = \"Location not found\") {\n super(message, 404);\n this.name = \"NotFoundError\";\n }\n}\n\n/**\n * Thrown when the API rate limit is exceeded (HTTP 429).\n */\nexport class RateLimitError extends TownshipError {\n constructor(message = \"Rate limit exceeded. Please slow down your requests.\") {\n super(message, 429);\n this.name = \"RateLimitError\";\n }\n}\n\n/**\n * Thrown when the request is malformed (HTTP 400).\n */\nexport class ValidationError extends TownshipError {\n constructor(message = \"Invalid request\") {\n super(message, 400);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Thrown when the batch payload exceeds the maximum size (HTTP 413).\n */\nexport class PayloadTooLargeError extends TownshipError {\n constructor(message = \"Batch payload exceeds the maximum of 100 records per request\") {\n super(message, 413);\n this.name = \"PayloadTooLargeError\";\n }\n}\n","import {\n AuthenticationError,\n NotFoundError,\n PayloadTooLargeError,\n RateLimitError,\n TownshipError,\n ValidationError\n} from \"./errors.js\";\nimport type {\n AutocompleteOptions,\n BatchReverseOptions,\n BatchSearchOptions,\n GeoJSONFeatureCollection,\n GeoJSONPolygon,\n ReverseOptions,\n SearchResult,\n TownshipClientOptions\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://developer.townshipamerica.com\";\nconst DEFAULT_TIMEOUT = 30_000;\nconst MAX_BATCH_SIZE = 100;\n\nfunction toSearchResult(fc: GeoJSONFeatureCollection): SearchResult {\n const centroid = fc.features.find((f) => f.properties.shape === \"centroid\");\n const grid = fc.features.find((f) => f.properties.shape === \"grid\");\n\n const props = centroid?.properties ?? grid?.properties;\n if (!props) {\n throw new TownshipError(\"Unexpected API response: no features returned\");\n }\n\n const [lng, lat] = centroid ? (centroid.geometry.coordinates as [number, number]) : [0, 0];\n\n return {\n legalLocation: props.legal_location,\n latitude: lat,\n longitude: lng,\n state: props.state,\n county: props.county,\n unit: props.unit,\n surveySystem: props.survey_system,\n alternateLegalLocation: props.alternate_legal_location,\n boundary: grid ? (grid.geometry as GeoJSONPolygon) : null,\n raw: fc\n };\n}\n\nexport class TownshipClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n\n constructor(options: TownshipClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT;\n\n if (!this.apiKey) {\n throw new TownshipError(\"apiKey is required\");\n }\n }\n\n // --- Internal ---\n\n private async request<T>(path: string, init?: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n ...init,\n headers: {\n \"X-API-Key\": this.apiKey,\n \"User-Agent\": \"townshipamerica-js/1.0.0\",\n ...(init?.headers ?? {})\n },\n signal: controller.signal\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as T;\n } catch (error) {\n if (error instanceof TownshipError) throw error;\n if (error instanceof DOMException && error.name === \"AbortError\") {\n throw new TownshipError(\"Request timed out\");\n }\n throw new TownshipError(error instanceof Error ? error.message : \"Unknown error\");\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async handleError(response: Response): Promise<never> {\n let message: string;\n try {\n const body = (await response.json()) as Record<string, unknown>;\n message = (body.error ?? body.message ?? response.statusText) as string;\n } catch {\n message = response.statusText;\n }\n\n const status = response.status;\n if (status === 400) throw new ValidationError(message);\n if (status === 401) throw new AuthenticationError(message);\n if (status === 404) throw new NotFoundError(message);\n if (status === 413) throw new PayloadTooLargeError(message);\n if (status === 429) throw new RateLimitError(message);\n throw new TownshipError(message, status);\n }\n\n // --- Search ---\n\n /**\n * Convert a PLSS legal land description to GPS coordinates.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns A SearchResult with coordinates, boundary, and metadata.\n * @throws {ValidationError} If the location string is invalid.\n * @throws {NotFoundError} If no match is found.\n */\n async search(legalLocation: string): Promise<SearchResult> {\n const params = new URLSearchParams({ location: legalLocation });\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/legal-location?${params}`\n );\n\n if (!(\"features\" in data) || !data.features?.length) {\n throw new NotFoundError(`No results found for \"${legalLocation}\"`);\n }\n\n return toSearchResult(data as GeoJSONFeatureCollection);\n }\n\n /**\n * Find the PLSS legal land description at the given GPS coordinates.\n *\n * @param longitude - Longitude (x) coordinate.\n * @param latitude - Latitude (y) coordinate.\n * @param options - Optional unit filter.\n * @returns A SearchResult or array of SearchResults (when unit is 'all').\n */\n async reverse(\n longitude: number,\n latitude: number,\n options?: ReverseOptions\n ): Promise<SearchResult | SearchResult[]> {\n const params = new URLSearchParams({\n location: `${longitude},${latitude}`\n });\n if (options?.unit) {\n params.set(\"unit\", options.unit);\n }\n\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/coordinates?${params}`\n );\n\n if (!(\"features\" in data) || !data.features?.length) {\n throw new NotFoundError(`No results found for coordinates [${longitude}, ${latitude}]`);\n }\n\n const fc = data as GeoJSONFeatureCollection;\n\n if (options?.unit === \"all\") {\n const groups = new Map<string, typeof fc.features>();\n for (const feature of fc.features) {\n const key = feature.properties.legal_location;\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(feature);\n }\n\n return Array.from(groups.values()).map((features) => {\n return toSearchResult({ type: \"FeatureCollection\", features });\n });\n }\n\n return toSearchResult(fc);\n }\n\n // --- Autocomplete ---\n\n /**\n * Get autocomplete suggestions for a partial PLSS description.\n *\n * @param query - Partial search query (minimum 2 characters).\n * @param options - Optional limit (1–10, default 3) and proximity.\n * @returns Raw GeoJSON FeatureCollection with suggestion features.\n */\n async autocomplete(\n query: string,\n options?: AutocompleteOptions\n ): Promise<GeoJSONFeatureCollection> {\n const params = new URLSearchParams({ location: query });\n if (options?.limit != null) {\n params.set(\"limit\", String(options.limit));\n }\n if (options?.proximity) {\n params.set(\"proximity\", `${options.proximity[0]},${options.proximity[1]}`);\n }\n\n return this.request<GeoJSONFeatureCollection>(`/autocomplete/legal-location?${params}`);\n }\n\n // --- Batch ---\n\n /**\n * Convert multiple PLSS descriptions to GPS coordinates in one request.\n * Auto-chunks if more than 100 items.\n *\n * @param locations - Array of PLSS legal land descriptions.\n * @param options - Optional chunk size.\n * @returns Array of SearchResult or null for each input.\n */\n async batchSearch(\n locations: string[],\n options?: BatchSearchOptions\n ): Promise<(SearchResult | null)[]> {\n const chunkSize = Math.min(options?.chunkSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const results: (SearchResult | null)[] = [];\n\n for (let i = 0; i < locations.length; i += chunkSize) {\n const chunk = locations.slice(i, i + chunkSize);\n const data = await this.request<(GeoJSONFeatureCollection | null)[]>(\n \"/batch/legal-location\",\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(chunk)\n }\n );\n\n for (const fc of data) {\n if (!fc || !fc.features?.length) {\n results.push(null);\n } else {\n results.push(toSearchResult(fc));\n }\n }\n }\n\n return results;\n }\n\n /**\n * Find PLSS descriptions for multiple coordinate pairs in one request.\n * Auto-chunks if more than 100 items.\n *\n * @param coordinates - Array of [longitude, latitude] pairs.\n * @param options - Optional unit filter and chunk size.\n * @returns Array of SearchResult or null for each input.\n */\n async batchReverse(\n coordinates: [number, number][],\n options?: BatchReverseOptions\n ): Promise<(SearchResult | null)[]> {\n const chunkSize = Math.min(options?.chunkSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const results: (SearchResult | null)[] = [];\n\n for (let i = 0; i < coordinates.length; i += chunkSize) {\n const chunk = coordinates.slice(i, i + chunkSize);\n const body: Record<string, unknown> = { coordinates: chunk };\n if (options?.unit) {\n body.unit = options.unit;\n }\n\n const data = await this.request<\n (GeoJSONFeatureCollection | null)[] | GeoJSONFeatureCollection\n >(\"/batch/coordinates\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body)\n });\n\n if (Array.isArray(data)) {\n for (const fc of data) {\n if (!fc || !fc.features?.length) {\n results.push(null);\n } else {\n results.push(toSearchResult(fc));\n }\n }\n } else if (data && \"features\" in data) {\n // unit=all returns a single FeatureCollection — split by legal_location\n const groups = new Map<string, typeof data.features>();\n for (const feature of data.features) {\n const key = JSON.stringify(feature.properties.search_term);\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(feature);\n }\n for (const features of groups.values()) {\n results.push(toSearchResult({ type: \"FeatureCollection\", features }));\n }\n }\n }\n\n return results;\n }\n\n // --- Convenience ---\n\n /**\n * Get the boundary polygon for a legal land description.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns The boundary GeoJSON Polygon, or null if not found.\n */\n async boundary(legalLocation: string): Promise<GeoJSONPolygon | null> {\n const result = await this.search(legalLocation);\n return result.boundary;\n }\n\n /**\n * Get the raw GeoJSON FeatureCollection for a legal land description.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns The raw GeoJSON FeatureCollection from the API.\n */\n async raw(legalLocation: string): Promise<GeoJSONFeatureCollection> {\n const params = new URLSearchParams({ location: legalLocation });\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/legal-location?${params}`\n );\n\n if (!(\"features\" in data)) {\n return { type: \"FeatureCollection\", features: [] };\n }\n\n return data as GeoJSONFeatureCollection;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export { TownshipClient } from \"./client.js\";\nexport {\n TownshipError,\n AuthenticationError,\n NotFoundError,\n RateLimitError,\n ValidationError,\n PayloadTooLargeError\n} from \"./errors.js\";\nexport type {\n TownshipClientOptions,\n GeoJSONPoint,\n GeoJSONPolygon,\n GeoJSONMultiPolygon,\n GeoJSONBoundary,\n GeoJSONFeature,\n GeoJSONFeatureCollection,\n FeatureProperties,\n Unit,\n SurveySystem,\n SearchResult,\n ReverseOptions,\n AutocompleteOptions,\n BatchSearchOptions,\n BatchReverseOptions\n} from \"./types.js\";\n","/**\n * Base error class for all Township SDK errors.\n */\nexport class TownshipError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number | null = null\n ) {\n super(message);\n this.name = \"TownshipError\";\n }\n}\n\n/**\n * Thrown when the API key is missing or invalid (HTTP 401).\n */\nexport class AuthenticationError extends TownshipError {\n constructor(message = \"Invalid or missing API key\") {\n super(message, 401);\n this.name = \"AuthenticationError\";\n }\n}\n\n/**\n * Thrown when no result is found for the given input.\n */\nexport class NotFoundError extends TownshipError {\n constructor(message = \"Location not found\") {\n super(message, 404);\n this.name = \"NotFoundError\";\n }\n}\n\n/**\n * Thrown when the API rate limit is exceeded (HTTP 429).\n */\nexport class RateLimitError extends TownshipError {\n constructor(message = \"Rate limit exceeded. Please slow down your requests.\") {\n super(message, 429);\n this.name = \"RateLimitError\";\n }\n}\n\n/**\n * Thrown when the request is malformed (HTTP 400).\n */\nexport class ValidationError extends TownshipError {\n constructor(message = \"Invalid request\") {\n super(message, 400);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Thrown when the batch payload exceeds the maximum size (HTTP 413).\n */\nexport class PayloadTooLargeError extends TownshipError {\n constructor(message = \"Batch payload exceeds the maximum of 100 records per request\") {\n super(message, 413);\n this.name = \"PayloadTooLargeError\";\n }\n}\n","import {\n AuthenticationError,\n NotFoundError,\n PayloadTooLargeError,\n RateLimitError,\n TownshipError,\n ValidationError\n} from \"./errors.js\";\nimport type {\n AutocompleteOptions,\n BatchReverseOptions,\n BatchSearchOptions,\n GeoJSONBoundary,\n GeoJSONFeatureCollection,\n ReverseOptions,\n SearchResult,\n TownshipClientOptions\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://developer.townshipamerica.com\";\nconst DEFAULT_TIMEOUT = 30_000;\nconst MAX_BATCH_SIZE = 100;\n\nfunction toSearchResult(fc: GeoJSONFeatureCollection): SearchResult {\n const centroid = fc.features.find((f) => f.properties.shape === \"centroid\");\n const grid = fc.features.find((f) => f.properties.shape === \"grid\");\n\n const props = centroid?.properties ?? grid?.properties;\n if (!props) {\n throw new TownshipError(\"Unexpected API response: no features returned\");\n }\n\n const [lng, lat] = centroid ? (centroid.geometry.coordinates as [number, number]) : [0, 0];\n\n return {\n legalLocation: props.legal_location,\n latitude: lat,\n longitude: lng,\n state: props.state,\n county: props.county,\n unit: props.unit,\n surveySystem: props.survey_system,\n alternateLegalLocation: props.alternate_legal_location,\n boundary: grid ? (grid.geometry as GeoJSONBoundary) : null,\n raw: fc\n };\n}\n\nexport class TownshipClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n\n constructor(options: TownshipClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT;\n\n if (!this.apiKey) {\n throw new TownshipError(\"apiKey is required\");\n }\n }\n\n // --- Internal ---\n\n private async request<T>(path: string, init?: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n ...init,\n headers: {\n \"X-API-Key\": this.apiKey,\n \"User-Agent\": \"townshipamerica-js/1.0.0\",\n ...(init?.headers ?? {})\n },\n signal: controller.signal\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as T;\n } catch (error) {\n if (error instanceof TownshipError) throw error;\n if (error instanceof DOMException && error.name === \"AbortError\") {\n throw new TownshipError(\"Request timed out\");\n }\n throw new TownshipError(error instanceof Error ? error.message : \"Unknown error\");\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async handleError(response: Response): Promise<never> {\n let message: string;\n try {\n const body = (await response.json()) as Record<string, unknown>;\n message = (body.error ?? body.message ?? response.statusText) as string;\n } catch {\n message = response.statusText;\n }\n\n const status = response.status;\n if (status === 400) throw new ValidationError(message);\n if (status === 401) throw new AuthenticationError(message);\n if (status === 404) throw new NotFoundError(message);\n if (status === 413) throw new PayloadTooLargeError(message);\n if (status === 429) throw new RateLimitError(message);\n throw new TownshipError(message, status);\n }\n\n // --- Search ---\n\n /**\n * Convert a PLSS or Texas TXSS legal land description to GPS coordinates.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\" or \"A-175 Reeves County\"\n * @returns A SearchResult with coordinates, boundary, and metadata.\n * @throws {ValidationError} If the location string is invalid.\n * @throws {NotFoundError} If no match is found.\n */\n async search(legalLocation: string): Promise<SearchResult> {\n const params = new URLSearchParams({ location: legalLocation });\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/legal-location?${params}`\n );\n\n if (!(\"features\" in data) || !data.features?.length) {\n throw new NotFoundError(`No results found for \"${legalLocation}\"`);\n }\n\n return toSearchResult(data as GeoJSONFeatureCollection);\n }\n\n /**\n * Find the legal land description at the given GPS coordinates (PLSS or Texas TXSS).\n *\n * @param longitude - Longitude (x) coordinate.\n * @param latitude - Latitude (y) coordinate.\n * @param options - Optional PLSS unit filter (ignored for TXSS results).\n * @returns A SearchResult or array of SearchResults (when unit is 'all').\n */\n async reverse(\n longitude: number,\n latitude: number,\n options?: ReverseOptions\n ): Promise<SearchResult | SearchResult[]> {\n const params = new URLSearchParams({\n location: `${longitude},${latitude}`\n });\n if (options?.unit) {\n params.set(\"unit\", options.unit);\n }\n\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/coordinates?${params}`\n );\n\n if (!(\"features\" in data) || !data.features?.length) {\n throw new NotFoundError(`No results found for coordinates [${longitude}, ${latitude}]`);\n }\n\n const fc = data as GeoJSONFeatureCollection;\n\n if (options?.unit === \"all\") {\n const groups = new Map<string, typeof fc.features>();\n for (const feature of fc.features) {\n const key = feature.properties.legal_location;\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(feature);\n }\n\n return Array.from(groups.values()).map((features) => {\n return toSearchResult({ type: \"FeatureCollection\", features });\n });\n }\n\n return toSearchResult(fc);\n }\n\n // --- Autocomplete ---\n\n /**\n * Get autocomplete suggestions for a partial PLSS or Texas TXSS description.\n *\n * @param query - Partial search query (minimum 2 characters).\n * @param options - Optional limit (1–10, default 3) and proximity.\n * @returns Raw GeoJSON FeatureCollection with suggestion features.\n */\n async autocomplete(\n query: string,\n options?: AutocompleteOptions\n ): Promise<GeoJSONFeatureCollection> {\n const params = new URLSearchParams({ location: query });\n if (options?.limit != null) {\n params.set(\"limit\", String(options.limit));\n }\n if (options?.proximity) {\n params.set(\"proximity\", `${options.proximity[0]},${options.proximity[1]}`);\n }\n\n return this.request<GeoJSONFeatureCollection>(`/autocomplete/legal-location?${params}`);\n }\n\n // --- Batch ---\n\n /**\n * Convert multiple legal land descriptions to GPS coordinates in one request.\n * Auto-chunks if more than 100 items. Mix PLSS and Texas TXSS inputs freely.\n *\n * @param locations - Array of legal land descriptions.\n * @param options - Optional chunk size.\n * @returns Array of SearchResult or null for each input.\n */\n async batchSearch(\n locations: string[],\n options?: BatchSearchOptions\n ): Promise<(SearchResult | null)[]> {\n const chunkSize = Math.min(options?.chunkSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const results: (SearchResult | null)[] = [];\n\n for (let i = 0; i < locations.length; i += chunkSize) {\n const chunk = locations.slice(i, i + chunkSize);\n const data = await this.request<(GeoJSONFeatureCollection | null)[]>(\n \"/batch/legal-location\",\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(chunk)\n }\n );\n\n for (const fc of data) {\n if (!fc || !fc.features?.length) {\n results.push(null);\n } else {\n results.push(toSearchResult(fc));\n }\n }\n }\n\n return results;\n }\n\n /**\n * Find legal land descriptions for multiple coordinate pairs in one request.\n * Auto-chunks if more than 100 items.\n *\n * @param coordinates - Array of [longitude, latitude] pairs.\n * @param options - Optional PLSS unit filter and chunk size.\n * @returns Array of SearchResult or null for each input.\n */\n async batchReverse(\n coordinates: [number, number][],\n options?: BatchReverseOptions\n ): Promise<(SearchResult | null)[]> {\n const chunkSize = Math.min(options?.chunkSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const results: (SearchResult | null)[] = [];\n\n for (let i = 0; i < coordinates.length; i += chunkSize) {\n const chunk = coordinates.slice(i, i + chunkSize);\n const body: Record<string, unknown> = { coordinates: chunk };\n if (options?.unit) {\n body.unit = options.unit;\n }\n\n const data = await this.request<\n (GeoJSONFeatureCollection | null)[] | GeoJSONFeatureCollection\n >(\"/batch/coordinates\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body)\n });\n\n if (Array.isArray(data)) {\n for (const fc of data) {\n if (!fc || !fc.features?.length) {\n results.push(null);\n } else {\n results.push(toSearchResult(fc));\n }\n }\n } else if (data && \"features\" in data) {\n // unit=all returns a single FeatureCollection — split by legal_location\n const groups = new Map<string, typeof data.features>();\n for (const feature of data.features) {\n const key = JSON.stringify(feature.properties.search_term);\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(feature);\n }\n for (const features of groups.values()) {\n results.push(toSearchResult({ type: \"FeatureCollection\", features }));\n }\n }\n }\n\n return results;\n }\n\n // --- Convenience ---\n\n /**\n * Get the boundary polygon for a legal land description.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns The boundary GeoJSON Polygon, or null if not found.\n */\n async boundary(legalLocation: string): Promise<GeoJSONBoundary | null> {\n const result = await this.search(legalLocation);\n return result.boundary;\n }\n\n /**\n * Get the raw GeoJSON FeatureCollection for a legal land description.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns The raw GeoJSON FeatureCollection from the API.\n */\n async raw(legalLocation: string): Promise<GeoJSONFeatureCollection> {\n const params = new URLSearchParams({ location: legalLocation });\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/legal-location?${params}`\n );\n\n if (!(\"features\" in data)) {\n return { type: \"FeatureCollection\", features: [] };\n }\n\n return data as GeoJSONFeatureCollection;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -14,18 +14,32 @@ interface GeoJSONPolygon {
14
14
  type: "Polygon";
15
15
  coordinates: number[][][];
16
16
  }
17
+ interface GeoJSONMultiPolygon {
18
+ type: "MultiPolygon";
19
+ coordinates: number[][][][];
20
+ }
21
+ type GeoJSONBoundary = GeoJSONPolygon | GeoJSONMultiPolygon;
17
22
  type Unit = "Township" | "First Division" | "Second Division";
23
+ type SurveySystem = "PLSS" | "TXSS";
18
24
  interface FeatureProperties {
19
25
  shape: "grid" | "centroid";
20
26
  search_term: string | number[];
21
27
  legal_location: string;
22
28
  alternate_legal_location?: string;
23
- unit?: Unit;
24
- survey_system?: string;
29
+ unit?: Unit | null;
30
+ survey_system?: SurveySystem | string;
25
31
  county?: string;
26
32
  state?: string;
27
- }
28
- interface GeoJSONFeature<G = GeoJSONPoint | GeoJSONPolygon> {
33
+ /** Texas abstract number (TXSS only). */
34
+ abstract_no?: string;
35
+ /** Texas block number (TXSS only). */
36
+ block_no?: string;
37
+ /** Texas survey name (TXSS only). */
38
+ survey_name?: string;
39
+ /** Reported acreage when available (TXSS only). */
40
+ acreage?: number;
41
+ }
42
+ interface GeoJSONFeature<G = GeoJSONPoint | GeoJSONBoundary> {
29
43
  type: "Feature";
30
44
  geometry: G;
31
45
  properties: FeatureProperties;
@@ -45,14 +59,14 @@ interface SearchResult {
45
59
  state: string | undefined;
46
60
  /** County where the land unit is located. */
47
61
  county: string | undefined;
48
- /** The land unit type (Township, First Division, Second Division). */
49
- unit: string | undefined;
50
- /** The survey system (PLSS). */
51
- surveySystem: string | undefined;
62
+ /** The land unit type (Township, First Division, Second Division). Null for TXSS. */
63
+ unit: string | null | undefined;
64
+ /** The survey system: PLSS or TXSS (Texas). */
65
+ surveySystem: SurveySystem | string | undefined;
52
66
  /** Alternate legal land description if available. */
53
67
  alternateLegalLocation: string | undefined;
54
68
  /** Grid boundary polygon, or null if no boundary returned. */
55
- boundary: GeoJSONPolygon | null;
69
+ boundary: GeoJSONBoundary | null;
56
70
  /** The raw GeoJSON FeatureCollection from the API. */
57
71
  raw: GeoJSONFeatureCollection;
58
72
  }
@@ -85,25 +99,25 @@ declare class TownshipClient {
85
99
  private request;
86
100
  private handleError;
87
101
  /**
88
- * Convert a PLSS legal land description to GPS coordinates.
102
+ * Convert a PLSS or Texas TXSS legal land description to GPS coordinates.
89
103
  *
90
- * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian"
104
+ * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian" or "A-175 Reeves County"
91
105
  * @returns A SearchResult with coordinates, boundary, and metadata.
92
106
  * @throws {ValidationError} If the location string is invalid.
93
107
  * @throws {NotFoundError} If no match is found.
94
108
  */
95
109
  search(legalLocation: string): Promise<SearchResult>;
96
110
  /**
97
- * Find the PLSS legal land description at the given GPS coordinates.
111
+ * Find the legal land description at the given GPS coordinates (PLSS or Texas TXSS).
98
112
  *
99
113
  * @param longitude - Longitude (x) coordinate.
100
114
  * @param latitude - Latitude (y) coordinate.
101
- * @param options - Optional unit filter.
115
+ * @param options - Optional PLSS unit filter (ignored for TXSS results).
102
116
  * @returns A SearchResult or array of SearchResults (when unit is 'all').
103
117
  */
104
118
  reverse(longitude: number, latitude: number, options?: ReverseOptions): Promise<SearchResult | SearchResult[]>;
105
119
  /**
106
- * Get autocomplete suggestions for a partial PLSS description.
120
+ * Get autocomplete suggestions for a partial PLSS or Texas TXSS description.
107
121
  *
108
122
  * @param query - Partial search query (minimum 2 characters).
109
123
  * @param options - Optional limit (1–10, default 3) and proximity.
@@ -111,20 +125,20 @@ declare class TownshipClient {
111
125
  */
112
126
  autocomplete(query: string, options?: AutocompleteOptions): Promise<GeoJSONFeatureCollection>;
113
127
  /**
114
- * Convert multiple PLSS descriptions to GPS coordinates in one request.
115
- * Auto-chunks if more than 100 items.
128
+ * Convert multiple legal land descriptions to GPS coordinates in one request.
129
+ * Auto-chunks if more than 100 items. Mix PLSS and Texas TXSS inputs freely.
116
130
  *
117
- * @param locations - Array of PLSS legal land descriptions.
131
+ * @param locations - Array of legal land descriptions.
118
132
  * @param options - Optional chunk size.
119
133
  * @returns Array of SearchResult or null for each input.
120
134
  */
121
135
  batchSearch(locations: string[], options?: BatchSearchOptions): Promise<(SearchResult | null)[]>;
122
136
  /**
123
- * Find PLSS descriptions for multiple coordinate pairs in one request.
137
+ * Find legal land descriptions for multiple coordinate pairs in one request.
124
138
  * Auto-chunks if more than 100 items.
125
139
  *
126
140
  * @param coordinates - Array of [longitude, latitude] pairs.
127
- * @param options - Optional unit filter and chunk size.
141
+ * @param options - Optional PLSS unit filter and chunk size.
128
142
  * @returns Array of SearchResult or null for each input.
129
143
  */
130
144
  batchReverse(coordinates: [number, number][], options?: BatchReverseOptions): Promise<(SearchResult | null)[]>;
@@ -134,7 +148,7 @@ declare class TownshipClient {
134
148
  * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian"
135
149
  * @returns The boundary GeoJSON Polygon, or null if not found.
136
150
  */
137
- boundary(legalLocation: string): Promise<GeoJSONPolygon | null>;
151
+ boundary(legalLocation: string): Promise<GeoJSONBoundary | null>;
138
152
  /**
139
153
  * Get the raw GeoJSON FeatureCollection for a legal land description.
140
154
  *
@@ -182,4 +196,4 @@ declare class PayloadTooLargeError extends TownshipError {
182
196
  constructor(message?: string);
183
197
  }
184
198
 
185
- export { AuthenticationError, type AutocompleteOptions, type BatchReverseOptions, type BatchSearchOptions, type FeatureProperties, type GeoJSONFeature, type GeoJSONFeatureCollection, type GeoJSONPoint, type GeoJSONPolygon, NotFoundError, PayloadTooLargeError, RateLimitError, type ReverseOptions, type SearchResult, TownshipClient, type TownshipClientOptions, TownshipError, type Unit, ValidationError };
199
+ export { AuthenticationError, type AutocompleteOptions, type BatchReverseOptions, type BatchSearchOptions, type FeatureProperties, type GeoJSONBoundary, type GeoJSONFeature, type GeoJSONFeatureCollection, type GeoJSONMultiPolygon, type GeoJSONPoint, type GeoJSONPolygon, NotFoundError, PayloadTooLargeError, RateLimitError, type ReverseOptions, type SearchResult, type SurveySystem, TownshipClient, type TownshipClientOptions, TownshipError, type Unit, ValidationError };
package/dist/index.d.ts CHANGED
@@ -14,18 +14,32 @@ interface GeoJSONPolygon {
14
14
  type: "Polygon";
15
15
  coordinates: number[][][];
16
16
  }
17
+ interface GeoJSONMultiPolygon {
18
+ type: "MultiPolygon";
19
+ coordinates: number[][][][];
20
+ }
21
+ type GeoJSONBoundary = GeoJSONPolygon | GeoJSONMultiPolygon;
17
22
  type Unit = "Township" | "First Division" | "Second Division";
23
+ type SurveySystem = "PLSS" | "TXSS";
18
24
  interface FeatureProperties {
19
25
  shape: "grid" | "centroid";
20
26
  search_term: string | number[];
21
27
  legal_location: string;
22
28
  alternate_legal_location?: string;
23
- unit?: Unit;
24
- survey_system?: string;
29
+ unit?: Unit | null;
30
+ survey_system?: SurveySystem | string;
25
31
  county?: string;
26
32
  state?: string;
27
- }
28
- interface GeoJSONFeature<G = GeoJSONPoint | GeoJSONPolygon> {
33
+ /** Texas abstract number (TXSS only). */
34
+ abstract_no?: string;
35
+ /** Texas block number (TXSS only). */
36
+ block_no?: string;
37
+ /** Texas survey name (TXSS only). */
38
+ survey_name?: string;
39
+ /** Reported acreage when available (TXSS only). */
40
+ acreage?: number;
41
+ }
42
+ interface GeoJSONFeature<G = GeoJSONPoint | GeoJSONBoundary> {
29
43
  type: "Feature";
30
44
  geometry: G;
31
45
  properties: FeatureProperties;
@@ -45,14 +59,14 @@ interface SearchResult {
45
59
  state: string | undefined;
46
60
  /** County where the land unit is located. */
47
61
  county: string | undefined;
48
- /** The land unit type (Township, First Division, Second Division). */
49
- unit: string | undefined;
50
- /** The survey system (PLSS). */
51
- surveySystem: string | undefined;
62
+ /** The land unit type (Township, First Division, Second Division). Null for TXSS. */
63
+ unit: string | null | undefined;
64
+ /** The survey system: PLSS or TXSS (Texas). */
65
+ surveySystem: SurveySystem | string | undefined;
52
66
  /** Alternate legal land description if available. */
53
67
  alternateLegalLocation: string | undefined;
54
68
  /** Grid boundary polygon, or null if no boundary returned. */
55
- boundary: GeoJSONPolygon | null;
69
+ boundary: GeoJSONBoundary | null;
56
70
  /** The raw GeoJSON FeatureCollection from the API. */
57
71
  raw: GeoJSONFeatureCollection;
58
72
  }
@@ -85,25 +99,25 @@ declare class TownshipClient {
85
99
  private request;
86
100
  private handleError;
87
101
  /**
88
- * Convert a PLSS legal land description to GPS coordinates.
102
+ * Convert a PLSS or Texas TXSS legal land description to GPS coordinates.
89
103
  *
90
- * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian"
104
+ * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian" or "A-175 Reeves County"
91
105
  * @returns A SearchResult with coordinates, boundary, and metadata.
92
106
  * @throws {ValidationError} If the location string is invalid.
93
107
  * @throws {NotFoundError} If no match is found.
94
108
  */
95
109
  search(legalLocation: string): Promise<SearchResult>;
96
110
  /**
97
- * Find the PLSS legal land description at the given GPS coordinates.
111
+ * Find the legal land description at the given GPS coordinates (PLSS or Texas TXSS).
98
112
  *
99
113
  * @param longitude - Longitude (x) coordinate.
100
114
  * @param latitude - Latitude (y) coordinate.
101
- * @param options - Optional unit filter.
115
+ * @param options - Optional PLSS unit filter (ignored for TXSS results).
102
116
  * @returns A SearchResult or array of SearchResults (when unit is 'all').
103
117
  */
104
118
  reverse(longitude: number, latitude: number, options?: ReverseOptions): Promise<SearchResult | SearchResult[]>;
105
119
  /**
106
- * Get autocomplete suggestions for a partial PLSS description.
120
+ * Get autocomplete suggestions for a partial PLSS or Texas TXSS description.
107
121
  *
108
122
  * @param query - Partial search query (minimum 2 characters).
109
123
  * @param options - Optional limit (1–10, default 3) and proximity.
@@ -111,20 +125,20 @@ declare class TownshipClient {
111
125
  */
112
126
  autocomplete(query: string, options?: AutocompleteOptions): Promise<GeoJSONFeatureCollection>;
113
127
  /**
114
- * Convert multiple PLSS descriptions to GPS coordinates in one request.
115
- * Auto-chunks if more than 100 items.
128
+ * Convert multiple legal land descriptions to GPS coordinates in one request.
129
+ * Auto-chunks if more than 100 items. Mix PLSS and Texas TXSS inputs freely.
116
130
  *
117
- * @param locations - Array of PLSS legal land descriptions.
131
+ * @param locations - Array of legal land descriptions.
118
132
  * @param options - Optional chunk size.
119
133
  * @returns Array of SearchResult or null for each input.
120
134
  */
121
135
  batchSearch(locations: string[], options?: BatchSearchOptions): Promise<(SearchResult | null)[]>;
122
136
  /**
123
- * Find PLSS descriptions for multiple coordinate pairs in one request.
137
+ * Find legal land descriptions for multiple coordinate pairs in one request.
124
138
  * Auto-chunks if more than 100 items.
125
139
  *
126
140
  * @param coordinates - Array of [longitude, latitude] pairs.
127
- * @param options - Optional unit filter and chunk size.
141
+ * @param options - Optional PLSS unit filter and chunk size.
128
142
  * @returns Array of SearchResult or null for each input.
129
143
  */
130
144
  batchReverse(coordinates: [number, number][], options?: BatchReverseOptions): Promise<(SearchResult | null)[]>;
@@ -134,7 +148,7 @@ declare class TownshipClient {
134
148
  * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian"
135
149
  * @returns The boundary GeoJSON Polygon, or null if not found.
136
150
  */
137
- boundary(legalLocation: string): Promise<GeoJSONPolygon | null>;
151
+ boundary(legalLocation: string): Promise<GeoJSONBoundary | null>;
138
152
  /**
139
153
  * Get the raw GeoJSON FeatureCollection for a legal land description.
140
154
  *
@@ -182,4 +196,4 @@ declare class PayloadTooLargeError extends TownshipError {
182
196
  constructor(message?: string);
183
197
  }
184
198
 
185
- export { AuthenticationError, type AutocompleteOptions, type BatchReverseOptions, type BatchSearchOptions, type FeatureProperties, type GeoJSONFeature, type GeoJSONFeatureCollection, type GeoJSONPoint, type GeoJSONPolygon, NotFoundError, PayloadTooLargeError, RateLimitError, type ReverseOptions, type SearchResult, TownshipClient, type TownshipClientOptions, TownshipError, type Unit, ValidationError };
199
+ export { AuthenticationError, type AutocompleteOptions, type BatchReverseOptions, type BatchSearchOptions, type FeatureProperties, type GeoJSONBoundary, type GeoJSONFeature, type GeoJSONFeatureCollection, type GeoJSONMultiPolygon, type GeoJSONPoint, type GeoJSONPolygon, NotFoundError, PayloadTooLargeError, RateLimitError, type ReverseOptions, type SearchResult, type SurveySystem, TownshipClient, type TownshipClientOptions, TownshipError, type Unit, ValidationError };
package/dist/index.js CHANGED
@@ -121,9 +121,9 @@ var TownshipClient = class {
121
121
  }
122
122
  // --- Search ---
123
123
  /**
124
- * Convert a PLSS legal land description to GPS coordinates.
124
+ * Convert a PLSS or Texas TXSS legal land description to GPS coordinates.
125
125
  *
126
- * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian"
126
+ * @param legalLocation - e.g. "NW 25 24N 1E 6th Meridian" or "A-175 Reeves County"
127
127
  * @returns A SearchResult with coordinates, boundary, and metadata.
128
128
  * @throws {ValidationError} If the location string is invalid.
129
129
  * @throws {NotFoundError} If no match is found.
@@ -139,11 +139,11 @@ var TownshipClient = class {
139
139
  return toSearchResult(data);
140
140
  }
141
141
  /**
142
- * Find the PLSS legal land description at the given GPS coordinates.
142
+ * Find the legal land description at the given GPS coordinates (PLSS or Texas TXSS).
143
143
  *
144
144
  * @param longitude - Longitude (x) coordinate.
145
145
  * @param latitude - Latitude (y) coordinate.
146
- * @param options - Optional unit filter.
146
+ * @param options - Optional PLSS unit filter (ignored for TXSS results).
147
147
  * @returns A SearchResult or array of SearchResults (when unit is 'all').
148
148
  */
149
149
  async reverse(longitude, latitude, options) {
@@ -175,7 +175,7 @@ var TownshipClient = class {
175
175
  }
176
176
  // --- Autocomplete ---
177
177
  /**
178
- * Get autocomplete suggestions for a partial PLSS description.
178
+ * Get autocomplete suggestions for a partial PLSS or Texas TXSS description.
179
179
  *
180
180
  * @param query - Partial search query (minimum 2 characters).
181
181
  * @param options - Optional limit (1–10, default 3) and proximity.
@@ -193,10 +193,10 @@ var TownshipClient = class {
193
193
  }
194
194
  // --- Batch ---
195
195
  /**
196
- * Convert multiple PLSS descriptions to GPS coordinates in one request.
197
- * Auto-chunks if more than 100 items.
196
+ * Convert multiple legal land descriptions to GPS coordinates in one request.
197
+ * Auto-chunks if more than 100 items. Mix PLSS and Texas TXSS inputs freely.
198
198
  *
199
- * @param locations - Array of PLSS legal land descriptions.
199
+ * @param locations - Array of legal land descriptions.
200
200
  * @param options - Optional chunk size.
201
201
  * @returns Array of SearchResult or null for each input.
202
202
  */
@@ -224,11 +224,11 @@ var TownshipClient = class {
224
224
  return results;
225
225
  }
226
226
  /**
227
- * Find PLSS descriptions for multiple coordinate pairs in one request.
227
+ * Find legal land descriptions for multiple coordinate pairs in one request.
228
228
  * Auto-chunks if more than 100 items.
229
229
  *
230
230
  * @param coordinates - Array of [longitude, latitude] pairs.
231
- * @param options - Optional unit filter and chunk size.
231
+ * @param options - Optional PLSS unit filter and chunk size.
232
232
  * @returns Array of SearchResult or null for each input.
233
233
  */
234
234
  async batchReverse(coordinates, options) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["/**\n * Base error class for all Township SDK errors.\n */\nexport class TownshipError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number | null = null\n ) {\n super(message);\n this.name = \"TownshipError\";\n }\n}\n\n/**\n * Thrown when the API key is missing or invalid (HTTP 401).\n */\nexport class AuthenticationError extends TownshipError {\n constructor(message = \"Invalid or missing API key\") {\n super(message, 401);\n this.name = \"AuthenticationError\";\n }\n}\n\n/**\n * Thrown when no result is found for the given input.\n */\nexport class NotFoundError extends TownshipError {\n constructor(message = \"Location not found\") {\n super(message, 404);\n this.name = \"NotFoundError\";\n }\n}\n\n/**\n * Thrown when the API rate limit is exceeded (HTTP 429).\n */\nexport class RateLimitError extends TownshipError {\n constructor(message = \"Rate limit exceeded. Please slow down your requests.\") {\n super(message, 429);\n this.name = \"RateLimitError\";\n }\n}\n\n/**\n * Thrown when the request is malformed (HTTP 400).\n */\nexport class ValidationError extends TownshipError {\n constructor(message = \"Invalid request\") {\n super(message, 400);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Thrown when the batch payload exceeds the maximum size (HTTP 413).\n */\nexport class PayloadTooLargeError extends TownshipError {\n constructor(message = \"Batch payload exceeds the maximum of 100 records per request\") {\n super(message, 413);\n this.name = \"PayloadTooLargeError\";\n }\n}\n","import {\n AuthenticationError,\n NotFoundError,\n PayloadTooLargeError,\n RateLimitError,\n TownshipError,\n ValidationError\n} from \"./errors.js\";\nimport type {\n AutocompleteOptions,\n BatchReverseOptions,\n BatchSearchOptions,\n GeoJSONFeatureCollection,\n GeoJSONPolygon,\n ReverseOptions,\n SearchResult,\n TownshipClientOptions\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://developer.townshipamerica.com\";\nconst DEFAULT_TIMEOUT = 30_000;\nconst MAX_BATCH_SIZE = 100;\n\nfunction toSearchResult(fc: GeoJSONFeatureCollection): SearchResult {\n const centroid = fc.features.find((f) => f.properties.shape === \"centroid\");\n const grid = fc.features.find((f) => f.properties.shape === \"grid\");\n\n const props = centroid?.properties ?? grid?.properties;\n if (!props) {\n throw new TownshipError(\"Unexpected API response: no features returned\");\n }\n\n const [lng, lat] = centroid ? (centroid.geometry.coordinates as [number, number]) : [0, 0];\n\n return {\n legalLocation: props.legal_location,\n latitude: lat,\n longitude: lng,\n state: props.state,\n county: props.county,\n unit: props.unit,\n surveySystem: props.survey_system,\n alternateLegalLocation: props.alternate_legal_location,\n boundary: grid ? (grid.geometry as GeoJSONPolygon) : null,\n raw: fc\n };\n}\n\nexport class TownshipClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n\n constructor(options: TownshipClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT;\n\n if (!this.apiKey) {\n throw new TownshipError(\"apiKey is required\");\n }\n }\n\n // --- Internal ---\n\n private async request<T>(path: string, init?: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n ...init,\n headers: {\n \"X-API-Key\": this.apiKey,\n \"User-Agent\": \"townshipamerica-js/1.0.0\",\n ...(init?.headers ?? {})\n },\n signal: controller.signal\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as T;\n } catch (error) {\n if (error instanceof TownshipError) throw error;\n if (error instanceof DOMException && error.name === \"AbortError\") {\n throw new TownshipError(\"Request timed out\");\n }\n throw new TownshipError(error instanceof Error ? error.message : \"Unknown error\");\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async handleError(response: Response): Promise<never> {\n let message: string;\n try {\n const body = (await response.json()) as Record<string, unknown>;\n message = (body.error ?? body.message ?? response.statusText) as string;\n } catch {\n message = response.statusText;\n }\n\n const status = response.status;\n if (status === 400) throw new ValidationError(message);\n if (status === 401) throw new AuthenticationError(message);\n if (status === 404) throw new NotFoundError(message);\n if (status === 413) throw new PayloadTooLargeError(message);\n if (status === 429) throw new RateLimitError(message);\n throw new TownshipError(message, status);\n }\n\n // --- Search ---\n\n /**\n * Convert a PLSS legal land description to GPS coordinates.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns A SearchResult with coordinates, boundary, and metadata.\n * @throws {ValidationError} If the location string is invalid.\n * @throws {NotFoundError} If no match is found.\n */\n async search(legalLocation: string): Promise<SearchResult> {\n const params = new URLSearchParams({ location: legalLocation });\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/legal-location?${params}`\n );\n\n if (!(\"features\" in data) || !data.features?.length) {\n throw new NotFoundError(`No results found for \"${legalLocation}\"`);\n }\n\n return toSearchResult(data as GeoJSONFeatureCollection);\n }\n\n /**\n * Find the PLSS legal land description at the given GPS coordinates.\n *\n * @param longitude - Longitude (x) coordinate.\n * @param latitude - Latitude (y) coordinate.\n * @param options - Optional unit filter.\n * @returns A SearchResult or array of SearchResults (when unit is 'all').\n */\n async reverse(\n longitude: number,\n latitude: number,\n options?: ReverseOptions\n ): Promise<SearchResult | SearchResult[]> {\n const params = new URLSearchParams({\n location: `${longitude},${latitude}`\n });\n if (options?.unit) {\n params.set(\"unit\", options.unit);\n }\n\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/coordinates?${params}`\n );\n\n if (!(\"features\" in data) || !data.features?.length) {\n throw new NotFoundError(`No results found for coordinates [${longitude}, ${latitude}]`);\n }\n\n const fc = data as GeoJSONFeatureCollection;\n\n if (options?.unit === \"all\") {\n const groups = new Map<string, typeof fc.features>();\n for (const feature of fc.features) {\n const key = feature.properties.legal_location;\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(feature);\n }\n\n return Array.from(groups.values()).map((features) => {\n return toSearchResult({ type: \"FeatureCollection\", features });\n });\n }\n\n return toSearchResult(fc);\n }\n\n // --- Autocomplete ---\n\n /**\n * Get autocomplete suggestions for a partial PLSS description.\n *\n * @param query - Partial search query (minimum 2 characters).\n * @param options - Optional limit (1–10, default 3) and proximity.\n * @returns Raw GeoJSON FeatureCollection with suggestion features.\n */\n async autocomplete(\n query: string,\n options?: AutocompleteOptions\n ): Promise<GeoJSONFeatureCollection> {\n const params = new URLSearchParams({ location: query });\n if (options?.limit != null) {\n params.set(\"limit\", String(options.limit));\n }\n if (options?.proximity) {\n params.set(\"proximity\", `${options.proximity[0]},${options.proximity[1]}`);\n }\n\n return this.request<GeoJSONFeatureCollection>(`/autocomplete/legal-location?${params}`);\n }\n\n // --- Batch ---\n\n /**\n * Convert multiple PLSS descriptions to GPS coordinates in one request.\n * Auto-chunks if more than 100 items.\n *\n * @param locations - Array of PLSS legal land descriptions.\n * @param options - Optional chunk size.\n * @returns Array of SearchResult or null for each input.\n */\n async batchSearch(\n locations: string[],\n options?: BatchSearchOptions\n ): Promise<(SearchResult | null)[]> {\n const chunkSize = Math.min(options?.chunkSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const results: (SearchResult | null)[] = [];\n\n for (let i = 0; i < locations.length; i += chunkSize) {\n const chunk = locations.slice(i, i + chunkSize);\n const data = await this.request<(GeoJSONFeatureCollection | null)[]>(\n \"/batch/legal-location\",\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(chunk)\n }\n );\n\n for (const fc of data) {\n if (!fc || !fc.features?.length) {\n results.push(null);\n } else {\n results.push(toSearchResult(fc));\n }\n }\n }\n\n return results;\n }\n\n /**\n * Find PLSS descriptions for multiple coordinate pairs in one request.\n * Auto-chunks if more than 100 items.\n *\n * @param coordinates - Array of [longitude, latitude] pairs.\n * @param options - Optional unit filter and chunk size.\n * @returns Array of SearchResult or null for each input.\n */\n async batchReverse(\n coordinates: [number, number][],\n options?: BatchReverseOptions\n ): Promise<(SearchResult | null)[]> {\n const chunkSize = Math.min(options?.chunkSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const results: (SearchResult | null)[] = [];\n\n for (let i = 0; i < coordinates.length; i += chunkSize) {\n const chunk = coordinates.slice(i, i + chunkSize);\n const body: Record<string, unknown> = { coordinates: chunk };\n if (options?.unit) {\n body.unit = options.unit;\n }\n\n const data = await this.request<\n (GeoJSONFeatureCollection | null)[] | GeoJSONFeatureCollection\n >(\"/batch/coordinates\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body)\n });\n\n if (Array.isArray(data)) {\n for (const fc of data) {\n if (!fc || !fc.features?.length) {\n results.push(null);\n } else {\n results.push(toSearchResult(fc));\n }\n }\n } else if (data && \"features\" in data) {\n // unit=all returns a single FeatureCollection — split by legal_location\n const groups = new Map<string, typeof data.features>();\n for (const feature of data.features) {\n const key = JSON.stringify(feature.properties.search_term);\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(feature);\n }\n for (const features of groups.values()) {\n results.push(toSearchResult({ type: \"FeatureCollection\", features }));\n }\n }\n }\n\n return results;\n }\n\n // --- Convenience ---\n\n /**\n * Get the boundary polygon for a legal land description.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns The boundary GeoJSON Polygon, or null if not found.\n */\n async boundary(legalLocation: string): Promise<GeoJSONPolygon | null> {\n const result = await this.search(legalLocation);\n return result.boundary;\n }\n\n /**\n * Get the raw GeoJSON FeatureCollection for a legal land description.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns The raw GeoJSON FeatureCollection from the API.\n */\n async raw(legalLocation: string): Promise<GeoJSONFeatureCollection> {\n const params = new URLSearchParams({ location: legalLocation });\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/legal-location?${params}`\n );\n\n if (!(\"features\" in data)) {\n return { type: \"FeatureCollection\", features: [] };\n }\n\n return data as GeoJSONFeatureCollection;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["/**\n * Base error class for all Township SDK errors.\n */\nexport class TownshipError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number | null = null\n ) {\n super(message);\n this.name = \"TownshipError\";\n }\n}\n\n/**\n * Thrown when the API key is missing or invalid (HTTP 401).\n */\nexport class AuthenticationError extends TownshipError {\n constructor(message = \"Invalid or missing API key\") {\n super(message, 401);\n this.name = \"AuthenticationError\";\n }\n}\n\n/**\n * Thrown when no result is found for the given input.\n */\nexport class NotFoundError extends TownshipError {\n constructor(message = \"Location not found\") {\n super(message, 404);\n this.name = \"NotFoundError\";\n }\n}\n\n/**\n * Thrown when the API rate limit is exceeded (HTTP 429).\n */\nexport class RateLimitError extends TownshipError {\n constructor(message = \"Rate limit exceeded. Please slow down your requests.\") {\n super(message, 429);\n this.name = \"RateLimitError\";\n }\n}\n\n/**\n * Thrown when the request is malformed (HTTP 400).\n */\nexport class ValidationError extends TownshipError {\n constructor(message = \"Invalid request\") {\n super(message, 400);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Thrown when the batch payload exceeds the maximum size (HTTP 413).\n */\nexport class PayloadTooLargeError extends TownshipError {\n constructor(message = \"Batch payload exceeds the maximum of 100 records per request\") {\n super(message, 413);\n this.name = \"PayloadTooLargeError\";\n }\n}\n","import {\n AuthenticationError,\n NotFoundError,\n PayloadTooLargeError,\n RateLimitError,\n TownshipError,\n ValidationError\n} from \"./errors.js\";\nimport type {\n AutocompleteOptions,\n BatchReverseOptions,\n BatchSearchOptions,\n GeoJSONBoundary,\n GeoJSONFeatureCollection,\n ReverseOptions,\n SearchResult,\n TownshipClientOptions\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://developer.townshipamerica.com\";\nconst DEFAULT_TIMEOUT = 30_000;\nconst MAX_BATCH_SIZE = 100;\n\nfunction toSearchResult(fc: GeoJSONFeatureCollection): SearchResult {\n const centroid = fc.features.find((f) => f.properties.shape === \"centroid\");\n const grid = fc.features.find((f) => f.properties.shape === \"grid\");\n\n const props = centroid?.properties ?? grid?.properties;\n if (!props) {\n throw new TownshipError(\"Unexpected API response: no features returned\");\n }\n\n const [lng, lat] = centroid ? (centroid.geometry.coordinates as [number, number]) : [0, 0];\n\n return {\n legalLocation: props.legal_location,\n latitude: lat,\n longitude: lng,\n state: props.state,\n county: props.county,\n unit: props.unit,\n surveySystem: props.survey_system,\n alternateLegalLocation: props.alternate_legal_location,\n boundary: grid ? (grid.geometry as GeoJSONBoundary) : null,\n raw: fc\n };\n}\n\nexport class TownshipClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n\n constructor(options: TownshipClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT;\n\n if (!this.apiKey) {\n throw new TownshipError(\"apiKey is required\");\n }\n }\n\n // --- Internal ---\n\n private async request<T>(path: string, init?: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n ...init,\n headers: {\n \"X-API-Key\": this.apiKey,\n \"User-Agent\": \"townshipamerica-js/1.0.0\",\n ...(init?.headers ?? {})\n },\n signal: controller.signal\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as T;\n } catch (error) {\n if (error instanceof TownshipError) throw error;\n if (error instanceof DOMException && error.name === \"AbortError\") {\n throw new TownshipError(\"Request timed out\");\n }\n throw new TownshipError(error instanceof Error ? error.message : \"Unknown error\");\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async handleError(response: Response): Promise<never> {\n let message: string;\n try {\n const body = (await response.json()) as Record<string, unknown>;\n message = (body.error ?? body.message ?? response.statusText) as string;\n } catch {\n message = response.statusText;\n }\n\n const status = response.status;\n if (status === 400) throw new ValidationError(message);\n if (status === 401) throw new AuthenticationError(message);\n if (status === 404) throw new NotFoundError(message);\n if (status === 413) throw new PayloadTooLargeError(message);\n if (status === 429) throw new RateLimitError(message);\n throw new TownshipError(message, status);\n }\n\n // --- Search ---\n\n /**\n * Convert a PLSS or Texas TXSS legal land description to GPS coordinates.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\" or \"A-175 Reeves County\"\n * @returns A SearchResult with coordinates, boundary, and metadata.\n * @throws {ValidationError} If the location string is invalid.\n * @throws {NotFoundError} If no match is found.\n */\n async search(legalLocation: string): Promise<SearchResult> {\n const params = new URLSearchParams({ location: legalLocation });\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/legal-location?${params}`\n );\n\n if (!(\"features\" in data) || !data.features?.length) {\n throw new NotFoundError(`No results found for \"${legalLocation}\"`);\n }\n\n return toSearchResult(data as GeoJSONFeatureCollection);\n }\n\n /**\n * Find the legal land description at the given GPS coordinates (PLSS or Texas TXSS).\n *\n * @param longitude - Longitude (x) coordinate.\n * @param latitude - Latitude (y) coordinate.\n * @param options - Optional PLSS unit filter (ignored for TXSS results).\n * @returns A SearchResult or array of SearchResults (when unit is 'all').\n */\n async reverse(\n longitude: number,\n latitude: number,\n options?: ReverseOptions\n ): Promise<SearchResult | SearchResult[]> {\n const params = new URLSearchParams({\n location: `${longitude},${latitude}`\n });\n if (options?.unit) {\n params.set(\"unit\", options.unit);\n }\n\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/coordinates?${params}`\n );\n\n if (!(\"features\" in data) || !data.features?.length) {\n throw new NotFoundError(`No results found for coordinates [${longitude}, ${latitude}]`);\n }\n\n const fc = data as GeoJSONFeatureCollection;\n\n if (options?.unit === \"all\") {\n const groups = new Map<string, typeof fc.features>();\n for (const feature of fc.features) {\n const key = feature.properties.legal_location;\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(feature);\n }\n\n return Array.from(groups.values()).map((features) => {\n return toSearchResult({ type: \"FeatureCollection\", features });\n });\n }\n\n return toSearchResult(fc);\n }\n\n // --- Autocomplete ---\n\n /**\n * Get autocomplete suggestions for a partial PLSS or Texas TXSS description.\n *\n * @param query - Partial search query (minimum 2 characters).\n * @param options - Optional limit (1–10, default 3) and proximity.\n * @returns Raw GeoJSON FeatureCollection with suggestion features.\n */\n async autocomplete(\n query: string,\n options?: AutocompleteOptions\n ): Promise<GeoJSONFeatureCollection> {\n const params = new URLSearchParams({ location: query });\n if (options?.limit != null) {\n params.set(\"limit\", String(options.limit));\n }\n if (options?.proximity) {\n params.set(\"proximity\", `${options.proximity[0]},${options.proximity[1]}`);\n }\n\n return this.request<GeoJSONFeatureCollection>(`/autocomplete/legal-location?${params}`);\n }\n\n // --- Batch ---\n\n /**\n * Convert multiple legal land descriptions to GPS coordinates in one request.\n * Auto-chunks if more than 100 items. Mix PLSS and Texas TXSS inputs freely.\n *\n * @param locations - Array of legal land descriptions.\n * @param options - Optional chunk size.\n * @returns Array of SearchResult or null for each input.\n */\n async batchSearch(\n locations: string[],\n options?: BatchSearchOptions\n ): Promise<(SearchResult | null)[]> {\n const chunkSize = Math.min(options?.chunkSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const results: (SearchResult | null)[] = [];\n\n for (let i = 0; i < locations.length; i += chunkSize) {\n const chunk = locations.slice(i, i + chunkSize);\n const data = await this.request<(GeoJSONFeatureCollection | null)[]>(\n \"/batch/legal-location\",\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(chunk)\n }\n );\n\n for (const fc of data) {\n if (!fc || !fc.features?.length) {\n results.push(null);\n } else {\n results.push(toSearchResult(fc));\n }\n }\n }\n\n return results;\n }\n\n /**\n * Find legal land descriptions for multiple coordinate pairs in one request.\n * Auto-chunks if more than 100 items.\n *\n * @param coordinates - Array of [longitude, latitude] pairs.\n * @param options - Optional PLSS unit filter and chunk size.\n * @returns Array of SearchResult or null for each input.\n */\n async batchReverse(\n coordinates: [number, number][],\n options?: BatchReverseOptions\n ): Promise<(SearchResult | null)[]> {\n const chunkSize = Math.min(options?.chunkSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const results: (SearchResult | null)[] = [];\n\n for (let i = 0; i < coordinates.length; i += chunkSize) {\n const chunk = coordinates.slice(i, i + chunkSize);\n const body: Record<string, unknown> = { coordinates: chunk };\n if (options?.unit) {\n body.unit = options.unit;\n }\n\n const data = await this.request<\n (GeoJSONFeatureCollection | null)[] | GeoJSONFeatureCollection\n >(\"/batch/coordinates\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body)\n });\n\n if (Array.isArray(data)) {\n for (const fc of data) {\n if (!fc || !fc.features?.length) {\n results.push(null);\n } else {\n results.push(toSearchResult(fc));\n }\n }\n } else if (data && \"features\" in data) {\n // unit=all returns a single FeatureCollection — split by legal_location\n const groups = new Map<string, typeof data.features>();\n for (const feature of data.features) {\n const key = JSON.stringify(feature.properties.search_term);\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(feature);\n }\n for (const features of groups.values()) {\n results.push(toSearchResult({ type: \"FeatureCollection\", features }));\n }\n }\n }\n\n return results;\n }\n\n // --- Convenience ---\n\n /**\n * Get the boundary polygon for a legal land description.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns The boundary GeoJSON Polygon, or null if not found.\n */\n async boundary(legalLocation: string): Promise<GeoJSONBoundary | null> {\n const result = await this.search(legalLocation);\n return result.boundary;\n }\n\n /**\n * Get the raw GeoJSON FeatureCollection for a legal land description.\n *\n * @param legalLocation - e.g. \"NW 25 24N 1E 6th Meridian\"\n * @returns The raw GeoJSON FeatureCollection from the API.\n */\n async raw(legalLocation: string): Promise<GeoJSONFeatureCollection> {\n const params = new URLSearchParams({ location: legalLocation });\n const data = await this.request<GeoJSONFeatureCollection | Record<string, never>>(\n `/search/legal-location?${params}`\n );\n\n if (!(\"features\" in data)) {\n return { type: \"FeatureCollection\", features: [] };\n }\n\n return data as GeoJSONFeatureCollection;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "townshipamerica",
3
- "version": "1.0.0",
4
- "description": "Official TypeScript SDK for the Township America API — convert PLSS legal land descriptions to GPS coordinates and back.",
3
+ "version": "1.0.2",
4
+ "description": "Official TypeScript SDK for the Township America API — convert PLSS and Texas TXSS legal land descriptions to GPS coordinates and back.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -50,8 +50,7 @@
50
50
  "license": "MIT",
51
51
  "repository": {
52
52
  "type": "git",
53
- "url": "https://github.com/mepa1363/townshipamerica-web",
54
- "directory": "sdk/typescript"
53
+ "url": "https://github.com/townshipamerica/typescript-sdk.git"
55
54
  },
56
55
  "homepage": "https://townshipamerica.com/api",
57
56
  "engines": {