@wherabouts/react 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,15 +1,21 @@
1
- Copyright (c) 2026 Wherabouts. All rights reserved.
1
+ MIT License
2
2
 
3
- This software and associated documentation files (the "SDK") are the proprietary
4
- property of Wherabouts. The SDK is licensed, not sold, and is made available solely
5
- for use in connection with the Wherabouts location API by parties holding valid
6
- Wherabouts API credentials, subject to the Wherabouts Terms of Service.
3
+ Copyright (c) 2026 Wherabouts
7
4
 
8
- Permission is NOT granted to use, copy, modify, merge, publish, distribute,
9
- sublicense, or sell copies of the SDK except as expressly permitted in writing by
10
- Wherabouts or as necessary to integrate with the Wherabouts API under a valid account.
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
11
 
12
- THE SDK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14
- PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL WHERABOUTS BE LIABLE FOR
15
- ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM THE USE OF THE SDK.
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs CHANGED
@@ -363,11 +363,13 @@ function useReverseGeocode(client, coords) {
363
363
  const [loading, setLoading] = react.useState(false);
364
364
  const [error, setError] = react.useState(null);
365
365
  const abortRef = react.useRef(null);
366
+ const lat = coords?.lat ?? null;
367
+ const lng = coords?.lng ?? null;
366
368
  react.useEffect(() => {
367
369
  if (abortRef.current) {
368
370
  abortRef.current.abort();
369
371
  }
370
- if (!coords) {
372
+ if (lat === null || lng === null) {
371
373
  setAddress(null);
372
374
  setDistance(null);
373
375
  setLoading(false);
@@ -378,7 +380,7 @@ function useReverseGeocode(client, coords) {
378
380
  abortRef.current = controller;
379
381
  setLoading(true);
380
382
  setError(null);
381
- client.addresses.reverse(coords, { signal: controller.signal }).then((res) => {
383
+ client.addresses.reverse({ lat, lng }, { signal: controller.signal }).then((res) => {
382
384
  if (!controller.signal.aborted) {
383
385
  setAddress(res.address);
384
386
  setDistance(res.distance);
@@ -395,7 +397,7 @@ function useReverseGeocode(client, coords) {
395
397
  return () => {
396
398
  controller.abort();
397
399
  };
398
- }, [coords?.lat, coords?.lng, client]);
400
+ }, [lat, lng, client]);
399
401
  return { address, distance, loading, error };
400
402
  }
401
403
 
@@ -468,11 +470,13 @@ function useZoneContains(client, coords) {
468
470
  const [loading, setLoading] = react.useState(false);
469
471
  const [error, setError] = react.useState(null);
470
472
  const abortRef = react.useRef(null);
473
+ const lat = coords?.lat ?? null;
474
+ const lng = coords?.lng ?? null;
471
475
  react.useEffect(() => {
472
476
  if (abortRef.current) {
473
477
  abortRef.current.abort();
474
478
  }
475
- if (!coords) {
479
+ if (lat === null || lng === null) {
476
480
  setZones([]);
477
481
  setLoading(false);
478
482
  setError(null);
@@ -482,7 +486,7 @@ function useZoneContains(client, coords) {
482
486
  abortRef.current = controller;
483
487
  setLoading(true);
484
488
  setError(null);
485
- client.zones.contains(coords, { signal: controller.signal }).then((res) => {
489
+ client.zones.contains({ lat, lng }, { signal: controller.signal }).then((res) => {
486
490
  if (!controller.signal.aborted) {
487
491
  setZones(res.zones);
488
492
  }
@@ -498,7 +502,7 @@ function useZoneContains(client, coords) {
498
502
  return () => {
499
503
  controller.abort();
500
504
  };
501
- }, [coords?.lat, coords?.lng, client]);
505
+ }, [lat, lng, client]);
502
506
  return { zones, loading, error };
503
507
  }
504
508
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/combobox.ts","../src/autocomplete-cache.ts","../src/use-autocomplete.ts","../src/use-reverse-geocode.ts","../src/async-resource.ts","../src/use-routing.ts","../src/use-zone-contains.ts"],"names":["useReducer","useCallback","isRateLimitError","useState","useRef","useEffect"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n\ttype KeyboardEvent,\n\ttype MouseEvent,\n\tuseCallback,\n\tuseReducer,\n} from \"react\";\n\n/**\n * Headless WAI-ARIA combobox helper for autocomplete dropdowns. Provides the\n * keyboard state machine (↑/↓/Home/End/Enter/Esc, wrapping) and ARIA prop\n * getters so an input + listbox is accessible by default. Bring your own\n * markup and data; this hook owns only the open/active-option state.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/combobox/\n */\n\nexport interface ComboboxState {\n\t/** Index of the visually-active option, or -1 when none is active. */\n\tactiveIndex: number;\n\tisOpen: boolean;\n}\n\nexport type ComboboxAction =\n\t| { type: \"next\"; count: number }\n\t| { type: \"prev\"; count: number }\n\t| { type: \"first\"; count: number }\n\t| { type: \"last\"; count: number }\n\t| { type: \"set\"; index: number }\n\t| { type: \"open\" }\n\t| { type: \"close\" }\n\t| { type: \"select\" }\n\t| { type: \"reset\" };\n\nexport const INITIAL_COMBOBOX_STATE: ComboboxState = {\n\tisOpen: false,\n\tactiveIndex: -1,\n};\n\n/** Pure transition function for the combobox keyboard state machine. */\nexport function comboboxReducer(\n\tstate: ComboboxState,\n\taction: ComboboxAction\n): ComboboxState {\n\tswitch (action.type) {\n\t\tcase \"next\": {\n\t\t\tif (action.count === 0) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst activeIndex =\n\t\t\t\tstate.activeIndex >= action.count - 1 ? 0 : state.activeIndex + 1;\n\t\t\treturn { isOpen: true, activeIndex };\n\t\t}\n\t\tcase \"prev\": {\n\t\t\tif (action.count === 0) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst activeIndex =\n\t\t\t\tstate.activeIndex <= 0 ? action.count - 1 : state.activeIndex - 1;\n\t\t\treturn { isOpen: true, activeIndex };\n\t\t}\n\t\tcase \"first\":\n\t\t\treturn action.count === 0 ? state : { isOpen: true, activeIndex: 0 };\n\t\tcase \"last\":\n\t\t\treturn action.count === 0\n\t\t\t\t? state\n\t\t\t\t: { isOpen: true, activeIndex: action.count - 1 };\n\t\tcase \"set\":\n\t\t\treturn { isOpen: true, activeIndex: action.index };\n\t\tcase \"open\":\n\t\t\treturn { ...state, isOpen: true };\n\t\tcase \"close\":\n\t\tcase \"select\":\n\t\t\treturn INITIAL_COMBOBOX_STATE;\n\t\tdefault:\n\t\t\treturn INITIAL_COMBOBOX_STATE;\n\t}\n}\n\n/** Map a keyboard key to a combobox action, or null when it is irrelevant. */\nexport function keyToAction(key: string, count: number): ComboboxAction | null {\n\tswitch (key) {\n\t\tcase \"ArrowDown\":\n\t\t\treturn { type: \"next\", count };\n\t\tcase \"ArrowUp\":\n\t\t\treturn { type: \"prev\", count };\n\t\tcase \"Home\":\n\t\t\treturn { type: \"first\", count };\n\t\tcase \"End\":\n\t\t\treturn { type: \"last\", count };\n\t\tcase \"Escape\":\n\t\t\treturn { type: \"close\" };\n\t\tcase \"Enter\":\n\t\t\treturn { type: \"select\" };\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nexport interface ComboboxInputProps {\n\t\"aria-activedescendant\": string | undefined;\n\t\"aria-autocomplete\": \"list\";\n\t\"aria-controls\": string;\n\t\"aria-expanded\": boolean;\n\trole: \"combobox\";\n}\n\nexport interface ComboboxListboxProps {\n\tid: string;\n\trole: \"listbox\";\n}\n\nexport interface ComboboxItemProps {\n\t\"aria-selected\": boolean;\n\tid: string;\n\trole: \"option\";\n}\n\nconst listboxId = (id: string) => `${id}-listbox`;\nconst optionId = (id: string, index: number) => `${id}-option-${index}`;\n\n/** Build the ARIA attributes for the combobox input — pure. */\nexport function buildInputProps(\n\tid: string,\n\tstate: ComboboxState\n): ComboboxInputProps {\n\treturn {\n\t\trole: \"combobox\",\n\t\t\"aria-autocomplete\": \"list\",\n\t\t\"aria-expanded\": state.isOpen,\n\t\t\"aria-controls\": listboxId(id),\n\t\t\"aria-activedescendant\":\n\t\t\tstate.isOpen && state.activeIndex >= 0\n\t\t\t\t? optionId(id, state.activeIndex)\n\t\t\t\t: undefined,\n\t};\n}\n\n/** Build the ARIA attributes for the listbox container — pure. */\nexport function buildListboxProps(id: string): ComboboxListboxProps {\n\treturn { id: listboxId(id), role: \"listbox\" };\n}\n\n/** Build the ARIA attributes for an option at `index` — pure. */\nexport function buildItemProps(\n\tid: string,\n\tindex: number,\n\tstate: ComboboxState\n): ComboboxItemProps {\n\treturn {\n\t\trole: \"option\",\n\t\tid: optionId(id, index),\n\t\t\"aria-selected\": state.activeIndex === index,\n\t};\n}\n\nexport interface UseComboboxOptions {\n\t/** Number of options currently rendered (drives wrapping/bounds). */\n\tcount: number;\n\t/** Stable id root; option/listbox ids derive from it. */\n\tid: string;\n\t/** Called when an option is chosen via Enter or pointer. */\n\tonSelect?: (index: number) => void;\n}\n\nexport interface UseComboboxResult {\n\tactiveIndex: number;\n\tclose: () => void;\n\tgetInputProps: () => ComboboxInputProps & {\n\t\tonBlur: () => void;\n\t\tonFocus: () => void;\n\t\tonKeyDown: (event: KeyboardEvent) => void;\n\t};\n\tgetItemProps: (index: number) => ComboboxItemProps & {\n\t\tonMouseDown: (event: MouseEvent) => void;\n\t\tonMouseEnter: () => void;\n\t};\n\tgetListboxProps: () => ComboboxListboxProps;\n\tisOpen: boolean;\n\topen: () => void;\n\treset: () => void;\n\tsetActiveIndex: (index: number) => void;\n}\n\nexport function useCombobox(options: UseComboboxOptions): UseComboboxResult {\n\tconst { id, count, onSelect } = options;\n\tconst [state, dispatch] = useReducer(comboboxReducer, INITIAL_COMBOBOX_STATE);\n\n\tconst open = useCallback(() => dispatch({ type: \"open\" }), []);\n\tconst close = useCallback(() => dispatch({ type: \"close\" }), []);\n\tconst reset = useCallback(() => dispatch({ type: \"reset\" }), []);\n\tconst setActiveIndex = useCallback(\n\t\t(index: number) => dispatch({ type: \"set\", index }),\n\t\t[]\n\t);\n\n\tconst getInputProps = useCallback(\n\t\t() => ({\n\t\t\t...buildInputProps(id, state),\n\t\t\tonFocus: () => dispatch({ type: \"open\" }),\n\t\t\tonBlur: () => dispatch({ type: \"close\" }),\n\t\t\tonKeyDown: (event: KeyboardEvent) => {\n\t\t\t\tconst action = keyToAction(event.key, count);\n\t\t\t\tif (!action) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action.type === \"select\") {\n\t\t\t\t\tif (state.activeIndex >= 0) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tonSelect?.(state.activeIndex);\n\t\t\t\t\t}\n\t\t\t\t\tdispatch({ type: \"select\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tdispatch(action);\n\t\t\t},\n\t\t}),\n\t\t[id, state, count, onSelect]\n\t);\n\n\tconst getListboxProps = useCallback(() => buildListboxProps(id), [id]);\n\n\tconst getItemProps = useCallback(\n\t\t(index: number) => ({\n\t\t\t...buildItemProps(id, index, state),\n\t\t\tonMouseEnter: () => dispatch({ type: \"set\", index }),\n\t\t\tonMouseDown: (event: MouseEvent) => {\n\t\t\t\t// Keep input focus so selection isn't cancelled by blur.\n\t\t\t\tevent.preventDefault();\n\t\t\t\tonSelect?.(index);\n\t\t\t\tdispatch({ type: \"select\" });\n\t\t\t},\n\t\t}),\n\t\t[id, state, onSelect]\n\t);\n\n\treturn {\n\t\tisOpen: state.isOpen,\n\t\tactiveIndex: state.activeIndex,\n\t\topen,\n\t\tclose,\n\t\treset,\n\t\tsetActiveIndex,\n\t\tgetInputProps,\n\t\tgetListboxProps,\n\t\tgetItemProps,\n\t};\n}\n","import type { AddressSuggestion } from \"@wherabouts/sdk\";\n\n/**\n * Minimal structural view of the Web Storage API (sessionStorage/localStorage).\n * Declared locally so the package type-checks with no DOM lib.\n */\nexport interface StorageLike {\n\tgetItem(key: string): string | null;\n\tremoveItem(key: string): void;\n\tsetItem(key: string, value: string): void;\n}\n\nexport interface AutocompleteCacheKeyParts {\n\tcountry?: string;\n\tlat?: number;\n\tlimit?: number;\n\tlng?: number;\n\tq: string;\n\tstate?: string;\n}\n\nconst KEY_PREFIX = \"wh:ac:\";\n\n/**\n * Build a stable cache key from the query parameters. The query is trimmed and\n * lower-cased so cosmetic differences (\"George St\" vs \"george st\") share a\n * cache entry; coordinates and filters are included so proximity-boosted or\n * filtered searches never collide with unfiltered ones.\n */\nexport function buildCacheKey(parts: AutocompleteCacheKeyParts): string {\n\tconst q = parts.q.trim().toLowerCase();\n\treturn JSON.stringify([\n\t\tq,\n\t\tparts.country ?? \"\",\n\t\tparts.state ?? \"\",\n\t\tparts.limit ?? \"\",\n\t\tparts.lat ?? \"\",\n\t\tparts.lng ?? \"\",\n\t]);\n}\n\ninterface CacheEntry {\n\tresults: AddressSuggestion[];\n\tt: number;\n}\n\n/**\n * Read cached suggestions for `key`. Returns null on a miss, on corrupt data,\n * or when the entry is older than `ttlMs`; expired/corrupt entries are removed.\n */\nexport function readCache(\n\tstorage: StorageLike,\n\tkey: string,\n\tttlMs: number,\n\tnow: number\n): AddressSuggestion[] | null {\n\tconst raw = storage.getItem(KEY_PREFIX + key);\n\tif (raw === null) {\n\t\treturn null;\n\t}\n\tlet entry: CacheEntry;\n\ttry {\n\t\tentry = JSON.parse(raw) as CacheEntry;\n\t} catch {\n\t\tstorage.removeItem(KEY_PREFIX + key);\n\t\treturn null;\n\t}\n\tif (\n\t\ttypeof entry?.t !== \"number\" ||\n\t\t!Array.isArray(entry.results) ||\n\t\tnow - entry.t > ttlMs\n\t) {\n\t\tstorage.removeItem(KEY_PREFIX + key);\n\t\treturn null;\n\t}\n\treturn entry.results;\n}\n\n/** Store suggestions for `key`, stamped with `now` for TTL eviction on read. */\nexport function writeCache(\n\tstorage: StorageLike,\n\tkey: string,\n\tresults: AddressSuggestion[],\n\tnow: number\n): void {\n\tconst entry: CacheEntry = { results, t: now };\n\ttry {\n\t\tstorage.setItem(KEY_PREFIX + key, JSON.stringify(entry));\n\t} catch {\n\t\t// Storage full or unavailable (private mode/quota) — caching is best-effort.\n\t}\n}\n","import type {\n\tAddressSuggestion,\n\tAutocompleteParams,\n\tWheraboutsClient,\n} from \"@wherabouts/sdk\";\nimport { isRateLimitError } from \"@wherabouts/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n\ttype AutocompleteCacheKeyParts,\n\tbuildCacheKey,\n\treadCache,\n\ttype StorageLike,\n\twriteCache,\n} from \"./autocomplete-cache.ts\";\n\nconst DEFAULT_DEBOUNCE_MS = 300;\n/** API rejects `q` shorter than 2 chars; gate locally to avoid wasted 400s. */\nconst DEFAULT_MIN_LENGTH = 2;\nconst DEFAULT_CACHE_TTL_MS = 60_000;\n\nexport type AutocompleteStatus =\n\t| \"idle\"\n\t| \"loading\"\n\t| \"success\"\n\t| \"empty\"\n\t| \"error\";\n\n/** Opt-in client-side cache for repeated/back-and-forth queries. */\nexport interface AutocompleteCacheConfig {\n\t/** A `sessionStorage`-like store. Entries are namespaced under `wh:ac:`. */\n\tstorage: StorageLike;\n\t/** Entry lifetime in ms (default 60_000). */\n\tttlMs?: number;\n}\n\nexport interface UseAutocompleteOptions {\n\tcache?: AutocompleteCacheConfig;\n\tcountry?: string;\n\tdebounceMs?: number;\n\t/** Keep the previous results visible while a new search runs / on error. */\n\tkeepPreviousData?: boolean;\n\t/** Latitude for proximity boosting (pair with `lng`). */\n\tlat?: number;\n\tlimit?: number;\n\t/** Longitude for proximity boosting (pair with `lat`). */\n\tlng?: number;\n\t/** Minimum trimmed query length before a request fires (default 2). */\n\tminLength?: number;\n\t/** Groups keystrokes into one billable session; see `newSessionToken()`. */\n\tsessionToken?: string;\n\tstate?: string;\n}\n\nexport interface UseAutocompleteResult {\n\terror: Error | null;\n\tloading: boolean;\n\tquery: string;\n\t/** True when the last request was rejected with HTTP 429. */\n\trateLimited: boolean;\n\t/** Clear the query, results, and any in-flight request. */\n\treset: () => void;\n\tresults: AddressSuggestion[];\n\tsetQuery: (q: string) => void;\n\tstatus: AutocompleteStatus;\n}\n\n/**\n * Derive a single coarse status from the hook's raw flags. Exported for\n * unit-testing and for consumers who prefer a state machine to booleans.\n */\nexport function deriveStatus(s: {\n\terror: Error | null;\n\tloading: boolean;\n\tminLength: number;\n\tquery: string;\n\tresults: AddressSuggestion[];\n}): AutocompleteStatus {\n\tif (s.query.trim().length < s.minLength) {\n\t\treturn \"idle\";\n\t}\n\tif (s.loading) {\n\t\treturn \"loading\";\n\t}\n\tif (s.error) {\n\t\treturn \"error\";\n\t}\n\treturn s.results.length === 0 ? \"empty\" : \"success\";\n}\n\ntype SearchPlan =\n\t| { kind: \"idle\" }\n\t| { kind: \"cache\"; results: AddressSuggestion[] }\n\t| { kind: \"fetch\" };\n\n/** Decide whether to skip, serve from cache, or hit the network — pure. */\nfunction planSearch(args: {\n\tcacheStorage: StorageLike | undefined;\n\tcacheTtl: number;\n\tkeyParts: AutocompleteCacheKeyParts;\n\tminLength: number;\n\ttrimmed: string;\n}): SearchPlan {\n\tif (args.trimmed.length < args.minLength) {\n\t\treturn { kind: \"idle\" };\n\t}\n\tif (args.cacheStorage) {\n\t\tconst hit = readCache(\n\t\t\targs.cacheStorage,\n\t\t\tbuildCacheKey(args.keyParts),\n\t\t\targs.cacheTtl,\n\t\t\tDate.now()\n\t\t);\n\t\tif (hit) {\n\t\t\treturn { kind: \"cache\", results: hit };\n\t\t}\n\t}\n\treturn { kind: \"fetch\" };\n}\n\ninterface SearchActions {\n\tonError: (error: Error, rateLimited: boolean) => void;\n\tonSettled: () => void;\n\tonSuccess: (results: AddressSuggestion[]) => void;\n}\n\n/** Run one autocomplete request, routing the outcome through `actions`. */\nasync function executeAutocomplete(\n\tclient: WheraboutsClient,\n\tparams: AutocompleteParams,\n\tcontroller: AbortController,\n\tactions: SearchActions\n): Promise<void> {\n\ttry {\n\t\tconst res = await client.addresses.autocomplete(params, {\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tif (!controller.signal.aborted) {\n\t\t\tactions.onSuccess(res.results);\n\t\t}\n\t} catch (e) {\n\t\tif (!controller.signal.aborted) {\n\t\t\tconst err = e instanceof Error ? e : new Error(String(e));\n\t\t\tactions.onError(err, isRateLimitError(e));\n\t\t}\n\t} finally {\n\t\tif (!controller.signal.aborted) {\n\t\t\tactions.onSettled();\n\t\t}\n\t}\n}\n\nfunction cancelPending(\n\ttimer: ReturnType<typeof setTimeout> | null,\n\tcontroller: AbortController | null\n): void {\n\tif (timer) {\n\t\tclearTimeout(timer);\n\t}\n\tcontroller?.abort();\n}\n\nexport function useAutocomplete(\n\tclient: WheraboutsClient,\n\toptions: UseAutocompleteOptions = {}\n): UseAutocompleteResult {\n\tconst {\n\t\tdebounceMs = DEFAULT_DEBOUNCE_MS,\n\t\tminLength = DEFAULT_MIN_LENGTH,\n\t\tlimit,\n\t\tcountry,\n\t\tstate,\n\t\tlat,\n\t\tlng,\n\t\tsessionToken,\n\t\tkeepPreviousData = false,\n\t\tcache,\n\t} = options;\n\n\tconst [query, setQuery] = useState(\"\");\n\tconst [results, setResults] = useState<AddressSuggestion[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst [rateLimited, setRateLimited] = useState(false);\n\n\tconst abortRef = useRef<AbortController | null>(null);\n\tconst timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n\t// Stable setter — consumers can safely pass this to input onChange.\n\tconst handleSetQuery = useCallback((q: string) => {\n\t\tsetQuery(q);\n\t}, []);\n\n\tconst reset = useCallback(() => {\n\t\tcancelPending(timerRef.current, abortRef.current);\n\t\tsetQuery(\"\");\n\t\tsetResults([]);\n\t\tsetLoading(false);\n\t\tsetError(null);\n\t\tsetRateLimited(false);\n\t}, []);\n\n\tconst cacheStorage = cache?.storage;\n\tconst cacheTtl = cache?.ttlMs ?? DEFAULT_CACHE_TTL_MS;\n\n\tuseEffect(() => {\n\t\tcancelPending(timerRef.current, abortRef.current);\n\n\t\tconst trimmed = query.trim();\n\t\tconst keyParts: AutocompleteCacheKeyParts = {\n\t\t\tq: trimmed,\n\t\t\tcountry,\n\t\t\tstate,\n\t\t\tlimit,\n\t\t\tlat,\n\t\t\tlng,\n\t\t};\n\t\tconst plan = planSearch({\n\t\t\ttrimmed,\n\t\t\tminLength,\n\t\t\tcacheStorage,\n\t\t\tcacheTtl,\n\t\t\tkeyParts,\n\t\t});\n\n\t\tsetError(null);\n\t\tsetRateLimited(false);\n\n\t\tif (plan.kind === \"idle\") {\n\t\t\tif (!keepPreviousData) {\n\t\t\t\tsetResults([]);\n\t\t\t}\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\t\tif (plan.kind === \"cache\") {\n\t\t\tsetResults(plan.results);\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\n\t\t// Clear stale results as the new search starts unless asked to keep them\n\t\t// visible (keepPreviousData avoids dropdown flicker between keystrokes).\n\t\tif (!keepPreviousData) {\n\t\t\tsetResults([]);\n\t\t}\n\t\tsetLoading(true);\n\t\ttimerRef.current = setTimeout(async () => {\n\t\t\tconst controller = new AbortController();\n\t\t\tabortRef.current = controller;\n\t\t\tawait executeAutocomplete(\n\t\t\t\tclient,\n\t\t\t\t{ q: trimmed, limit, country, state, lat, lng, sessionToken },\n\t\t\t\tcontroller,\n\t\t\t\t{\n\t\t\t\t\tonSuccess: (r) => {\n\t\t\t\t\t\tsetResults(r);\n\t\t\t\t\t\tif (cacheStorage) {\n\t\t\t\t\t\t\twriteCache(cacheStorage, buildCacheKey(keyParts), r, Date.now());\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonError: (err, limited) => {\n\t\t\t\t\t\tsetError(err);\n\t\t\t\t\t\tsetRateLimited(limited);\n\t\t\t\t\t\tif (!keepPreviousData) {\n\t\t\t\t\t\t\tsetResults([]);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonSettled: () => setLoading(false),\n\t\t\t\t}\n\t\t\t);\n\t\t}, debounceMs);\n\n\t\treturn () => cancelPending(timerRef.current, abortRef.current);\n\t}, [\n\t\tquery,\n\t\tdebounceMs,\n\t\tminLength,\n\t\tlimit,\n\t\tcountry,\n\t\tstate,\n\t\tlat,\n\t\tlng,\n\t\tsessionToken,\n\t\tkeepPreviousData,\n\t\tcacheStorage,\n\t\tcacheTtl,\n\t\tclient,\n\t]);\n\n\tconst status = deriveStatus({ query, minLength, loading, error, results });\n\n\treturn {\n\t\tquery,\n\t\tsetQuery: handleSetQuery,\n\t\tresults,\n\t\tloading,\n\t\terror,\n\t\trateLimited,\n\t\treset,\n\t\tstatus,\n\t};\n}\n","import type { ReverseGeocodeAddress, WheraboutsClient } from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport interface LatLng {\n\tlat: number;\n\tlng: number;\n}\n\nexport interface UseReverseGeocodeResult {\n\taddress: ReverseGeocodeAddress | null;\n\tdistance: number | null;\n\terror: Error | null;\n\tloading: boolean;\n}\n\nexport function useReverseGeocode(\n\tclient: WheraboutsClient,\n\tcoords: LatLng | null\n): UseReverseGeocodeResult {\n\tconst [address, setAddress] = useState<ReverseGeocodeAddress | null>(null);\n\tconst [distance, setDistance] = useState<number | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (!coords) {\n\t\t\tsetAddress(null);\n\t\t\tsetDistance(null);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\tclient.addresses\n\t\t\t.reverse(coords, { signal: controller.signal })\n\t\t\t.then((res) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetAddress(res.address);\n\t\t\t\t\tsetDistance(res.distance);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetLoading(false);\n\t\t\t\t}\n\t\t\t});\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t};\n\t}, [coords?.lat, coords?.lng, client]);\n\n\treturn { address, distance, loading, error };\n}\n","/** Minimal view of AbortSignal — only the `aborted` flag is needed here. */\nexport interface AbortLike {\n\taborted: boolean;\n}\n\nexport interface ResourceActions<T> {\n\tonError: (error: Error) => void;\n\tonSettled: () => void;\n\tonSuccess: (data: T) => void;\n}\n\n/**\n * Await `promise` and route the outcome through `actions`, skipping every\n * callback once `signal` is aborted (so a stale request can't clobber the\n * state of a newer one). Shared by the data-fetching hooks.\n */\nexport async function runResource<T>(\n\tpromise: Promise<T>,\n\tsignal: AbortLike,\n\tactions: ResourceActions<T>\n): Promise<void> {\n\ttry {\n\t\tconst data = await promise;\n\t\tif (!signal.aborted) {\n\t\t\tactions.onSuccess(data);\n\t\t}\n\t} catch (e) {\n\t\tif (!signal.aborted) {\n\t\t\tactions.onError(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t} finally {\n\t\tif (!signal.aborted) {\n\t\t\tactions.onSettled();\n\t\t}\n\t}\n}\n","import type {\n\tCallOptions,\n\tDirectionsParams,\n\tDirectionsResponse,\n\tIsochroneParams,\n\tIsochroneResponse,\n\tMatrixParams,\n\tMatrixResponse,\n\tWheraboutsClient,\n} from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { runResource } from \"./async-resource.ts\";\n\nexport interface RoutingResourceResult<T> {\n\tdata: T | null;\n\terror: Error | null;\n\tloading: boolean;\n}\n\ntype RoutingCall<P, R> = (\n\tclient: WheraboutsClient,\n\tparams: P,\n\toptions: CallOptions\n) => Promise<R>;\n\n/**\n * Shared effect skeleton for the routing hooks: fires `call` whenever the\n * (serialized) params change, aborts the previous request, and exposes\n * `{ data, loading, error }`. Pass `null` params to stay idle.\n */\nfunction useRoutingResource<P, R>(\n\tclient: WheraboutsClient,\n\tparams: P | null,\n\tcall: RoutingCall<P, R>\n): RoutingResourceResult<R> {\n\tconst [data, setData] = useState<R | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\t// Serialize params so stable values don't refire on every render.\n\tconst key = params ? JSON.stringify(params) : null;\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: `params` is tracked via its serialized `key`\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (!params) {\n\t\t\tsetData(null);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\trunResource(\n\t\t\tcall(client, params, { signal: controller.signal }),\n\t\t\tcontroller.signal,\n\t\t\t{\n\t\t\t\tonSuccess: setData,\n\t\t\t\tonError: setError,\n\t\t\t\tonSettled: () => setLoading(false),\n\t\t\t}\n\t\t);\n\n\t\treturn () => controller.abort();\n\t}, [key, client, call]);\n\n\treturn { data, loading, error };\n}\n\nconst directionsCall: RoutingCall<DirectionsParams, DirectionsResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.directions(params, options);\n\nconst matrixCall: RoutingCall<MatrixParams, MatrixResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.matrix(params, options);\n\nconst isochroneCall: RoutingCall<IsochroneParams, IsochroneResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.isochrone(params, options);\n\n/** Fetch turn-by-turn directions; pass `null` to stay idle. */\nexport function useDirections(\n\tclient: WheraboutsClient,\n\tparams: DirectionsParams | null\n): RoutingResourceResult<DirectionsResponse> {\n\treturn useRoutingResource(client, params, directionsCall);\n}\n\n/** Fetch a duration/distance matrix; pass `null` to stay idle. */\nexport function useMatrix(\n\tclient: WheraboutsClient,\n\tparams: MatrixParams | null\n): RoutingResourceResult<MatrixResponse> {\n\treturn useRoutingResource(client, params, matrixCall);\n}\n\n/** Fetch an isochrone polygon; pass `null` to stay idle. */\nexport function useIsochrone(\n\tclient: WheraboutsClient,\n\tparams: IsochroneParams | null\n): RoutingResourceResult<IsochroneResponse> {\n\treturn useRoutingResource(client, params, isochroneCall);\n}\n","import type { WheraboutsClient, ZoneRecord } from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport type { LatLng } from \"./use-reverse-geocode.ts\";\n\nexport interface UseZoneContainsResult {\n\terror: Error | null;\n\tloading: boolean;\n\tzones: ZoneRecord[];\n}\n\nexport function useZoneContains(\n\tclient: WheraboutsClient,\n\tcoords: LatLng | null\n): UseZoneContainsResult {\n\tconst [zones, setZones] = useState<ZoneRecord[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (!coords) {\n\t\t\tsetZones([]);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\tclient.zones\n\t\t\t.contains(coords, { signal: controller.signal })\n\t\t\t.then((res) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetZones(res.zones);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetLoading(false);\n\t\t\t\t}\n\t\t\t});\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t};\n\t}, [coords?.lat, coords?.lng, client]);\n\n\treturn { zones, loading, error };\n}\n"]}
1
+ {"version":3,"sources":["../src/combobox.ts","../src/autocomplete-cache.ts","../src/use-autocomplete.ts","../src/use-reverse-geocode.ts","../src/async-resource.ts","../src/use-routing.ts","../src/use-zone-contains.ts"],"names":["useReducer","useCallback","isRateLimitError","useState","useRef","useEffect"],"mappings":";;;;;;AAiCO,IAAM,sBAAA,GAAwC;AAAA,EACpD,MAAA,EAAQ,KAAA;AAAA,EACR,WAAA,EAAa;AACd;AAGO,SAAS,eAAA,CACf,OACA,MAAA,EACgB;AAChB,EAAA,QAAQ,OAAO,IAAA;AAAM,IACpB,KAAK,MAAA,EAAQ;AACZ,MAAA,IAAI,MAAA,CAAO,UAAU,CAAA,EAAG;AACvB,QAAA,OAAO,KAAA;AAAA,MACR;AACA,MAAA,MAAM,WAAA,GACL,MAAM,WAAA,IAAe,MAAA,CAAO,QAAQ,CAAA,GAAI,CAAA,GAAI,MAAM,WAAA,GAAc,CAAA;AACjE,MAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,WAAA,EAAY;AAAA,IACpC;AAAA,IACA,KAAK,MAAA,EAAQ;AACZ,MAAA,IAAI,MAAA,CAAO,UAAU,CAAA,EAAG;AACvB,QAAA,OAAO,KAAA;AAAA,MACR;AACA,MAAA,MAAM,WAAA,GACL,MAAM,WAAA,IAAe,CAAA,GAAI,OAAO,KAAA,GAAQ,CAAA,GAAI,MAAM,WAAA,GAAc,CAAA;AACjE,MAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,WAAA,EAAY;AAAA,IACpC;AAAA,IACA,KAAK,OAAA;AACJ,MAAA,OAAO,MAAA,CAAO,UAAU,CAAA,GAAI,KAAA,GAAQ,EAAE,MAAA,EAAQ,IAAA,EAAM,aAAa,CAAA,EAAE;AAAA,IACpE,KAAK,MAAA;AACJ,MAAA,OAAO,MAAA,CAAO,KAAA,KAAU,CAAA,GACrB,KAAA,GACA,EAAE,QAAQ,IAAA,EAAM,WAAA,EAAa,MAAA,CAAO,KAAA,GAAQ,CAAA,EAAE;AAAA,IAClD,KAAK,KAAA;AACJ,MAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,WAAA,EAAa,OAAO,KAAA,EAAM;AAAA,IAClD,KAAK,MAAA;AACJ,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,MAAA,EAAQ,IAAA,EAAK;AAAA,IACjC,KAAK,OAAA;AAAA,IACL,KAAK,QAAA;AACJ,MAAA,OAAO,sBAAA;AAAA,IACR;AACC,MAAA,OAAO,sBAAA;AAAA;AAEV;AAGO,SAAS,WAAA,CAAY,KAAa,KAAA,EAAsC;AAC9E,EAAA,QAAQ,GAAA;AAAK,IACZ,KAAK,WAAA;AACJ,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAM;AAAA,IAC9B,KAAK,SAAA;AACJ,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAM;AAAA,IAC9B,KAAK,MAAA;AACJ,MAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAM;AAAA,IAC/B,KAAK,KAAA;AACJ,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAM;AAAA,IAC9B,KAAK,QAAA;AACJ,MAAA,OAAO,EAAE,MAAM,OAAA,EAAQ;AAAA,IACxB,KAAK,OAAA;AACJ,MAAA,OAAO,EAAE,MAAM,QAAA,EAAS;AAAA,IACzB;AACC,MAAA,OAAO,IAAA;AAAA;AAEV;AAqBA,IAAM,SAAA,GAAY,CAAC,EAAA,KAAe,CAAA,EAAG,EAAE,CAAA,QAAA,CAAA;AACvC,IAAM,WAAW,CAAC,EAAA,EAAY,UAAkB,CAAA,EAAG,EAAE,WAAW,KAAK,CAAA,CAAA;AAG9D,SAAS,eAAA,CACf,IACA,KAAA,EACqB;AACrB,EAAA,OAAO;AAAA,IACN,IAAA,EAAM,UAAA;AAAA,IACN,mBAAA,EAAqB,MAAA;AAAA,IACrB,iBAAiB,KAAA,CAAM,MAAA;AAAA,IACvB,eAAA,EAAiB,UAAU,EAAE,CAAA;AAAA,IAC7B,uBAAA,EACC,KAAA,CAAM,MAAA,IAAU,KAAA,CAAM,WAAA,IAAe,IAClC,QAAA,CAAS,EAAA,EAAI,KAAA,CAAM,WAAW,CAAA,GAC9B;AAAA,GACL;AACD;AAGO,SAAS,kBAAkB,EAAA,EAAkC;AACnE,EAAA,OAAO,EAAE,EAAA,EAAI,SAAA,CAAU,EAAE,CAAA,EAAG,MAAM,SAAA,EAAU;AAC7C;AAGO,SAAS,cAAA,CACf,EAAA,EACA,KAAA,EACA,KAAA,EACoB;AACpB,EAAA,OAAO;AAAA,IACN,IAAA,EAAM,QAAA;AAAA,IACN,EAAA,EAAI,QAAA,CAAS,EAAA,EAAI,KAAK,CAAA;AAAA,IACtB,eAAA,EAAiB,MAAM,WAAA,KAAgB;AAAA,GACxC;AACD;AA8BO,SAAS,YAAY,OAAA,EAAgD;AAC3E,EAAA,MAAM,EAAE,EAAA,EAAI,KAAA,EAAO,QAAA,EAAS,GAAI,OAAA;AAChC,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,gBAAA,CAAW,iBAAiB,sBAAsB,CAAA;AAE5E,EAAA,MAAM,IAAA,GAAOC,iBAAA,CAAY,MAAM,QAAA,CAAS,EAAE,MAAM,MAAA,EAAQ,CAAA,EAAG,EAAE,CAAA;AAC7D,EAAA,MAAM,KAAA,GAAQA,iBAAA,CAAY,MAAM,QAAA,CAAS,EAAE,MAAM,OAAA,EAAS,CAAA,EAAG,EAAE,CAAA;AAC/D,EAAA,MAAM,KAAA,GAAQA,iBAAA,CAAY,MAAM,QAAA,CAAS,EAAE,MAAM,OAAA,EAAS,CAAA,EAAG,EAAE,CAAA;AAC/D,EAAA,MAAM,cAAA,GAAiBA,iBAAA;AAAA,IACtB,CAAC,KAAA,KAAkB,QAAA,CAAS,EAAE,IAAA,EAAM,KAAA,EAAO,OAAO,CAAA;AAAA,IAClD;AAAC,GACF;AAEA,EAAA,MAAM,aAAA,GAAgBA,iBAAA;AAAA,IACrB,OAAO;AAAA,MACN,GAAG,eAAA,CAAgB,EAAA,EAAI,KAAK,CAAA;AAAA,MAC5B,SAAS,MAAM,QAAA,CAAS,EAAE,IAAA,EAAM,QAAQ,CAAA;AAAA,MACxC,QAAQ,MAAM,QAAA,CAAS,EAAE,IAAA,EAAM,SAAS,CAAA;AAAA,MACxC,SAAA,EAAW,CAAC,KAAA,KAAyB;AACpC,QAAA,MAAM,MAAA,GAAS,WAAA,CAAY,KAAA,CAAM,GAAA,EAAK,KAAK,CAAA;AAC3C,QAAA,IAAI,CAAC,MAAA,EAAQ;AACZ,UAAA;AAAA,QACD;AACA,QAAA,IAAI,MAAA,CAAO,SAAS,QAAA,EAAU;AAC7B,UAAA,IAAI,KAAA,CAAM,eAAe,CAAA,EAAG;AAC3B,YAAA,KAAA,CAAM,cAAA,EAAe;AACrB,YAAA,QAAA,GAAW,MAAM,WAAW,CAAA;AAAA,UAC7B;AACA,UAAA,QAAA,CAAS,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA;AAC3B,UAAA;AAAA,QACD;AACA,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,QAAA,CAAS,MAAM,CAAA;AAAA,MAChB;AAAA,KACD,CAAA;AAAA,IACA,CAAC,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,QAAQ;AAAA,GAC5B;AAEA,EAAA,MAAM,eAAA,GAAkBA,kBAAY,MAAM,iBAAA,CAAkB,EAAE,CAAA,EAAG,CAAC,EAAE,CAAC,CAAA;AAErE,EAAA,MAAM,YAAA,GAAeA,iBAAA;AAAA,IACpB,CAAC,KAAA,MAAmB;AAAA,MACnB,GAAG,cAAA,CAAe,EAAA,EAAI,KAAA,EAAO,KAAK,CAAA;AAAA,MAClC,cAAc,MAAM,QAAA,CAAS,EAAE,IAAA,EAAM,KAAA,EAAO,OAAO,CAAA;AAAA,MACnD,WAAA,EAAa,CAAC,KAAA,KAAsB;AAEnC,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,QAAA,GAAW,KAAK,CAAA;AAChB,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA;AAAA,MAC5B;AAAA,KACD,CAAA;AAAA,IACA,CAAC,EAAA,EAAI,KAAA,EAAO,QAAQ;AAAA,GACrB;AAEA,EAAA,OAAO;AAAA,IACN,QAAQ,KAAA,CAAM,MAAA;AAAA,IACd,aAAa,KAAA,CAAM,WAAA;AAAA,IACnB,IAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAA;AAAA,IACA,cAAA;AAAA,IACA,aAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACD;AACD;;;AClOA,IAAM,UAAA,GAAa,QAAA;AAQZ,SAAS,cAAc,KAAA,EAA0C;AACvE,EAAA,MAAM,CAAA,GAAI,KAAA,CAAM,CAAA,CAAE,IAAA,GAAO,WAAA,EAAY;AACrC,EAAA,OAAO,KAAK,SAAA,CAAU;AAAA,IACrB,CAAA;AAAA,IACA,MAAM,OAAA,IAAW,EAAA;AAAA,IACjB,MAAM,KAAA,IAAS,EAAA;AAAA,IACf,MAAM,KAAA,IAAS,EAAA;AAAA,IACf,MAAM,GAAA,IAAO,EAAA;AAAA,IACb,MAAM,GAAA,IAAO;AAAA,GACb,CAAA;AACF;AAWO,SAAS,SAAA,CACf,OAAA,EACA,GAAA,EACA,KAAA,EACA,GAAA,EAC6B;AAC7B,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,UAAA,GAAa,GAAG,CAAA;AAC5C,EAAA,IAAI,QAAQ,IAAA,EAAM;AACjB,IAAA,OAAO,IAAA;AAAA,EACR;AACA,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACH,IAAA,KAAA,GAAQ,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACvB,CAAA,CAAA,MAAQ;AACP,IAAA,OAAA,CAAQ,UAAA,CAAW,aAAa,GAAG,CAAA;AACnC,IAAA,OAAO,IAAA;AAAA,EACR;AACA,EAAA,IACC,OAAO,KAAA,EAAO,CAAA,KAAM,QAAA,IACpB,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,OAAO,CAAA,IAC5B,GAAA,GAAM,KAAA,CAAM,IAAI,KAAA,EACf;AACD,IAAA,OAAA,CAAQ,UAAA,CAAW,aAAa,GAAG,CAAA;AACnC,IAAA,OAAO,IAAA;AAAA,EACR;AACA,EAAA,OAAO,KAAA,CAAM,OAAA;AACd;AAGO,SAAS,UAAA,CACf,OAAA,EACA,GAAA,EACA,OAAA,EACA,GAAA,EACO;AACP,EAAA,MAAM,KAAA,GAAoB,EAAE,OAAA,EAAS,CAAA,EAAG,GAAA,EAAI;AAC5C,EAAA,IAAI;AACH,IAAA,OAAA,CAAQ,QAAQ,UAAA,GAAa,GAAA,EAAK,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,EACxD,CAAA,CAAA,MAAQ;AAAA,EAER;AACD;;;AC5EA,IAAM,mBAAA,GAAsB,GAAA;AAE5B,IAAM,kBAAA,GAAqB,CAAA;AAC3B,IAAM,oBAAA,GAAuB,GAAA;AAoDtB,SAAS,aAAa,CAAA,EAMN;AACtB,EAAA,IAAI,EAAE,KAAA,CAAM,IAAA,EAAK,CAAE,MAAA,GAAS,EAAE,SAAA,EAAW;AACxC,IAAA,OAAO,MAAA;AAAA,EACR;AACA,EAAA,IAAI,EAAE,OAAA,EAAS;AACd,IAAA,OAAO,SAAA;AAAA,EACR;AACA,EAAA,IAAI,EAAE,KAAA,EAAO;AACZ,IAAA,OAAO,OAAA;AAAA,EACR;AACA,EAAA,OAAO,CAAA,CAAE,OAAA,CAAQ,MAAA,KAAW,CAAA,GAAI,OAAA,GAAU,SAAA;AAC3C;AAQA,SAAS,WAAW,IAAA,EAML;AACd,EAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,MAAA,GAAS,IAAA,CAAK,SAAA,EAAW;AACzC,IAAA,OAAO,EAAE,MAAM,MAAA,EAAO;AAAA,EACvB;AACA,EAAA,IAAI,KAAK,YAAA,EAAc;AACtB,IAAA,MAAM,GAAA,GAAM,SAAA;AAAA,MACX,IAAA,CAAK,YAAA;AAAA,MACL,aAAA,CAAc,KAAK,QAAQ,CAAA;AAAA,MAC3B,IAAA,CAAK,QAAA;AAAA,MACL,KAAK,GAAA;AAAI,KACV;AACA,IAAA,IAAI,GAAA,EAAK;AACR,MAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,OAAA,EAAS,GAAA,EAAI;AAAA,IACtC;AAAA,EACD;AACA,EAAA,OAAO,EAAE,MAAM,OAAA,EAAQ;AACxB;AASA,eAAe,mBAAA,CACd,MAAA,EACA,MAAA,EACA,UAAA,EACA,OAAA,EACgB;AAChB,EAAA,IAAI;AACH,IAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,SAAA,CAAU,aAAa,MAAA,EAAQ;AAAA,MACvD,QAAQ,UAAA,CAAW;AAAA,KACnB,CAAA;AACD,IAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAC/B,MAAA,OAAA,CAAQ,SAAA,CAAU,IAAI,OAAO,CAAA;AAAA,IAC9B;AAAA,EACD,SAAS,CAAA,EAAG;AACX,IAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAC/B,MAAA,MAAM,GAAA,GAAM,aAAa,KAAA,GAAQ,CAAA,GAAI,IAAI,KAAA,CAAM,MAAA,CAAO,CAAC,CAAC,CAAA;AACxD,MAAA,OAAA,CAAQ,OAAA,CAAQ,GAAA,EAAKC,oBAAA,CAAiB,CAAC,CAAC,CAAA;AAAA,IACzC;AAAA,EACD,CAAA,SAAE;AACD,IAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAC/B,MAAA,OAAA,CAAQ,SAAA,EAAU;AAAA,IACnB;AAAA,EACD;AACD;AAEA,SAAS,aAAA,CACR,OACA,UAAA,EACO;AACP,EAAA,IAAI,KAAA,EAAO;AACV,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACnB;AACA,EAAA,UAAA,EAAY,KAAA,EAAM;AACnB;AAEO,SAAS,eAAA,CACf,MAAA,EACA,OAAA,GAAkC,EAAC,EACX;AACxB,EAAA,MAAM;AAAA,IACL,UAAA,GAAa,mBAAA;AAAA,IACb,SAAA,GAAY,kBAAA;AAAA,IACZ,KAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA;AAAA,IACA,GAAA;AAAA,IACA,GAAA;AAAA,IACA,YAAA;AAAA,IACA,gBAAA,GAAmB,KAAA;AAAA,IACnB;AAAA,GACD,GAAI,OAAA;AAEJ,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIC,eAAS,EAAE,CAAA;AACrC,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,cAAA,CAA8B,EAAE,CAAA;AAC9D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAuB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIA,eAAS,KAAK,CAAA;AAEpD,EAAA,MAAM,QAAA,GAAWC,aAA+B,IAAI,CAAA;AACpD,EAAA,MAAM,QAAA,GAAWA,aAA6C,IAAI,CAAA;AAGlE,EAAA,MAAM,cAAA,GAAiBH,iBAAAA,CAAY,CAAC,CAAA,KAAc;AACjD,IAAA,QAAA,CAAS,CAAC,CAAA;AAAA,EACX,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,KAAA,GAAQA,kBAAY,MAAM;AAC/B,IAAA,aAAA,CAAc,QAAA,CAAS,OAAA,EAAS,QAAA,CAAS,OAAO,CAAA;AAChD,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,UAAA,CAAW,EAAE,CAAA;AACb,IAAA,UAAA,CAAW,KAAK,CAAA;AAChB,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,cAAA,CAAe,KAAK,CAAA;AAAA,EACrB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,eAAe,KAAA,EAAO,OAAA;AAC5B,EAAA,MAAM,QAAA,GAAW,OAAO,KAAA,IAAS,oBAAA;AAEjC,EAAAI,eAAA,CAAU,MAAM;AACf,IAAA,aAAA,CAAc,QAAA,CAAS,OAAA,EAAS,QAAA,CAAS,OAAO,CAAA;AAEhD,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,IAAA,MAAM,QAAA,GAAsC;AAAA,MAC3C,CAAA,EAAG,OAAA;AAAA,MACH,OAAA;AAAA,MACA,KAAA;AAAA,MACA,KAAA;AAAA,MACA,GAAA;AAAA,MACA;AAAA,KACD;AACA,IAAA,MAAM,OAAO,UAAA,CAAW;AAAA,MACvB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA;AAAA,MACA,QAAA;AAAA,MACA;AAAA,KACA,CAAA;AAED,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,cAAA,CAAe,KAAK,CAAA;AAEpB,IAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACzB,MAAA,IAAI,CAAC,gBAAA,EAAkB;AACtB,QAAA,UAAA,CAAW,EAAE,CAAA;AAAA,MACd;AACA,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACD;AACA,IAAA,IAAI,IAAA,CAAK,SAAS,OAAA,EAAS;AAC1B,MAAA,UAAA,CAAW,KAAK,OAAO,CAAA;AACvB,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACD;AAIA,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACtB,MAAA,UAAA,CAAW,EAAE,CAAA;AAAA,IACd;AACA,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,OAAA,GAAU,WAAW,YAAY;AACzC,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AACnB,MAAA,MAAM,mBAAA;AAAA,QACL,MAAA;AAAA,QACA,EAAE,GAAG,OAAA,EAAS,KAAA,EAAO,SAAS,KAAA,EAAO,GAAA,EAAK,KAAK,YAAA,EAAa;AAAA,QAC5D,UAAA;AAAA,QACA;AAAA,UACC,SAAA,EAAW,CAAC,CAAA,KAAM;AACjB,YAAA,UAAA,CAAW,CAAC,CAAA;AACZ,YAAA,IAAI,YAAA,EAAc;AACjB,cAAA,UAAA,CAAW,cAAc,aAAA,CAAc,QAAQ,GAAG,CAAA,EAAG,IAAA,CAAK,KAAK,CAAA;AAAA,YAChE;AAAA,UACD,CAAA;AAAA,UACA,OAAA,EAAS,CAAC,GAAA,EAAK,OAAA,KAAY;AAC1B,YAAA,QAAA,CAAS,GAAG,CAAA;AACZ,YAAA,cAAA,CAAe,OAAO,CAAA;AACtB,YAAA,IAAI,CAAC,gBAAA,EAAkB;AACtB,cAAA,UAAA,CAAW,EAAE,CAAA;AAAA,YACd;AAAA,UACD,CAAA;AAAA,UACA,SAAA,EAAW,MAAM,UAAA,CAAW,KAAK;AAAA;AAClC,OACD;AAAA,IACD,GAAG,UAAU,CAAA;AAEb,IAAA,OAAO,MAAM,aAAA,CAAc,QAAA,CAAS,OAAA,EAAS,SAAS,OAAO,CAAA;AAAA,EAC9D,CAAA,EAAG;AAAA,IACF,KAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA;AAAA,IACA,KAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA;AAAA,IACA,GAAA;AAAA,IACA,GAAA;AAAA,IACA,YAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACA,CAAA;AAED,EAAA,MAAM,MAAA,GAAS,aAAa,EAAE,KAAA,EAAO,WAAW,OAAA,EAAS,KAAA,EAAO,SAAS,CAAA;AAEzE,EAAA,OAAO;AAAA,IACN,KAAA;AAAA,IACA,QAAA,EAAU,cAAA;AAAA,IACV,OAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA;AAAA,IACA,WAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACD;AACD;AC9RO,SAAS,iBAAA,CACf,QACA,MAAA,EAC0B;AAC1B,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIF,eAAuC,IAAI,CAAA;AACzE,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,eAAwB,IAAI,CAAA;AAC5D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAuB,IAAI,CAAA;AACrD,EAAA,MAAM,QAAA,GAAWC,aAA+B,IAAI,CAAA;AAMpD,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,IAAO,IAAA;AAC3B,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,IAAO,IAAA;AAE3B,EAAAC,gBAAU,MAAM;AACf,IAAA,IAAI,SAAS,OAAA,EAAS;AACrB,MAAA,QAAA,CAAS,QAAQ,KAAA,EAAM;AAAA,IACxB;AAEA,IAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,GAAA,KAAQ,IAAA,EAAM;AACjC,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,WAAA,CAAY,IAAI,CAAA;AAChB,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA;AAAA,IACD;AAEA,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AACnB,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,IAAI,CAAA;AAEb,IAAA,MAAA,CAAO,SAAA,CACL,OAAA,CAAQ,EAAE,GAAA,EAAK,KAAI,EAAG,EAAE,MAAA,EAAQ,UAAA,CAAW,MAAA,EAAQ,CAAA,CACnD,IAAA,CAAK,CAAC,GAAA,KAAQ;AACd,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAC/B,QAAA,UAAA,CAAW,IAAI,OAAO,CAAA;AACtB,QAAA,WAAA,CAAY,IAAI,QAAQ,CAAA;AAAA,MACzB;AAAA,IACD,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,CAAA,KAAe;AACtB,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAC/B,QAAA,QAAA,CAAS,CAAA,YAAa,QAAQ,CAAA,GAAI,IAAI,MAAM,MAAA,CAAO,CAAC,CAAC,CAAC,CAAA;AAAA,MACvD;AAAA,IACD,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACd,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAC/B,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MACjB;AAAA,IACD,CAAC,CAAA;AAEF,IAAA,OAAO,MAAM;AACZ,MAAA,UAAA,CAAW,KAAA,EAAM;AAAA,IAClB,CAAA;AAAA,EACD,CAAA,EAAG,CAAC,GAAA,EAAK,GAAA,EAAK,MAAM,CAAC,CAAA;AAErB,EAAA,OAAO,EAAE,OAAA,EAAS,QAAA,EAAU,OAAA,EAAS,KAAA,EAAM;AAC5C;;;AC3DA,eAAsB,WAAA,CACrB,OAAA,EACA,MAAA,EACA,OAAA,EACgB;AAChB,EAAA,IAAI;AACH,IAAA,MAAM,OAAO,MAAM,OAAA;AACnB,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACpB,MAAA,OAAA,CAAQ,UAAU,IAAI,CAAA;AAAA,IACvB;AAAA,EACD,SAAS,CAAA,EAAG;AACX,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACpB,MAAA,OAAA,CAAQ,OAAA,CAAQ,aAAa,KAAA,GAAQ,CAAA,GAAI,IAAI,KAAA,CAAM,MAAA,CAAO,CAAC,CAAC,CAAC,CAAA;AAAA,IAC9D;AAAA,EACD,CAAA,SAAE;AACD,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACpB,MAAA,OAAA,CAAQ,SAAA,EAAU;AAAA,IACnB;AAAA,EACD;AACD;;;ACLA,SAAS,kBAAA,CACR,MAAA,EACA,MAAA,EACA,IAAA,EAC2B;AAC3B,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIF,eAAmB,IAAI,CAAA;AAC/C,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAuB,IAAI,CAAA;AACrD,EAAA,MAAM,QAAA,GAAWC,aAA+B,IAAI,CAAA;AAGpD,EAAA,MAAM,GAAA,GAAM,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,MAAM,CAAA,GAAI,IAAA;AAG9C,EAAAC,gBAAU,MAAM;AACf,IAAA,IAAI,SAAS,OAAA,EAAS;AACrB,MAAA,QAAA,CAAS,QAAQ,KAAA,EAAM;AAAA,IACxB;AAEA,IAAA,IAAI,CAAC,MAAA,EAAQ;AACZ,MAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA;AAAA,IACD;AAEA,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AACnB,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,IAAI,CAAA;AAEb,IAAA,WAAA;AAAA,MACC,KAAK,MAAA,EAAQ,MAAA,EAAQ,EAAE,MAAA,EAAQ,UAAA,CAAW,QAAQ,CAAA;AAAA,MAClD,UAAA,CAAW,MAAA;AAAA,MACX;AAAA,QACC,SAAA,EAAW,OAAA;AAAA,QACX,OAAA,EAAS,QAAA;AAAA,QACT,SAAA,EAAW,MAAM,UAAA,CAAW,KAAK;AAAA;AAClC,KACD;AAEA,IAAA,OAAO,MAAM,WAAW,KAAA,EAAM;AAAA,EAC/B,CAAA,EAAG,CAAC,GAAA,EAAK,MAAA,EAAQ,IAAI,CAAC,CAAA;AAEtB,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAM;AAC/B;AAEA,IAAM,cAAA,GAAoE,CACzE,MAAA,EACA,MAAA,EACA,YACI,MAAA,CAAO,OAAA,CAAQ,UAAA,CAAW,MAAA,EAAQ,OAAO,CAAA;AAE9C,IAAM,UAAA,GAAwD,CAC7D,MAAA,EACA,MAAA,EACA,YACI,MAAA,CAAO,OAAA,CAAQ,MAAA,CAAO,MAAA,EAAQ,OAAO,CAAA;AAE1C,IAAM,aAAA,GAAiE,CACtE,MAAA,EACA,MAAA,EACA,YACI,MAAA,CAAO,OAAA,CAAQ,SAAA,CAAU,MAAA,EAAQ,OAAO,CAAA;AAGtC,SAAS,aAAA,CACf,QACA,MAAA,EAC4C;AAC5C,EAAA,OAAO,kBAAA,CAAmB,MAAA,EAAQ,MAAA,EAAQ,cAAc,CAAA;AACzD;AAGO,SAAS,SAAA,CACf,QACA,MAAA,EACwC;AACxC,EAAA,OAAO,kBAAA,CAAmB,MAAA,EAAQ,MAAA,EAAQ,UAAU,CAAA;AACrD;AAGO,SAAS,YAAA,CACf,QACA,MAAA,EAC2C;AAC3C,EAAA,OAAO,kBAAA,CAAmB,MAAA,EAAQ,MAAA,EAAQ,aAAa,CAAA;AACxD;AC1GO,SAAS,eAAA,CACf,QACA,MAAA,EACwB;AACxB,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIF,cAAAA,CAAuB,EAAE,CAAA;AACnD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAuB,IAAI,CAAA;AACrD,EAAA,MAAM,QAAA,GAAWC,aAA+B,IAAI,CAAA;AAMpD,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,IAAO,IAAA;AAC3B,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,IAAO,IAAA;AAE3B,EAAAC,gBAAU,MAAM;AACf,IAAA,IAAI,SAAS,OAAA,EAAS;AACrB,MAAA,QAAA,CAAS,QAAQ,KAAA,EAAM;AAAA,IACxB;AAEA,IAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,GAAA,KAAQ,IAAA,EAAM;AACjC,MAAA,QAAA,CAAS,EAAE,CAAA;AACX,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA;AAAA,IACD;AAEA,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AACnB,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,IAAI,CAAA;AAEb,IAAA,MAAA,CAAO,KAAA,CACL,QAAA,CAAS,EAAE,GAAA,EAAK,KAAI,EAAG,EAAE,MAAA,EAAQ,UAAA,CAAW,MAAA,EAAQ,CAAA,CACpD,IAAA,CAAK,CAAC,GAAA,KAAQ;AACd,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAC/B,QAAA,QAAA,CAAS,IAAI,KAAK,CAAA;AAAA,MACnB;AAAA,IACD,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,CAAA,KAAe;AACtB,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAC/B,QAAA,QAAA,CAAS,CAAA,YAAa,QAAQ,CAAA,GAAI,IAAI,MAAM,MAAA,CAAO,CAAC,CAAC,CAAC,CAAA;AAAA,MACvD;AAAA,IACD,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACd,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAC/B,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MACjB;AAAA,IACD,CAAC,CAAA;AAEF,IAAA,OAAO,MAAM;AACZ,MAAA,UAAA,CAAW,KAAA,EAAM;AAAA,IAClB,CAAA;AAAA,EACD,CAAA,EAAG,CAAC,GAAA,EAAK,GAAA,EAAK,MAAM,CAAC,CAAA;AAErB,EAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAM;AAChC","file":"index.cjs","sourcesContent":["import {\n\ttype KeyboardEvent,\n\ttype MouseEvent,\n\tuseCallback,\n\tuseReducer,\n} from \"react\";\n\n/**\n * Headless WAI-ARIA combobox helper for autocomplete dropdowns. Provides the\n * keyboard state machine (↑/↓/Home/End/Enter/Esc, wrapping) and ARIA prop\n * getters so an input + listbox is accessible by default. Bring your own\n * markup and data; this hook owns only the open/active-option state.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/combobox/\n */\n\nexport interface ComboboxState {\n\t/** Index of the visually-active option, or -1 when none is active. */\n\tactiveIndex: number;\n\tisOpen: boolean;\n}\n\nexport type ComboboxAction =\n\t| { type: \"next\"; count: number }\n\t| { type: \"prev\"; count: number }\n\t| { type: \"first\"; count: number }\n\t| { type: \"last\"; count: number }\n\t| { type: \"set\"; index: number }\n\t| { type: \"open\" }\n\t| { type: \"close\" }\n\t| { type: \"select\" }\n\t| { type: \"reset\" };\n\nexport const INITIAL_COMBOBOX_STATE: ComboboxState = {\n\tisOpen: false,\n\tactiveIndex: -1,\n};\n\n/** Pure transition function for the combobox keyboard state machine. */\nexport function comboboxReducer(\n\tstate: ComboboxState,\n\taction: ComboboxAction\n): ComboboxState {\n\tswitch (action.type) {\n\t\tcase \"next\": {\n\t\t\tif (action.count === 0) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst activeIndex =\n\t\t\t\tstate.activeIndex >= action.count - 1 ? 0 : state.activeIndex + 1;\n\t\t\treturn { isOpen: true, activeIndex };\n\t\t}\n\t\tcase \"prev\": {\n\t\t\tif (action.count === 0) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst activeIndex =\n\t\t\t\tstate.activeIndex <= 0 ? action.count - 1 : state.activeIndex - 1;\n\t\t\treturn { isOpen: true, activeIndex };\n\t\t}\n\t\tcase \"first\":\n\t\t\treturn action.count === 0 ? state : { isOpen: true, activeIndex: 0 };\n\t\tcase \"last\":\n\t\t\treturn action.count === 0\n\t\t\t\t? state\n\t\t\t\t: { isOpen: true, activeIndex: action.count - 1 };\n\t\tcase \"set\":\n\t\t\treturn { isOpen: true, activeIndex: action.index };\n\t\tcase \"open\":\n\t\t\treturn { ...state, isOpen: true };\n\t\tcase \"close\":\n\t\tcase \"select\":\n\t\t\treturn INITIAL_COMBOBOX_STATE;\n\t\tdefault:\n\t\t\treturn INITIAL_COMBOBOX_STATE;\n\t}\n}\n\n/** Map a keyboard key to a combobox action, or null when it is irrelevant. */\nexport function keyToAction(key: string, count: number): ComboboxAction | null {\n\tswitch (key) {\n\t\tcase \"ArrowDown\":\n\t\t\treturn { type: \"next\", count };\n\t\tcase \"ArrowUp\":\n\t\t\treturn { type: \"prev\", count };\n\t\tcase \"Home\":\n\t\t\treturn { type: \"first\", count };\n\t\tcase \"End\":\n\t\t\treturn { type: \"last\", count };\n\t\tcase \"Escape\":\n\t\t\treturn { type: \"close\" };\n\t\tcase \"Enter\":\n\t\t\treturn { type: \"select\" };\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nexport interface ComboboxInputProps {\n\t\"aria-activedescendant\": string | undefined;\n\t\"aria-autocomplete\": \"list\";\n\t\"aria-controls\": string;\n\t\"aria-expanded\": boolean;\n\trole: \"combobox\";\n}\n\nexport interface ComboboxListboxProps {\n\tid: string;\n\trole: \"listbox\";\n}\n\nexport interface ComboboxItemProps {\n\t\"aria-selected\": boolean;\n\tid: string;\n\trole: \"option\";\n}\n\nconst listboxId = (id: string) => `${id}-listbox`;\nconst optionId = (id: string, index: number) => `${id}-option-${index}`;\n\n/** Build the ARIA attributes for the combobox input — pure. */\nexport function buildInputProps(\n\tid: string,\n\tstate: ComboboxState\n): ComboboxInputProps {\n\treturn {\n\t\trole: \"combobox\",\n\t\t\"aria-autocomplete\": \"list\",\n\t\t\"aria-expanded\": state.isOpen,\n\t\t\"aria-controls\": listboxId(id),\n\t\t\"aria-activedescendant\":\n\t\t\tstate.isOpen && state.activeIndex >= 0\n\t\t\t\t? optionId(id, state.activeIndex)\n\t\t\t\t: undefined,\n\t};\n}\n\n/** Build the ARIA attributes for the listbox container — pure. */\nexport function buildListboxProps(id: string): ComboboxListboxProps {\n\treturn { id: listboxId(id), role: \"listbox\" };\n}\n\n/** Build the ARIA attributes for an option at `index` — pure. */\nexport function buildItemProps(\n\tid: string,\n\tindex: number,\n\tstate: ComboboxState\n): ComboboxItemProps {\n\treturn {\n\t\trole: \"option\",\n\t\tid: optionId(id, index),\n\t\t\"aria-selected\": state.activeIndex === index,\n\t};\n}\n\nexport interface UseComboboxOptions {\n\t/** Number of options currently rendered (drives wrapping/bounds). */\n\tcount: number;\n\t/** Stable id root; option/listbox ids derive from it. */\n\tid: string;\n\t/** Called when an option is chosen via Enter or pointer. */\n\tonSelect?: (index: number) => void;\n}\n\nexport interface UseComboboxResult {\n\tactiveIndex: number;\n\tclose: () => void;\n\tgetInputProps: () => ComboboxInputProps & {\n\t\tonBlur: () => void;\n\t\tonFocus: () => void;\n\t\tonKeyDown: (event: KeyboardEvent) => void;\n\t};\n\tgetItemProps: (index: number) => ComboboxItemProps & {\n\t\tonMouseDown: (event: MouseEvent) => void;\n\t\tonMouseEnter: () => void;\n\t};\n\tgetListboxProps: () => ComboboxListboxProps;\n\tisOpen: boolean;\n\topen: () => void;\n\treset: () => void;\n\tsetActiveIndex: (index: number) => void;\n}\n\nexport function useCombobox(options: UseComboboxOptions): UseComboboxResult {\n\tconst { id, count, onSelect } = options;\n\tconst [state, dispatch] = useReducer(comboboxReducer, INITIAL_COMBOBOX_STATE);\n\n\tconst open = useCallback(() => dispatch({ type: \"open\" }), []);\n\tconst close = useCallback(() => dispatch({ type: \"close\" }), []);\n\tconst reset = useCallback(() => dispatch({ type: \"reset\" }), []);\n\tconst setActiveIndex = useCallback(\n\t\t(index: number) => dispatch({ type: \"set\", index }),\n\t\t[]\n\t);\n\n\tconst getInputProps = useCallback(\n\t\t() => ({\n\t\t\t...buildInputProps(id, state),\n\t\t\tonFocus: () => dispatch({ type: \"open\" }),\n\t\t\tonBlur: () => dispatch({ type: \"close\" }),\n\t\t\tonKeyDown: (event: KeyboardEvent) => {\n\t\t\t\tconst action = keyToAction(event.key, count);\n\t\t\t\tif (!action) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action.type === \"select\") {\n\t\t\t\t\tif (state.activeIndex >= 0) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tonSelect?.(state.activeIndex);\n\t\t\t\t\t}\n\t\t\t\t\tdispatch({ type: \"select\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tdispatch(action);\n\t\t\t},\n\t\t}),\n\t\t[id, state, count, onSelect]\n\t);\n\n\tconst getListboxProps = useCallback(() => buildListboxProps(id), [id]);\n\n\tconst getItemProps = useCallback(\n\t\t(index: number) => ({\n\t\t\t...buildItemProps(id, index, state),\n\t\t\tonMouseEnter: () => dispatch({ type: \"set\", index }),\n\t\t\tonMouseDown: (event: MouseEvent) => {\n\t\t\t\t// Keep input focus so selection isn't cancelled by blur.\n\t\t\t\tevent.preventDefault();\n\t\t\t\tonSelect?.(index);\n\t\t\t\tdispatch({ type: \"select\" });\n\t\t\t},\n\t\t}),\n\t\t[id, state, onSelect]\n\t);\n\n\treturn {\n\t\tisOpen: state.isOpen,\n\t\tactiveIndex: state.activeIndex,\n\t\topen,\n\t\tclose,\n\t\treset,\n\t\tsetActiveIndex,\n\t\tgetInputProps,\n\t\tgetListboxProps,\n\t\tgetItemProps,\n\t};\n}\n","import type { AddressSuggestion } from \"@wherabouts/sdk\";\n\n/**\n * Minimal structural view of the Web Storage API (sessionStorage/localStorage).\n * Declared locally so the package type-checks with no DOM lib.\n */\nexport interface StorageLike {\n\tgetItem(key: string): string | null;\n\tremoveItem(key: string): void;\n\tsetItem(key: string, value: string): void;\n}\n\nexport interface AutocompleteCacheKeyParts {\n\tcountry?: string;\n\tlat?: number;\n\tlimit?: number;\n\tlng?: number;\n\tq: string;\n\tstate?: string;\n}\n\nconst KEY_PREFIX = \"wh:ac:\";\n\n/**\n * Build a stable cache key from the query parameters. The query is trimmed and\n * lower-cased so cosmetic differences (\"George St\" vs \"george st\") share a\n * cache entry; coordinates and filters are included so proximity-boosted or\n * filtered searches never collide with unfiltered ones.\n */\nexport function buildCacheKey(parts: AutocompleteCacheKeyParts): string {\n\tconst q = parts.q.trim().toLowerCase();\n\treturn JSON.stringify([\n\t\tq,\n\t\tparts.country ?? \"\",\n\t\tparts.state ?? \"\",\n\t\tparts.limit ?? \"\",\n\t\tparts.lat ?? \"\",\n\t\tparts.lng ?? \"\",\n\t]);\n}\n\ninterface CacheEntry {\n\tresults: AddressSuggestion[];\n\tt: number;\n}\n\n/**\n * Read cached suggestions for `key`. Returns null on a miss, on corrupt data,\n * or when the entry is older than `ttlMs`; expired/corrupt entries are removed.\n */\nexport function readCache(\n\tstorage: StorageLike,\n\tkey: string,\n\tttlMs: number,\n\tnow: number\n): AddressSuggestion[] | null {\n\tconst raw = storage.getItem(KEY_PREFIX + key);\n\tif (raw === null) {\n\t\treturn null;\n\t}\n\tlet entry: CacheEntry;\n\ttry {\n\t\tentry = JSON.parse(raw) as CacheEntry;\n\t} catch {\n\t\tstorage.removeItem(KEY_PREFIX + key);\n\t\treturn null;\n\t}\n\tif (\n\t\ttypeof entry?.t !== \"number\" ||\n\t\t!Array.isArray(entry.results) ||\n\t\tnow - entry.t > ttlMs\n\t) {\n\t\tstorage.removeItem(KEY_PREFIX + key);\n\t\treturn null;\n\t}\n\treturn entry.results;\n}\n\n/** Store suggestions for `key`, stamped with `now` for TTL eviction on read. */\nexport function writeCache(\n\tstorage: StorageLike,\n\tkey: string,\n\tresults: AddressSuggestion[],\n\tnow: number\n): void {\n\tconst entry: CacheEntry = { results, t: now };\n\ttry {\n\t\tstorage.setItem(KEY_PREFIX + key, JSON.stringify(entry));\n\t} catch {\n\t\t// Storage full or unavailable (private mode/quota) — caching is best-effort.\n\t}\n}\n","import type {\n\tAddressSuggestion,\n\tAutocompleteParams,\n\tWheraboutsClient,\n} from \"@wherabouts/sdk\";\nimport { isRateLimitError } from \"@wherabouts/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n\ttype AutocompleteCacheKeyParts,\n\tbuildCacheKey,\n\treadCache,\n\ttype StorageLike,\n\twriteCache,\n} from \"./autocomplete-cache.ts\";\n\nconst DEFAULT_DEBOUNCE_MS = 300;\n/** API rejects `q` shorter than 2 chars; gate locally to avoid wasted 400s. */\nconst DEFAULT_MIN_LENGTH = 2;\nconst DEFAULT_CACHE_TTL_MS = 60_000;\n\nexport type AutocompleteStatus =\n\t| \"idle\"\n\t| \"loading\"\n\t| \"success\"\n\t| \"empty\"\n\t| \"error\";\n\n/** Opt-in client-side cache for repeated/back-and-forth queries. */\nexport interface AutocompleteCacheConfig {\n\t/** A `sessionStorage`-like store. Entries are namespaced under `wh:ac:`. */\n\tstorage: StorageLike;\n\t/** Entry lifetime in ms (default 60_000). */\n\tttlMs?: number;\n}\n\nexport interface UseAutocompleteOptions {\n\tcache?: AutocompleteCacheConfig;\n\tcountry?: string;\n\tdebounceMs?: number;\n\t/** Keep the previous results visible while a new search runs / on error. */\n\tkeepPreviousData?: boolean;\n\t/** Latitude for proximity boosting (pair with `lng`). */\n\tlat?: number;\n\tlimit?: number;\n\t/** Longitude for proximity boosting (pair with `lat`). */\n\tlng?: number;\n\t/** Minimum trimmed query length before a request fires (default 2). */\n\tminLength?: number;\n\t/** Groups keystrokes into one billable session; see `newSessionToken()`. */\n\tsessionToken?: string;\n\tstate?: string;\n}\n\nexport interface UseAutocompleteResult {\n\terror: Error | null;\n\tloading: boolean;\n\tquery: string;\n\t/** True when the last request was rejected with HTTP 429. */\n\trateLimited: boolean;\n\t/** Clear the query, results, and any in-flight request. */\n\treset: () => void;\n\tresults: AddressSuggestion[];\n\tsetQuery: (q: string) => void;\n\tstatus: AutocompleteStatus;\n}\n\n/**\n * Derive a single coarse status from the hook's raw flags. Exported for\n * unit-testing and for consumers who prefer a state machine to booleans.\n */\nexport function deriveStatus(s: {\n\terror: Error | null;\n\tloading: boolean;\n\tminLength: number;\n\tquery: string;\n\tresults: AddressSuggestion[];\n}): AutocompleteStatus {\n\tif (s.query.trim().length < s.minLength) {\n\t\treturn \"idle\";\n\t}\n\tif (s.loading) {\n\t\treturn \"loading\";\n\t}\n\tif (s.error) {\n\t\treturn \"error\";\n\t}\n\treturn s.results.length === 0 ? \"empty\" : \"success\";\n}\n\ntype SearchPlan =\n\t| { kind: \"idle\" }\n\t| { kind: \"cache\"; results: AddressSuggestion[] }\n\t| { kind: \"fetch\" };\n\n/** Decide whether to skip, serve from cache, or hit the network — pure. */\nfunction planSearch(args: {\n\tcacheStorage: StorageLike | undefined;\n\tcacheTtl: number;\n\tkeyParts: AutocompleteCacheKeyParts;\n\tminLength: number;\n\ttrimmed: string;\n}): SearchPlan {\n\tif (args.trimmed.length < args.minLength) {\n\t\treturn { kind: \"idle\" };\n\t}\n\tif (args.cacheStorage) {\n\t\tconst hit = readCache(\n\t\t\targs.cacheStorage,\n\t\t\tbuildCacheKey(args.keyParts),\n\t\t\targs.cacheTtl,\n\t\t\tDate.now()\n\t\t);\n\t\tif (hit) {\n\t\t\treturn { kind: \"cache\", results: hit };\n\t\t}\n\t}\n\treturn { kind: \"fetch\" };\n}\n\ninterface SearchActions {\n\tonError: (error: Error, rateLimited: boolean) => void;\n\tonSettled: () => void;\n\tonSuccess: (results: AddressSuggestion[]) => void;\n}\n\n/** Run one autocomplete request, routing the outcome through `actions`. */\nasync function executeAutocomplete(\n\tclient: WheraboutsClient,\n\tparams: AutocompleteParams,\n\tcontroller: AbortController,\n\tactions: SearchActions\n): Promise<void> {\n\ttry {\n\t\tconst res = await client.addresses.autocomplete(params, {\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tif (!controller.signal.aborted) {\n\t\t\tactions.onSuccess(res.results);\n\t\t}\n\t} catch (e) {\n\t\tif (!controller.signal.aborted) {\n\t\t\tconst err = e instanceof Error ? e : new Error(String(e));\n\t\t\tactions.onError(err, isRateLimitError(e));\n\t\t}\n\t} finally {\n\t\tif (!controller.signal.aborted) {\n\t\t\tactions.onSettled();\n\t\t}\n\t}\n}\n\nfunction cancelPending(\n\ttimer: ReturnType<typeof setTimeout> | null,\n\tcontroller: AbortController | null\n): void {\n\tif (timer) {\n\t\tclearTimeout(timer);\n\t}\n\tcontroller?.abort();\n}\n\nexport function useAutocomplete(\n\tclient: WheraboutsClient,\n\toptions: UseAutocompleteOptions = {}\n): UseAutocompleteResult {\n\tconst {\n\t\tdebounceMs = DEFAULT_DEBOUNCE_MS,\n\t\tminLength = DEFAULT_MIN_LENGTH,\n\t\tlimit,\n\t\tcountry,\n\t\tstate,\n\t\tlat,\n\t\tlng,\n\t\tsessionToken,\n\t\tkeepPreviousData = false,\n\t\tcache,\n\t} = options;\n\n\tconst [query, setQuery] = useState(\"\");\n\tconst [results, setResults] = useState<AddressSuggestion[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst [rateLimited, setRateLimited] = useState(false);\n\n\tconst abortRef = useRef<AbortController | null>(null);\n\tconst timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n\t// Stable setter — consumers can safely pass this to input onChange.\n\tconst handleSetQuery = useCallback((q: string) => {\n\t\tsetQuery(q);\n\t}, []);\n\n\tconst reset = useCallback(() => {\n\t\tcancelPending(timerRef.current, abortRef.current);\n\t\tsetQuery(\"\");\n\t\tsetResults([]);\n\t\tsetLoading(false);\n\t\tsetError(null);\n\t\tsetRateLimited(false);\n\t}, []);\n\n\tconst cacheStorage = cache?.storage;\n\tconst cacheTtl = cache?.ttlMs ?? DEFAULT_CACHE_TTL_MS;\n\n\tuseEffect(() => {\n\t\tcancelPending(timerRef.current, abortRef.current);\n\n\t\tconst trimmed = query.trim();\n\t\tconst keyParts: AutocompleteCacheKeyParts = {\n\t\t\tq: trimmed,\n\t\t\tcountry,\n\t\t\tstate,\n\t\t\tlimit,\n\t\t\tlat,\n\t\t\tlng,\n\t\t};\n\t\tconst plan = planSearch({\n\t\t\ttrimmed,\n\t\t\tminLength,\n\t\t\tcacheStorage,\n\t\t\tcacheTtl,\n\t\t\tkeyParts,\n\t\t});\n\n\t\tsetError(null);\n\t\tsetRateLimited(false);\n\n\t\tif (plan.kind === \"idle\") {\n\t\t\tif (!keepPreviousData) {\n\t\t\t\tsetResults([]);\n\t\t\t}\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\t\tif (plan.kind === \"cache\") {\n\t\t\tsetResults(plan.results);\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\n\t\t// Clear stale results as the new search starts unless asked to keep them\n\t\t// visible (keepPreviousData avoids dropdown flicker between keystrokes).\n\t\tif (!keepPreviousData) {\n\t\t\tsetResults([]);\n\t\t}\n\t\tsetLoading(true);\n\t\ttimerRef.current = setTimeout(async () => {\n\t\t\tconst controller = new AbortController();\n\t\t\tabortRef.current = controller;\n\t\t\tawait executeAutocomplete(\n\t\t\t\tclient,\n\t\t\t\t{ q: trimmed, limit, country, state, lat, lng, sessionToken },\n\t\t\t\tcontroller,\n\t\t\t\t{\n\t\t\t\t\tonSuccess: (r) => {\n\t\t\t\t\t\tsetResults(r);\n\t\t\t\t\t\tif (cacheStorage) {\n\t\t\t\t\t\t\twriteCache(cacheStorage, buildCacheKey(keyParts), r, Date.now());\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonError: (err, limited) => {\n\t\t\t\t\t\tsetError(err);\n\t\t\t\t\t\tsetRateLimited(limited);\n\t\t\t\t\t\tif (!keepPreviousData) {\n\t\t\t\t\t\t\tsetResults([]);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonSettled: () => setLoading(false),\n\t\t\t\t}\n\t\t\t);\n\t\t}, debounceMs);\n\n\t\treturn () => cancelPending(timerRef.current, abortRef.current);\n\t}, [\n\t\tquery,\n\t\tdebounceMs,\n\t\tminLength,\n\t\tlimit,\n\t\tcountry,\n\t\tstate,\n\t\tlat,\n\t\tlng,\n\t\tsessionToken,\n\t\tkeepPreviousData,\n\t\tcacheStorage,\n\t\tcacheTtl,\n\t\tclient,\n\t]);\n\n\tconst status = deriveStatus({ query, minLength, loading, error, results });\n\n\treturn {\n\t\tquery,\n\t\tsetQuery: handleSetQuery,\n\t\tresults,\n\t\tloading,\n\t\terror,\n\t\trateLimited,\n\t\treset,\n\t\tstatus,\n\t};\n}\n","import type { ReverseGeocodeAddress, WheraboutsClient } from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport interface LatLng {\n\tlat: number;\n\tlng: number;\n}\n\nexport interface UseReverseGeocodeResult {\n\taddress: ReverseGeocodeAddress | null;\n\tdistance: number | null;\n\terror: Error | null;\n\tloading: boolean;\n}\n\nexport function useReverseGeocode(\n\tclient: WheraboutsClient,\n\tcoords: LatLng | null\n): UseReverseGeocodeResult {\n\tconst [address, setAddress] = useState<ReverseGeocodeAddress | null>(null);\n\tconst [distance, setDistance] = useState<number | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\t// Depend on the primitive lat/lng rather than the coords object so the effect\n\t// re-runs only when the coordinates actually change, not on every new object\n\t// identity a caller may pass. Capturing these locals (not `coords`) also keeps\n\t// the dependency array exhaustive.\n\tconst lat = coords?.lat ?? null;\n\tconst lng = coords?.lng ?? null;\n\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (lat === null || lng === null) {\n\t\t\tsetAddress(null);\n\t\t\tsetDistance(null);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\tclient.addresses\n\t\t\t.reverse({ lat, lng }, { signal: controller.signal })\n\t\t\t.then((res) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetAddress(res.address);\n\t\t\t\t\tsetDistance(res.distance);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetLoading(false);\n\t\t\t\t}\n\t\t\t});\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t};\n\t}, [lat, lng, client]);\n\n\treturn { address, distance, loading, error };\n}\n","/** Minimal view of AbortSignal — only the `aborted` flag is needed here. */\nexport interface AbortLike {\n\taborted: boolean;\n}\n\nexport interface ResourceActions<T> {\n\tonError: (error: Error) => void;\n\tonSettled: () => void;\n\tonSuccess: (data: T) => void;\n}\n\n/**\n * Await `promise` and route the outcome through `actions`, skipping every\n * callback once `signal` is aborted (so a stale request can't clobber the\n * state of a newer one). Shared by the data-fetching hooks.\n */\nexport async function runResource<T>(\n\tpromise: Promise<T>,\n\tsignal: AbortLike,\n\tactions: ResourceActions<T>\n): Promise<void> {\n\ttry {\n\t\tconst data = await promise;\n\t\tif (!signal.aborted) {\n\t\t\tactions.onSuccess(data);\n\t\t}\n\t} catch (e) {\n\t\tif (!signal.aborted) {\n\t\t\tactions.onError(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t} finally {\n\t\tif (!signal.aborted) {\n\t\t\tactions.onSettled();\n\t\t}\n\t}\n}\n","import type {\n\tCallOptions,\n\tDirectionsParams,\n\tDirectionsResponse,\n\tIsochroneParams,\n\tIsochroneResponse,\n\tMatrixParams,\n\tMatrixResponse,\n\tWheraboutsClient,\n} from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { runResource } from \"./async-resource.ts\";\n\nexport interface RoutingResourceResult<T> {\n\tdata: T | null;\n\terror: Error | null;\n\tloading: boolean;\n}\n\ntype RoutingCall<P, R> = (\n\tclient: WheraboutsClient,\n\tparams: P,\n\toptions: CallOptions\n) => Promise<R>;\n\n/**\n * Shared effect skeleton for the routing hooks: fires `call` whenever the\n * (serialized) params change, aborts the previous request, and exposes\n * `{ data, loading, error }`. Pass `null` params to stay idle.\n */\nfunction useRoutingResource<P, R>(\n\tclient: WheraboutsClient,\n\tparams: P | null,\n\tcall: RoutingCall<P, R>\n): RoutingResourceResult<R> {\n\tconst [data, setData] = useState<R | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\t// Serialize params so stable values don't refire on every render.\n\tconst key = params ? JSON.stringify(params) : null;\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: `params` is tracked via its serialized `key`\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (!params) {\n\t\t\tsetData(null);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\trunResource(\n\t\t\tcall(client, params, { signal: controller.signal }),\n\t\t\tcontroller.signal,\n\t\t\t{\n\t\t\t\tonSuccess: setData,\n\t\t\t\tonError: setError,\n\t\t\t\tonSettled: () => setLoading(false),\n\t\t\t}\n\t\t);\n\n\t\treturn () => controller.abort();\n\t}, [key, client, call]);\n\n\treturn { data, loading, error };\n}\n\nconst directionsCall: RoutingCall<DirectionsParams, DirectionsResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.directions(params, options);\n\nconst matrixCall: RoutingCall<MatrixParams, MatrixResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.matrix(params, options);\n\nconst isochroneCall: RoutingCall<IsochroneParams, IsochroneResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.isochrone(params, options);\n\n/** Fetch turn-by-turn directions; pass `null` to stay idle. */\nexport function useDirections(\n\tclient: WheraboutsClient,\n\tparams: DirectionsParams | null\n): RoutingResourceResult<DirectionsResponse> {\n\treturn useRoutingResource(client, params, directionsCall);\n}\n\n/** Fetch a duration/distance matrix; pass `null` to stay idle. */\nexport function useMatrix(\n\tclient: WheraboutsClient,\n\tparams: MatrixParams | null\n): RoutingResourceResult<MatrixResponse> {\n\treturn useRoutingResource(client, params, matrixCall);\n}\n\n/** Fetch an isochrone polygon; pass `null` to stay idle. */\nexport function useIsochrone(\n\tclient: WheraboutsClient,\n\tparams: IsochroneParams | null\n): RoutingResourceResult<IsochroneResponse> {\n\treturn useRoutingResource(client, params, isochroneCall);\n}\n","import type { WheraboutsClient, ZoneRecord } from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport type { LatLng } from \"./use-reverse-geocode.ts\";\n\nexport interface UseZoneContainsResult {\n\terror: Error | null;\n\tloading: boolean;\n\tzones: ZoneRecord[];\n}\n\nexport function useZoneContains(\n\tclient: WheraboutsClient,\n\tcoords: LatLng | null\n): UseZoneContainsResult {\n\tconst [zones, setZones] = useState<ZoneRecord[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\t// Depend on the primitive lat/lng rather than the coords object so the effect\n\t// re-runs only when the coordinates actually change, not on every new object\n\t// identity a caller may pass. Capturing these locals (not `coords`) also keeps\n\t// the dependency array exhaustive.\n\tconst lat = coords?.lat ?? null;\n\tconst lng = coords?.lng ?? null;\n\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (lat === null || lng === null) {\n\t\t\tsetZones([]);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\tclient.zones\n\t\t\t.contains({ lat, lng }, { signal: controller.signal })\n\t\t\t.then((res) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetZones(res.zones);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetLoading(false);\n\t\t\t\t}\n\t\t\t});\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t};\n\t}, [lat, lng, client]);\n\n\treturn { zones, loading, error };\n}\n"]}
package/dist/index.js CHANGED
@@ -361,11 +361,13 @@ function useReverseGeocode(client, coords) {
361
361
  const [loading, setLoading] = useState(false);
362
362
  const [error, setError] = useState(null);
363
363
  const abortRef = useRef(null);
364
+ const lat = coords?.lat ?? null;
365
+ const lng = coords?.lng ?? null;
364
366
  useEffect(() => {
365
367
  if (abortRef.current) {
366
368
  abortRef.current.abort();
367
369
  }
368
- if (!coords) {
370
+ if (lat === null || lng === null) {
369
371
  setAddress(null);
370
372
  setDistance(null);
371
373
  setLoading(false);
@@ -376,7 +378,7 @@ function useReverseGeocode(client, coords) {
376
378
  abortRef.current = controller;
377
379
  setLoading(true);
378
380
  setError(null);
379
- client.addresses.reverse(coords, { signal: controller.signal }).then((res) => {
381
+ client.addresses.reverse({ lat, lng }, { signal: controller.signal }).then((res) => {
380
382
  if (!controller.signal.aborted) {
381
383
  setAddress(res.address);
382
384
  setDistance(res.distance);
@@ -393,7 +395,7 @@ function useReverseGeocode(client, coords) {
393
395
  return () => {
394
396
  controller.abort();
395
397
  };
396
- }, [coords?.lat, coords?.lng, client]);
398
+ }, [lat, lng, client]);
397
399
  return { address, distance, loading, error };
398
400
  }
399
401
 
@@ -466,11 +468,13 @@ function useZoneContains(client, coords) {
466
468
  const [loading, setLoading] = useState(false);
467
469
  const [error, setError] = useState(null);
468
470
  const abortRef = useRef(null);
471
+ const lat = coords?.lat ?? null;
472
+ const lng = coords?.lng ?? null;
469
473
  useEffect(() => {
470
474
  if (abortRef.current) {
471
475
  abortRef.current.abort();
472
476
  }
473
- if (!coords) {
477
+ if (lat === null || lng === null) {
474
478
  setZones([]);
475
479
  setLoading(false);
476
480
  setError(null);
@@ -480,7 +484,7 @@ function useZoneContains(client, coords) {
480
484
  abortRef.current = controller;
481
485
  setLoading(true);
482
486
  setError(null);
483
- client.zones.contains(coords, { signal: controller.signal }).then((res) => {
487
+ client.zones.contains({ lat, lng }, { signal: controller.signal }).then((res) => {
484
488
  if (!controller.signal.aborted) {
485
489
  setZones(res.zones);
486
490
  }
@@ -496,7 +500,7 @@ function useZoneContains(client, coords) {
496
500
  return () => {
497
501
  controller.abort();
498
502
  };
499
- }, [coords?.lat, coords?.lng, client]);
503
+ }, [lat, lng, client]);
500
504
  return { zones, loading, error };
501
505
  }
502
506
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/combobox.ts","../src/autocomplete-cache.ts","../src/use-autocomplete.ts","../src/use-reverse-geocode.ts","../src/async-resource.ts","../src/use-routing.ts","../src/use-zone-contains.ts"],"names":["useCallback","useState","useRef","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import {\n\ttype KeyboardEvent,\n\ttype MouseEvent,\n\tuseCallback,\n\tuseReducer,\n} from \"react\";\n\n/**\n * Headless WAI-ARIA combobox helper for autocomplete dropdowns. Provides the\n * keyboard state machine (↑/↓/Home/End/Enter/Esc, wrapping) and ARIA prop\n * getters so an input + listbox is accessible by default. Bring your own\n * markup and data; this hook owns only the open/active-option state.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/combobox/\n */\n\nexport interface ComboboxState {\n\t/** Index of the visually-active option, or -1 when none is active. */\n\tactiveIndex: number;\n\tisOpen: boolean;\n}\n\nexport type ComboboxAction =\n\t| { type: \"next\"; count: number }\n\t| { type: \"prev\"; count: number }\n\t| { type: \"first\"; count: number }\n\t| { type: \"last\"; count: number }\n\t| { type: \"set\"; index: number }\n\t| { type: \"open\" }\n\t| { type: \"close\" }\n\t| { type: \"select\" }\n\t| { type: \"reset\" };\n\nexport const INITIAL_COMBOBOX_STATE: ComboboxState = {\n\tisOpen: false,\n\tactiveIndex: -1,\n};\n\n/** Pure transition function for the combobox keyboard state machine. */\nexport function comboboxReducer(\n\tstate: ComboboxState,\n\taction: ComboboxAction\n): ComboboxState {\n\tswitch (action.type) {\n\t\tcase \"next\": {\n\t\t\tif (action.count === 0) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst activeIndex =\n\t\t\t\tstate.activeIndex >= action.count - 1 ? 0 : state.activeIndex + 1;\n\t\t\treturn { isOpen: true, activeIndex };\n\t\t}\n\t\tcase \"prev\": {\n\t\t\tif (action.count === 0) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst activeIndex =\n\t\t\t\tstate.activeIndex <= 0 ? action.count - 1 : state.activeIndex - 1;\n\t\t\treturn { isOpen: true, activeIndex };\n\t\t}\n\t\tcase \"first\":\n\t\t\treturn action.count === 0 ? state : { isOpen: true, activeIndex: 0 };\n\t\tcase \"last\":\n\t\t\treturn action.count === 0\n\t\t\t\t? state\n\t\t\t\t: { isOpen: true, activeIndex: action.count - 1 };\n\t\tcase \"set\":\n\t\t\treturn { isOpen: true, activeIndex: action.index };\n\t\tcase \"open\":\n\t\t\treturn { ...state, isOpen: true };\n\t\tcase \"close\":\n\t\tcase \"select\":\n\t\t\treturn INITIAL_COMBOBOX_STATE;\n\t\tdefault:\n\t\t\treturn INITIAL_COMBOBOX_STATE;\n\t}\n}\n\n/** Map a keyboard key to a combobox action, or null when it is irrelevant. */\nexport function keyToAction(key: string, count: number): ComboboxAction | null {\n\tswitch (key) {\n\t\tcase \"ArrowDown\":\n\t\t\treturn { type: \"next\", count };\n\t\tcase \"ArrowUp\":\n\t\t\treturn { type: \"prev\", count };\n\t\tcase \"Home\":\n\t\t\treturn { type: \"first\", count };\n\t\tcase \"End\":\n\t\t\treturn { type: \"last\", count };\n\t\tcase \"Escape\":\n\t\t\treturn { type: \"close\" };\n\t\tcase \"Enter\":\n\t\t\treturn { type: \"select\" };\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nexport interface ComboboxInputProps {\n\t\"aria-activedescendant\": string | undefined;\n\t\"aria-autocomplete\": \"list\";\n\t\"aria-controls\": string;\n\t\"aria-expanded\": boolean;\n\trole: \"combobox\";\n}\n\nexport interface ComboboxListboxProps {\n\tid: string;\n\trole: \"listbox\";\n}\n\nexport interface ComboboxItemProps {\n\t\"aria-selected\": boolean;\n\tid: string;\n\trole: \"option\";\n}\n\nconst listboxId = (id: string) => `${id}-listbox`;\nconst optionId = (id: string, index: number) => `${id}-option-${index}`;\n\n/** Build the ARIA attributes for the combobox input — pure. */\nexport function buildInputProps(\n\tid: string,\n\tstate: ComboboxState\n): ComboboxInputProps {\n\treturn {\n\t\trole: \"combobox\",\n\t\t\"aria-autocomplete\": \"list\",\n\t\t\"aria-expanded\": state.isOpen,\n\t\t\"aria-controls\": listboxId(id),\n\t\t\"aria-activedescendant\":\n\t\t\tstate.isOpen && state.activeIndex >= 0\n\t\t\t\t? optionId(id, state.activeIndex)\n\t\t\t\t: undefined,\n\t};\n}\n\n/** Build the ARIA attributes for the listbox container — pure. */\nexport function buildListboxProps(id: string): ComboboxListboxProps {\n\treturn { id: listboxId(id), role: \"listbox\" };\n}\n\n/** Build the ARIA attributes for an option at `index` — pure. */\nexport function buildItemProps(\n\tid: string,\n\tindex: number,\n\tstate: ComboboxState\n): ComboboxItemProps {\n\treturn {\n\t\trole: \"option\",\n\t\tid: optionId(id, index),\n\t\t\"aria-selected\": state.activeIndex === index,\n\t};\n}\n\nexport interface UseComboboxOptions {\n\t/** Number of options currently rendered (drives wrapping/bounds). */\n\tcount: number;\n\t/** Stable id root; option/listbox ids derive from it. */\n\tid: string;\n\t/** Called when an option is chosen via Enter or pointer. */\n\tonSelect?: (index: number) => void;\n}\n\nexport interface UseComboboxResult {\n\tactiveIndex: number;\n\tclose: () => void;\n\tgetInputProps: () => ComboboxInputProps & {\n\t\tonBlur: () => void;\n\t\tonFocus: () => void;\n\t\tonKeyDown: (event: KeyboardEvent) => void;\n\t};\n\tgetItemProps: (index: number) => ComboboxItemProps & {\n\t\tonMouseDown: (event: MouseEvent) => void;\n\t\tonMouseEnter: () => void;\n\t};\n\tgetListboxProps: () => ComboboxListboxProps;\n\tisOpen: boolean;\n\topen: () => void;\n\treset: () => void;\n\tsetActiveIndex: (index: number) => void;\n}\n\nexport function useCombobox(options: UseComboboxOptions): UseComboboxResult {\n\tconst { id, count, onSelect } = options;\n\tconst [state, dispatch] = useReducer(comboboxReducer, INITIAL_COMBOBOX_STATE);\n\n\tconst open = useCallback(() => dispatch({ type: \"open\" }), []);\n\tconst close = useCallback(() => dispatch({ type: \"close\" }), []);\n\tconst reset = useCallback(() => dispatch({ type: \"reset\" }), []);\n\tconst setActiveIndex = useCallback(\n\t\t(index: number) => dispatch({ type: \"set\", index }),\n\t\t[]\n\t);\n\n\tconst getInputProps = useCallback(\n\t\t() => ({\n\t\t\t...buildInputProps(id, state),\n\t\t\tonFocus: () => dispatch({ type: \"open\" }),\n\t\t\tonBlur: () => dispatch({ type: \"close\" }),\n\t\t\tonKeyDown: (event: KeyboardEvent) => {\n\t\t\t\tconst action = keyToAction(event.key, count);\n\t\t\t\tif (!action) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action.type === \"select\") {\n\t\t\t\t\tif (state.activeIndex >= 0) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tonSelect?.(state.activeIndex);\n\t\t\t\t\t}\n\t\t\t\t\tdispatch({ type: \"select\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tdispatch(action);\n\t\t\t},\n\t\t}),\n\t\t[id, state, count, onSelect]\n\t);\n\n\tconst getListboxProps = useCallback(() => buildListboxProps(id), [id]);\n\n\tconst getItemProps = useCallback(\n\t\t(index: number) => ({\n\t\t\t...buildItemProps(id, index, state),\n\t\t\tonMouseEnter: () => dispatch({ type: \"set\", index }),\n\t\t\tonMouseDown: (event: MouseEvent) => {\n\t\t\t\t// Keep input focus so selection isn't cancelled by blur.\n\t\t\t\tevent.preventDefault();\n\t\t\t\tonSelect?.(index);\n\t\t\t\tdispatch({ type: \"select\" });\n\t\t\t},\n\t\t}),\n\t\t[id, state, onSelect]\n\t);\n\n\treturn {\n\t\tisOpen: state.isOpen,\n\t\tactiveIndex: state.activeIndex,\n\t\topen,\n\t\tclose,\n\t\treset,\n\t\tsetActiveIndex,\n\t\tgetInputProps,\n\t\tgetListboxProps,\n\t\tgetItemProps,\n\t};\n}\n","import type { AddressSuggestion } from \"@wherabouts/sdk\";\n\n/**\n * Minimal structural view of the Web Storage API (sessionStorage/localStorage).\n * Declared locally so the package type-checks with no DOM lib.\n */\nexport interface StorageLike {\n\tgetItem(key: string): string | null;\n\tremoveItem(key: string): void;\n\tsetItem(key: string, value: string): void;\n}\n\nexport interface AutocompleteCacheKeyParts {\n\tcountry?: string;\n\tlat?: number;\n\tlimit?: number;\n\tlng?: number;\n\tq: string;\n\tstate?: string;\n}\n\nconst KEY_PREFIX = \"wh:ac:\";\n\n/**\n * Build a stable cache key from the query parameters. The query is trimmed and\n * lower-cased so cosmetic differences (\"George St\" vs \"george st\") share a\n * cache entry; coordinates and filters are included so proximity-boosted or\n * filtered searches never collide with unfiltered ones.\n */\nexport function buildCacheKey(parts: AutocompleteCacheKeyParts): string {\n\tconst q = parts.q.trim().toLowerCase();\n\treturn JSON.stringify([\n\t\tq,\n\t\tparts.country ?? \"\",\n\t\tparts.state ?? \"\",\n\t\tparts.limit ?? \"\",\n\t\tparts.lat ?? \"\",\n\t\tparts.lng ?? \"\",\n\t]);\n}\n\ninterface CacheEntry {\n\tresults: AddressSuggestion[];\n\tt: number;\n}\n\n/**\n * Read cached suggestions for `key`. Returns null on a miss, on corrupt data,\n * or when the entry is older than `ttlMs`; expired/corrupt entries are removed.\n */\nexport function readCache(\n\tstorage: StorageLike,\n\tkey: string,\n\tttlMs: number,\n\tnow: number\n): AddressSuggestion[] | null {\n\tconst raw = storage.getItem(KEY_PREFIX + key);\n\tif (raw === null) {\n\t\treturn null;\n\t}\n\tlet entry: CacheEntry;\n\ttry {\n\t\tentry = JSON.parse(raw) as CacheEntry;\n\t} catch {\n\t\tstorage.removeItem(KEY_PREFIX + key);\n\t\treturn null;\n\t}\n\tif (\n\t\ttypeof entry?.t !== \"number\" ||\n\t\t!Array.isArray(entry.results) ||\n\t\tnow - entry.t > ttlMs\n\t) {\n\t\tstorage.removeItem(KEY_PREFIX + key);\n\t\treturn null;\n\t}\n\treturn entry.results;\n}\n\n/** Store suggestions for `key`, stamped with `now` for TTL eviction on read. */\nexport function writeCache(\n\tstorage: StorageLike,\n\tkey: string,\n\tresults: AddressSuggestion[],\n\tnow: number\n): void {\n\tconst entry: CacheEntry = { results, t: now };\n\ttry {\n\t\tstorage.setItem(KEY_PREFIX + key, JSON.stringify(entry));\n\t} catch {\n\t\t// Storage full or unavailable (private mode/quota) — caching is best-effort.\n\t}\n}\n","import type {\n\tAddressSuggestion,\n\tAutocompleteParams,\n\tWheraboutsClient,\n} from \"@wherabouts/sdk\";\nimport { isRateLimitError } from \"@wherabouts/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n\ttype AutocompleteCacheKeyParts,\n\tbuildCacheKey,\n\treadCache,\n\ttype StorageLike,\n\twriteCache,\n} from \"./autocomplete-cache.ts\";\n\nconst DEFAULT_DEBOUNCE_MS = 300;\n/** API rejects `q` shorter than 2 chars; gate locally to avoid wasted 400s. */\nconst DEFAULT_MIN_LENGTH = 2;\nconst DEFAULT_CACHE_TTL_MS = 60_000;\n\nexport type AutocompleteStatus =\n\t| \"idle\"\n\t| \"loading\"\n\t| \"success\"\n\t| \"empty\"\n\t| \"error\";\n\n/** Opt-in client-side cache for repeated/back-and-forth queries. */\nexport interface AutocompleteCacheConfig {\n\t/** A `sessionStorage`-like store. Entries are namespaced under `wh:ac:`. */\n\tstorage: StorageLike;\n\t/** Entry lifetime in ms (default 60_000). */\n\tttlMs?: number;\n}\n\nexport interface UseAutocompleteOptions {\n\tcache?: AutocompleteCacheConfig;\n\tcountry?: string;\n\tdebounceMs?: number;\n\t/** Keep the previous results visible while a new search runs / on error. */\n\tkeepPreviousData?: boolean;\n\t/** Latitude for proximity boosting (pair with `lng`). */\n\tlat?: number;\n\tlimit?: number;\n\t/** Longitude for proximity boosting (pair with `lat`). */\n\tlng?: number;\n\t/** Minimum trimmed query length before a request fires (default 2). */\n\tminLength?: number;\n\t/** Groups keystrokes into one billable session; see `newSessionToken()`. */\n\tsessionToken?: string;\n\tstate?: string;\n}\n\nexport interface UseAutocompleteResult {\n\terror: Error | null;\n\tloading: boolean;\n\tquery: string;\n\t/** True when the last request was rejected with HTTP 429. */\n\trateLimited: boolean;\n\t/** Clear the query, results, and any in-flight request. */\n\treset: () => void;\n\tresults: AddressSuggestion[];\n\tsetQuery: (q: string) => void;\n\tstatus: AutocompleteStatus;\n}\n\n/**\n * Derive a single coarse status from the hook's raw flags. Exported for\n * unit-testing and for consumers who prefer a state machine to booleans.\n */\nexport function deriveStatus(s: {\n\terror: Error | null;\n\tloading: boolean;\n\tminLength: number;\n\tquery: string;\n\tresults: AddressSuggestion[];\n}): AutocompleteStatus {\n\tif (s.query.trim().length < s.minLength) {\n\t\treturn \"idle\";\n\t}\n\tif (s.loading) {\n\t\treturn \"loading\";\n\t}\n\tif (s.error) {\n\t\treturn \"error\";\n\t}\n\treturn s.results.length === 0 ? \"empty\" : \"success\";\n}\n\ntype SearchPlan =\n\t| { kind: \"idle\" }\n\t| { kind: \"cache\"; results: AddressSuggestion[] }\n\t| { kind: \"fetch\" };\n\n/** Decide whether to skip, serve from cache, or hit the network — pure. */\nfunction planSearch(args: {\n\tcacheStorage: StorageLike | undefined;\n\tcacheTtl: number;\n\tkeyParts: AutocompleteCacheKeyParts;\n\tminLength: number;\n\ttrimmed: string;\n}): SearchPlan {\n\tif (args.trimmed.length < args.minLength) {\n\t\treturn { kind: \"idle\" };\n\t}\n\tif (args.cacheStorage) {\n\t\tconst hit = readCache(\n\t\t\targs.cacheStorage,\n\t\t\tbuildCacheKey(args.keyParts),\n\t\t\targs.cacheTtl,\n\t\t\tDate.now()\n\t\t);\n\t\tif (hit) {\n\t\t\treturn { kind: \"cache\", results: hit };\n\t\t}\n\t}\n\treturn { kind: \"fetch\" };\n}\n\ninterface SearchActions {\n\tonError: (error: Error, rateLimited: boolean) => void;\n\tonSettled: () => void;\n\tonSuccess: (results: AddressSuggestion[]) => void;\n}\n\n/** Run one autocomplete request, routing the outcome through `actions`. */\nasync function executeAutocomplete(\n\tclient: WheraboutsClient,\n\tparams: AutocompleteParams,\n\tcontroller: AbortController,\n\tactions: SearchActions\n): Promise<void> {\n\ttry {\n\t\tconst res = await client.addresses.autocomplete(params, {\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tif (!controller.signal.aborted) {\n\t\t\tactions.onSuccess(res.results);\n\t\t}\n\t} catch (e) {\n\t\tif (!controller.signal.aborted) {\n\t\t\tconst err = e instanceof Error ? e : new Error(String(e));\n\t\t\tactions.onError(err, isRateLimitError(e));\n\t\t}\n\t} finally {\n\t\tif (!controller.signal.aborted) {\n\t\t\tactions.onSettled();\n\t\t}\n\t}\n}\n\nfunction cancelPending(\n\ttimer: ReturnType<typeof setTimeout> | null,\n\tcontroller: AbortController | null\n): void {\n\tif (timer) {\n\t\tclearTimeout(timer);\n\t}\n\tcontroller?.abort();\n}\n\nexport function useAutocomplete(\n\tclient: WheraboutsClient,\n\toptions: UseAutocompleteOptions = {}\n): UseAutocompleteResult {\n\tconst {\n\t\tdebounceMs = DEFAULT_DEBOUNCE_MS,\n\t\tminLength = DEFAULT_MIN_LENGTH,\n\t\tlimit,\n\t\tcountry,\n\t\tstate,\n\t\tlat,\n\t\tlng,\n\t\tsessionToken,\n\t\tkeepPreviousData = false,\n\t\tcache,\n\t} = options;\n\n\tconst [query, setQuery] = useState(\"\");\n\tconst [results, setResults] = useState<AddressSuggestion[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst [rateLimited, setRateLimited] = useState(false);\n\n\tconst abortRef = useRef<AbortController | null>(null);\n\tconst timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n\t// Stable setter — consumers can safely pass this to input onChange.\n\tconst handleSetQuery = useCallback((q: string) => {\n\t\tsetQuery(q);\n\t}, []);\n\n\tconst reset = useCallback(() => {\n\t\tcancelPending(timerRef.current, abortRef.current);\n\t\tsetQuery(\"\");\n\t\tsetResults([]);\n\t\tsetLoading(false);\n\t\tsetError(null);\n\t\tsetRateLimited(false);\n\t}, []);\n\n\tconst cacheStorage = cache?.storage;\n\tconst cacheTtl = cache?.ttlMs ?? DEFAULT_CACHE_TTL_MS;\n\n\tuseEffect(() => {\n\t\tcancelPending(timerRef.current, abortRef.current);\n\n\t\tconst trimmed = query.trim();\n\t\tconst keyParts: AutocompleteCacheKeyParts = {\n\t\t\tq: trimmed,\n\t\t\tcountry,\n\t\t\tstate,\n\t\t\tlimit,\n\t\t\tlat,\n\t\t\tlng,\n\t\t};\n\t\tconst plan = planSearch({\n\t\t\ttrimmed,\n\t\t\tminLength,\n\t\t\tcacheStorage,\n\t\t\tcacheTtl,\n\t\t\tkeyParts,\n\t\t});\n\n\t\tsetError(null);\n\t\tsetRateLimited(false);\n\n\t\tif (plan.kind === \"idle\") {\n\t\t\tif (!keepPreviousData) {\n\t\t\t\tsetResults([]);\n\t\t\t}\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\t\tif (plan.kind === \"cache\") {\n\t\t\tsetResults(plan.results);\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\n\t\t// Clear stale results as the new search starts unless asked to keep them\n\t\t// visible (keepPreviousData avoids dropdown flicker between keystrokes).\n\t\tif (!keepPreviousData) {\n\t\t\tsetResults([]);\n\t\t}\n\t\tsetLoading(true);\n\t\ttimerRef.current = setTimeout(async () => {\n\t\t\tconst controller = new AbortController();\n\t\t\tabortRef.current = controller;\n\t\t\tawait executeAutocomplete(\n\t\t\t\tclient,\n\t\t\t\t{ q: trimmed, limit, country, state, lat, lng, sessionToken },\n\t\t\t\tcontroller,\n\t\t\t\t{\n\t\t\t\t\tonSuccess: (r) => {\n\t\t\t\t\t\tsetResults(r);\n\t\t\t\t\t\tif (cacheStorage) {\n\t\t\t\t\t\t\twriteCache(cacheStorage, buildCacheKey(keyParts), r, Date.now());\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonError: (err, limited) => {\n\t\t\t\t\t\tsetError(err);\n\t\t\t\t\t\tsetRateLimited(limited);\n\t\t\t\t\t\tif (!keepPreviousData) {\n\t\t\t\t\t\t\tsetResults([]);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonSettled: () => setLoading(false),\n\t\t\t\t}\n\t\t\t);\n\t\t}, debounceMs);\n\n\t\treturn () => cancelPending(timerRef.current, abortRef.current);\n\t}, [\n\t\tquery,\n\t\tdebounceMs,\n\t\tminLength,\n\t\tlimit,\n\t\tcountry,\n\t\tstate,\n\t\tlat,\n\t\tlng,\n\t\tsessionToken,\n\t\tkeepPreviousData,\n\t\tcacheStorage,\n\t\tcacheTtl,\n\t\tclient,\n\t]);\n\n\tconst status = deriveStatus({ query, minLength, loading, error, results });\n\n\treturn {\n\t\tquery,\n\t\tsetQuery: handleSetQuery,\n\t\tresults,\n\t\tloading,\n\t\terror,\n\t\trateLimited,\n\t\treset,\n\t\tstatus,\n\t};\n}\n","import type { ReverseGeocodeAddress, WheraboutsClient } from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport interface LatLng {\n\tlat: number;\n\tlng: number;\n}\n\nexport interface UseReverseGeocodeResult {\n\taddress: ReverseGeocodeAddress | null;\n\tdistance: number | null;\n\terror: Error | null;\n\tloading: boolean;\n}\n\nexport function useReverseGeocode(\n\tclient: WheraboutsClient,\n\tcoords: LatLng | null\n): UseReverseGeocodeResult {\n\tconst [address, setAddress] = useState<ReverseGeocodeAddress | null>(null);\n\tconst [distance, setDistance] = useState<number | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (!coords) {\n\t\t\tsetAddress(null);\n\t\t\tsetDistance(null);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\tclient.addresses\n\t\t\t.reverse(coords, { signal: controller.signal })\n\t\t\t.then((res) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetAddress(res.address);\n\t\t\t\t\tsetDistance(res.distance);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetLoading(false);\n\t\t\t\t}\n\t\t\t});\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t};\n\t}, [coords?.lat, coords?.lng, client]);\n\n\treturn { address, distance, loading, error };\n}\n","/** Minimal view of AbortSignal — only the `aborted` flag is needed here. */\nexport interface AbortLike {\n\taborted: boolean;\n}\n\nexport interface ResourceActions<T> {\n\tonError: (error: Error) => void;\n\tonSettled: () => void;\n\tonSuccess: (data: T) => void;\n}\n\n/**\n * Await `promise` and route the outcome through `actions`, skipping every\n * callback once `signal` is aborted (so a stale request can't clobber the\n * state of a newer one). Shared by the data-fetching hooks.\n */\nexport async function runResource<T>(\n\tpromise: Promise<T>,\n\tsignal: AbortLike,\n\tactions: ResourceActions<T>\n): Promise<void> {\n\ttry {\n\t\tconst data = await promise;\n\t\tif (!signal.aborted) {\n\t\t\tactions.onSuccess(data);\n\t\t}\n\t} catch (e) {\n\t\tif (!signal.aborted) {\n\t\t\tactions.onError(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t} finally {\n\t\tif (!signal.aborted) {\n\t\t\tactions.onSettled();\n\t\t}\n\t}\n}\n","import type {\n\tCallOptions,\n\tDirectionsParams,\n\tDirectionsResponse,\n\tIsochroneParams,\n\tIsochroneResponse,\n\tMatrixParams,\n\tMatrixResponse,\n\tWheraboutsClient,\n} from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { runResource } from \"./async-resource.ts\";\n\nexport interface RoutingResourceResult<T> {\n\tdata: T | null;\n\terror: Error | null;\n\tloading: boolean;\n}\n\ntype RoutingCall<P, R> = (\n\tclient: WheraboutsClient,\n\tparams: P,\n\toptions: CallOptions\n) => Promise<R>;\n\n/**\n * Shared effect skeleton for the routing hooks: fires `call` whenever the\n * (serialized) params change, aborts the previous request, and exposes\n * `{ data, loading, error }`. Pass `null` params to stay idle.\n */\nfunction useRoutingResource<P, R>(\n\tclient: WheraboutsClient,\n\tparams: P | null,\n\tcall: RoutingCall<P, R>\n): RoutingResourceResult<R> {\n\tconst [data, setData] = useState<R | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\t// Serialize params so stable values don't refire on every render.\n\tconst key = params ? JSON.stringify(params) : null;\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: `params` is tracked via its serialized `key`\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (!params) {\n\t\t\tsetData(null);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\trunResource(\n\t\t\tcall(client, params, { signal: controller.signal }),\n\t\t\tcontroller.signal,\n\t\t\t{\n\t\t\t\tonSuccess: setData,\n\t\t\t\tonError: setError,\n\t\t\t\tonSettled: () => setLoading(false),\n\t\t\t}\n\t\t);\n\n\t\treturn () => controller.abort();\n\t}, [key, client, call]);\n\n\treturn { data, loading, error };\n}\n\nconst directionsCall: RoutingCall<DirectionsParams, DirectionsResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.directions(params, options);\n\nconst matrixCall: RoutingCall<MatrixParams, MatrixResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.matrix(params, options);\n\nconst isochroneCall: RoutingCall<IsochroneParams, IsochroneResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.isochrone(params, options);\n\n/** Fetch turn-by-turn directions; pass `null` to stay idle. */\nexport function useDirections(\n\tclient: WheraboutsClient,\n\tparams: DirectionsParams | null\n): RoutingResourceResult<DirectionsResponse> {\n\treturn useRoutingResource(client, params, directionsCall);\n}\n\n/** Fetch a duration/distance matrix; pass `null` to stay idle. */\nexport function useMatrix(\n\tclient: WheraboutsClient,\n\tparams: MatrixParams | null\n): RoutingResourceResult<MatrixResponse> {\n\treturn useRoutingResource(client, params, matrixCall);\n}\n\n/** Fetch an isochrone polygon; pass `null` to stay idle. */\nexport function useIsochrone(\n\tclient: WheraboutsClient,\n\tparams: IsochroneParams | null\n): RoutingResourceResult<IsochroneResponse> {\n\treturn useRoutingResource(client, params, isochroneCall);\n}\n","import type { WheraboutsClient, ZoneRecord } from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport type { LatLng } from \"./use-reverse-geocode.ts\";\n\nexport interface UseZoneContainsResult {\n\terror: Error | null;\n\tloading: boolean;\n\tzones: ZoneRecord[];\n}\n\nexport function useZoneContains(\n\tclient: WheraboutsClient,\n\tcoords: LatLng | null\n): UseZoneContainsResult {\n\tconst [zones, setZones] = useState<ZoneRecord[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (!coords) {\n\t\t\tsetZones([]);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\tclient.zones\n\t\t\t.contains(coords, { signal: controller.signal })\n\t\t\t.then((res) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetZones(res.zones);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetLoading(false);\n\t\t\t\t}\n\t\t\t});\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t};\n\t}, [coords?.lat, coords?.lng, client]);\n\n\treturn { zones, loading, error };\n}\n"]}
1
+ {"version":3,"sources":["../src/combobox.ts","../src/autocomplete-cache.ts","../src/use-autocomplete.ts","../src/use-reverse-geocode.ts","../src/async-resource.ts","../src/use-routing.ts","../src/use-zone-contains.ts"],"names":["useCallback","useState","useRef","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import {\n\ttype KeyboardEvent,\n\ttype MouseEvent,\n\tuseCallback,\n\tuseReducer,\n} from \"react\";\n\n/**\n * Headless WAI-ARIA combobox helper for autocomplete dropdowns. Provides the\n * keyboard state machine (↑/↓/Home/End/Enter/Esc, wrapping) and ARIA prop\n * getters so an input + listbox is accessible by default. Bring your own\n * markup and data; this hook owns only the open/active-option state.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/combobox/\n */\n\nexport interface ComboboxState {\n\t/** Index of the visually-active option, or -1 when none is active. */\n\tactiveIndex: number;\n\tisOpen: boolean;\n}\n\nexport type ComboboxAction =\n\t| { type: \"next\"; count: number }\n\t| { type: \"prev\"; count: number }\n\t| { type: \"first\"; count: number }\n\t| { type: \"last\"; count: number }\n\t| { type: \"set\"; index: number }\n\t| { type: \"open\" }\n\t| { type: \"close\" }\n\t| { type: \"select\" }\n\t| { type: \"reset\" };\n\nexport const INITIAL_COMBOBOX_STATE: ComboboxState = {\n\tisOpen: false,\n\tactiveIndex: -1,\n};\n\n/** Pure transition function for the combobox keyboard state machine. */\nexport function comboboxReducer(\n\tstate: ComboboxState,\n\taction: ComboboxAction\n): ComboboxState {\n\tswitch (action.type) {\n\t\tcase \"next\": {\n\t\t\tif (action.count === 0) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst activeIndex =\n\t\t\t\tstate.activeIndex >= action.count - 1 ? 0 : state.activeIndex + 1;\n\t\t\treturn { isOpen: true, activeIndex };\n\t\t}\n\t\tcase \"prev\": {\n\t\t\tif (action.count === 0) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst activeIndex =\n\t\t\t\tstate.activeIndex <= 0 ? action.count - 1 : state.activeIndex - 1;\n\t\t\treturn { isOpen: true, activeIndex };\n\t\t}\n\t\tcase \"first\":\n\t\t\treturn action.count === 0 ? state : { isOpen: true, activeIndex: 0 };\n\t\tcase \"last\":\n\t\t\treturn action.count === 0\n\t\t\t\t? state\n\t\t\t\t: { isOpen: true, activeIndex: action.count - 1 };\n\t\tcase \"set\":\n\t\t\treturn { isOpen: true, activeIndex: action.index };\n\t\tcase \"open\":\n\t\t\treturn { ...state, isOpen: true };\n\t\tcase \"close\":\n\t\tcase \"select\":\n\t\t\treturn INITIAL_COMBOBOX_STATE;\n\t\tdefault:\n\t\t\treturn INITIAL_COMBOBOX_STATE;\n\t}\n}\n\n/** Map a keyboard key to a combobox action, or null when it is irrelevant. */\nexport function keyToAction(key: string, count: number): ComboboxAction | null {\n\tswitch (key) {\n\t\tcase \"ArrowDown\":\n\t\t\treturn { type: \"next\", count };\n\t\tcase \"ArrowUp\":\n\t\t\treturn { type: \"prev\", count };\n\t\tcase \"Home\":\n\t\t\treturn { type: \"first\", count };\n\t\tcase \"End\":\n\t\t\treturn { type: \"last\", count };\n\t\tcase \"Escape\":\n\t\t\treturn { type: \"close\" };\n\t\tcase \"Enter\":\n\t\t\treturn { type: \"select\" };\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nexport interface ComboboxInputProps {\n\t\"aria-activedescendant\": string | undefined;\n\t\"aria-autocomplete\": \"list\";\n\t\"aria-controls\": string;\n\t\"aria-expanded\": boolean;\n\trole: \"combobox\";\n}\n\nexport interface ComboboxListboxProps {\n\tid: string;\n\trole: \"listbox\";\n}\n\nexport interface ComboboxItemProps {\n\t\"aria-selected\": boolean;\n\tid: string;\n\trole: \"option\";\n}\n\nconst listboxId = (id: string) => `${id}-listbox`;\nconst optionId = (id: string, index: number) => `${id}-option-${index}`;\n\n/** Build the ARIA attributes for the combobox input — pure. */\nexport function buildInputProps(\n\tid: string,\n\tstate: ComboboxState\n): ComboboxInputProps {\n\treturn {\n\t\trole: \"combobox\",\n\t\t\"aria-autocomplete\": \"list\",\n\t\t\"aria-expanded\": state.isOpen,\n\t\t\"aria-controls\": listboxId(id),\n\t\t\"aria-activedescendant\":\n\t\t\tstate.isOpen && state.activeIndex >= 0\n\t\t\t\t? optionId(id, state.activeIndex)\n\t\t\t\t: undefined,\n\t};\n}\n\n/** Build the ARIA attributes for the listbox container — pure. */\nexport function buildListboxProps(id: string): ComboboxListboxProps {\n\treturn { id: listboxId(id), role: \"listbox\" };\n}\n\n/** Build the ARIA attributes for an option at `index` — pure. */\nexport function buildItemProps(\n\tid: string,\n\tindex: number,\n\tstate: ComboboxState\n): ComboboxItemProps {\n\treturn {\n\t\trole: \"option\",\n\t\tid: optionId(id, index),\n\t\t\"aria-selected\": state.activeIndex === index,\n\t};\n}\n\nexport interface UseComboboxOptions {\n\t/** Number of options currently rendered (drives wrapping/bounds). */\n\tcount: number;\n\t/** Stable id root; option/listbox ids derive from it. */\n\tid: string;\n\t/** Called when an option is chosen via Enter or pointer. */\n\tonSelect?: (index: number) => void;\n}\n\nexport interface UseComboboxResult {\n\tactiveIndex: number;\n\tclose: () => void;\n\tgetInputProps: () => ComboboxInputProps & {\n\t\tonBlur: () => void;\n\t\tonFocus: () => void;\n\t\tonKeyDown: (event: KeyboardEvent) => void;\n\t};\n\tgetItemProps: (index: number) => ComboboxItemProps & {\n\t\tonMouseDown: (event: MouseEvent) => void;\n\t\tonMouseEnter: () => void;\n\t};\n\tgetListboxProps: () => ComboboxListboxProps;\n\tisOpen: boolean;\n\topen: () => void;\n\treset: () => void;\n\tsetActiveIndex: (index: number) => void;\n}\n\nexport function useCombobox(options: UseComboboxOptions): UseComboboxResult {\n\tconst { id, count, onSelect } = options;\n\tconst [state, dispatch] = useReducer(comboboxReducer, INITIAL_COMBOBOX_STATE);\n\n\tconst open = useCallback(() => dispatch({ type: \"open\" }), []);\n\tconst close = useCallback(() => dispatch({ type: \"close\" }), []);\n\tconst reset = useCallback(() => dispatch({ type: \"reset\" }), []);\n\tconst setActiveIndex = useCallback(\n\t\t(index: number) => dispatch({ type: \"set\", index }),\n\t\t[]\n\t);\n\n\tconst getInputProps = useCallback(\n\t\t() => ({\n\t\t\t...buildInputProps(id, state),\n\t\t\tonFocus: () => dispatch({ type: \"open\" }),\n\t\t\tonBlur: () => dispatch({ type: \"close\" }),\n\t\t\tonKeyDown: (event: KeyboardEvent) => {\n\t\t\t\tconst action = keyToAction(event.key, count);\n\t\t\t\tif (!action) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action.type === \"select\") {\n\t\t\t\t\tif (state.activeIndex >= 0) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tonSelect?.(state.activeIndex);\n\t\t\t\t\t}\n\t\t\t\t\tdispatch({ type: \"select\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tdispatch(action);\n\t\t\t},\n\t\t}),\n\t\t[id, state, count, onSelect]\n\t);\n\n\tconst getListboxProps = useCallback(() => buildListboxProps(id), [id]);\n\n\tconst getItemProps = useCallback(\n\t\t(index: number) => ({\n\t\t\t...buildItemProps(id, index, state),\n\t\t\tonMouseEnter: () => dispatch({ type: \"set\", index }),\n\t\t\tonMouseDown: (event: MouseEvent) => {\n\t\t\t\t// Keep input focus so selection isn't cancelled by blur.\n\t\t\t\tevent.preventDefault();\n\t\t\t\tonSelect?.(index);\n\t\t\t\tdispatch({ type: \"select\" });\n\t\t\t},\n\t\t}),\n\t\t[id, state, onSelect]\n\t);\n\n\treturn {\n\t\tisOpen: state.isOpen,\n\t\tactiveIndex: state.activeIndex,\n\t\topen,\n\t\tclose,\n\t\treset,\n\t\tsetActiveIndex,\n\t\tgetInputProps,\n\t\tgetListboxProps,\n\t\tgetItemProps,\n\t};\n}\n","import type { AddressSuggestion } from \"@wherabouts/sdk\";\n\n/**\n * Minimal structural view of the Web Storage API (sessionStorage/localStorage).\n * Declared locally so the package type-checks with no DOM lib.\n */\nexport interface StorageLike {\n\tgetItem(key: string): string | null;\n\tremoveItem(key: string): void;\n\tsetItem(key: string, value: string): void;\n}\n\nexport interface AutocompleteCacheKeyParts {\n\tcountry?: string;\n\tlat?: number;\n\tlimit?: number;\n\tlng?: number;\n\tq: string;\n\tstate?: string;\n}\n\nconst KEY_PREFIX = \"wh:ac:\";\n\n/**\n * Build a stable cache key from the query parameters. The query is trimmed and\n * lower-cased so cosmetic differences (\"George St\" vs \"george st\") share a\n * cache entry; coordinates and filters are included so proximity-boosted or\n * filtered searches never collide with unfiltered ones.\n */\nexport function buildCacheKey(parts: AutocompleteCacheKeyParts): string {\n\tconst q = parts.q.trim().toLowerCase();\n\treturn JSON.stringify([\n\t\tq,\n\t\tparts.country ?? \"\",\n\t\tparts.state ?? \"\",\n\t\tparts.limit ?? \"\",\n\t\tparts.lat ?? \"\",\n\t\tparts.lng ?? \"\",\n\t]);\n}\n\ninterface CacheEntry {\n\tresults: AddressSuggestion[];\n\tt: number;\n}\n\n/**\n * Read cached suggestions for `key`. Returns null on a miss, on corrupt data,\n * or when the entry is older than `ttlMs`; expired/corrupt entries are removed.\n */\nexport function readCache(\n\tstorage: StorageLike,\n\tkey: string,\n\tttlMs: number,\n\tnow: number\n): AddressSuggestion[] | null {\n\tconst raw = storage.getItem(KEY_PREFIX + key);\n\tif (raw === null) {\n\t\treturn null;\n\t}\n\tlet entry: CacheEntry;\n\ttry {\n\t\tentry = JSON.parse(raw) as CacheEntry;\n\t} catch {\n\t\tstorage.removeItem(KEY_PREFIX + key);\n\t\treturn null;\n\t}\n\tif (\n\t\ttypeof entry?.t !== \"number\" ||\n\t\t!Array.isArray(entry.results) ||\n\t\tnow - entry.t > ttlMs\n\t) {\n\t\tstorage.removeItem(KEY_PREFIX + key);\n\t\treturn null;\n\t}\n\treturn entry.results;\n}\n\n/** Store suggestions for `key`, stamped with `now` for TTL eviction on read. */\nexport function writeCache(\n\tstorage: StorageLike,\n\tkey: string,\n\tresults: AddressSuggestion[],\n\tnow: number\n): void {\n\tconst entry: CacheEntry = { results, t: now };\n\ttry {\n\t\tstorage.setItem(KEY_PREFIX + key, JSON.stringify(entry));\n\t} catch {\n\t\t// Storage full or unavailable (private mode/quota) — caching is best-effort.\n\t}\n}\n","import type {\n\tAddressSuggestion,\n\tAutocompleteParams,\n\tWheraboutsClient,\n} from \"@wherabouts/sdk\";\nimport { isRateLimitError } from \"@wherabouts/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n\ttype AutocompleteCacheKeyParts,\n\tbuildCacheKey,\n\treadCache,\n\ttype StorageLike,\n\twriteCache,\n} from \"./autocomplete-cache.ts\";\n\nconst DEFAULT_DEBOUNCE_MS = 300;\n/** API rejects `q` shorter than 2 chars; gate locally to avoid wasted 400s. */\nconst DEFAULT_MIN_LENGTH = 2;\nconst DEFAULT_CACHE_TTL_MS = 60_000;\n\nexport type AutocompleteStatus =\n\t| \"idle\"\n\t| \"loading\"\n\t| \"success\"\n\t| \"empty\"\n\t| \"error\";\n\n/** Opt-in client-side cache for repeated/back-and-forth queries. */\nexport interface AutocompleteCacheConfig {\n\t/** A `sessionStorage`-like store. Entries are namespaced under `wh:ac:`. */\n\tstorage: StorageLike;\n\t/** Entry lifetime in ms (default 60_000). */\n\tttlMs?: number;\n}\n\nexport interface UseAutocompleteOptions {\n\tcache?: AutocompleteCacheConfig;\n\tcountry?: string;\n\tdebounceMs?: number;\n\t/** Keep the previous results visible while a new search runs / on error. */\n\tkeepPreviousData?: boolean;\n\t/** Latitude for proximity boosting (pair with `lng`). */\n\tlat?: number;\n\tlimit?: number;\n\t/** Longitude for proximity boosting (pair with `lat`). */\n\tlng?: number;\n\t/** Minimum trimmed query length before a request fires (default 2). */\n\tminLength?: number;\n\t/** Groups keystrokes into one billable session; see `newSessionToken()`. */\n\tsessionToken?: string;\n\tstate?: string;\n}\n\nexport interface UseAutocompleteResult {\n\terror: Error | null;\n\tloading: boolean;\n\tquery: string;\n\t/** True when the last request was rejected with HTTP 429. */\n\trateLimited: boolean;\n\t/** Clear the query, results, and any in-flight request. */\n\treset: () => void;\n\tresults: AddressSuggestion[];\n\tsetQuery: (q: string) => void;\n\tstatus: AutocompleteStatus;\n}\n\n/**\n * Derive a single coarse status from the hook's raw flags. Exported for\n * unit-testing and for consumers who prefer a state machine to booleans.\n */\nexport function deriveStatus(s: {\n\terror: Error | null;\n\tloading: boolean;\n\tminLength: number;\n\tquery: string;\n\tresults: AddressSuggestion[];\n}): AutocompleteStatus {\n\tif (s.query.trim().length < s.minLength) {\n\t\treturn \"idle\";\n\t}\n\tif (s.loading) {\n\t\treturn \"loading\";\n\t}\n\tif (s.error) {\n\t\treturn \"error\";\n\t}\n\treturn s.results.length === 0 ? \"empty\" : \"success\";\n}\n\ntype SearchPlan =\n\t| { kind: \"idle\" }\n\t| { kind: \"cache\"; results: AddressSuggestion[] }\n\t| { kind: \"fetch\" };\n\n/** Decide whether to skip, serve from cache, or hit the network — pure. */\nfunction planSearch(args: {\n\tcacheStorage: StorageLike | undefined;\n\tcacheTtl: number;\n\tkeyParts: AutocompleteCacheKeyParts;\n\tminLength: number;\n\ttrimmed: string;\n}): SearchPlan {\n\tif (args.trimmed.length < args.minLength) {\n\t\treturn { kind: \"idle\" };\n\t}\n\tif (args.cacheStorage) {\n\t\tconst hit = readCache(\n\t\t\targs.cacheStorage,\n\t\t\tbuildCacheKey(args.keyParts),\n\t\t\targs.cacheTtl,\n\t\t\tDate.now()\n\t\t);\n\t\tif (hit) {\n\t\t\treturn { kind: \"cache\", results: hit };\n\t\t}\n\t}\n\treturn { kind: \"fetch\" };\n}\n\ninterface SearchActions {\n\tonError: (error: Error, rateLimited: boolean) => void;\n\tonSettled: () => void;\n\tonSuccess: (results: AddressSuggestion[]) => void;\n}\n\n/** Run one autocomplete request, routing the outcome through `actions`. */\nasync function executeAutocomplete(\n\tclient: WheraboutsClient,\n\tparams: AutocompleteParams,\n\tcontroller: AbortController,\n\tactions: SearchActions\n): Promise<void> {\n\ttry {\n\t\tconst res = await client.addresses.autocomplete(params, {\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tif (!controller.signal.aborted) {\n\t\t\tactions.onSuccess(res.results);\n\t\t}\n\t} catch (e) {\n\t\tif (!controller.signal.aborted) {\n\t\t\tconst err = e instanceof Error ? e : new Error(String(e));\n\t\t\tactions.onError(err, isRateLimitError(e));\n\t\t}\n\t} finally {\n\t\tif (!controller.signal.aborted) {\n\t\t\tactions.onSettled();\n\t\t}\n\t}\n}\n\nfunction cancelPending(\n\ttimer: ReturnType<typeof setTimeout> | null,\n\tcontroller: AbortController | null\n): void {\n\tif (timer) {\n\t\tclearTimeout(timer);\n\t}\n\tcontroller?.abort();\n}\n\nexport function useAutocomplete(\n\tclient: WheraboutsClient,\n\toptions: UseAutocompleteOptions = {}\n): UseAutocompleteResult {\n\tconst {\n\t\tdebounceMs = DEFAULT_DEBOUNCE_MS,\n\t\tminLength = DEFAULT_MIN_LENGTH,\n\t\tlimit,\n\t\tcountry,\n\t\tstate,\n\t\tlat,\n\t\tlng,\n\t\tsessionToken,\n\t\tkeepPreviousData = false,\n\t\tcache,\n\t} = options;\n\n\tconst [query, setQuery] = useState(\"\");\n\tconst [results, setResults] = useState<AddressSuggestion[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst [rateLimited, setRateLimited] = useState(false);\n\n\tconst abortRef = useRef<AbortController | null>(null);\n\tconst timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n\t// Stable setter — consumers can safely pass this to input onChange.\n\tconst handleSetQuery = useCallback((q: string) => {\n\t\tsetQuery(q);\n\t}, []);\n\n\tconst reset = useCallback(() => {\n\t\tcancelPending(timerRef.current, abortRef.current);\n\t\tsetQuery(\"\");\n\t\tsetResults([]);\n\t\tsetLoading(false);\n\t\tsetError(null);\n\t\tsetRateLimited(false);\n\t}, []);\n\n\tconst cacheStorage = cache?.storage;\n\tconst cacheTtl = cache?.ttlMs ?? DEFAULT_CACHE_TTL_MS;\n\n\tuseEffect(() => {\n\t\tcancelPending(timerRef.current, abortRef.current);\n\n\t\tconst trimmed = query.trim();\n\t\tconst keyParts: AutocompleteCacheKeyParts = {\n\t\t\tq: trimmed,\n\t\t\tcountry,\n\t\t\tstate,\n\t\t\tlimit,\n\t\t\tlat,\n\t\t\tlng,\n\t\t};\n\t\tconst plan = planSearch({\n\t\t\ttrimmed,\n\t\t\tminLength,\n\t\t\tcacheStorage,\n\t\t\tcacheTtl,\n\t\t\tkeyParts,\n\t\t});\n\n\t\tsetError(null);\n\t\tsetRateLimited(false);\n\n\t\tif (plan.kind === \"idle\") {\n\t\t\tif (!keepPreviousData) {\n\t\t\t\tsetResults([]);\n\t\t\t}\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\t\tif (plan.kind === \"cache\") {\n\t\t\tsetResults(plan.results);\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\n\t\t// Clear stale results as the new search starts unless asked to keep them\n\t\t// visible (keepPreviousData avoids dropdown flicker between keystrokes).\n\t\tif (!keepPreviousData) {\n\t\t\tsetResults([]);\n\t\t}\n\t\tsetLoading(true);\n\t\ttimerRef.current = setTimeout(async () => {\n\t\t\tconst controller = new AbortController();\n\t\t\tabortRef.current = controller;\n\t\t\tawait executeAutocomplete(\n\t\t\t\tclient,\n\t\t\t\t{ q: trimmed, limit, country, state, lat, lng, sessionToken },\n\t\t\t\tcontroller,\n\t\t\t\t{\n\t\t\t\t\tonSuccess: (r) => {\n\t\t\t\t\t\tsetResults(r);\n\t\t\t\t\t\tif (cacheStorage) {\n\t\t\t\t\t\t\twriteCache(cacheStorage, buildCacheKey(keyParts), r, Date.now());\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonError: (err, limited) => {\n\t\t\t\t\t\tsetError(err);\n\t\t\t\t\t\tsetRateLimited(limited);\n\t\t\t\t\t\tif (!keepPreviousData) {\n\t\t\t\t\t\t\tsetResults([]);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonSettled: () => setLoading(false),\n\t\t\t\t}\n\t\t\t);\n\t\t}, debounceMs);\n\n\t\treturn () => cancelPending(timerRef.current, abortRef.current);\n\t}, [\n\t\tquery,\n\t\tdebounceMs,\n\t\tminLength,\n\t\tlimit,\n\t\tcountry,\n\t\tstate,\n\t\tlat,\n\t\tlng,\n\t\tsessionToken,\n\t\tkeepPreviousData,\n\t\tcacheStorage,\n\t\tcacheTtl,\n\t\tclient,\n\t]);\n\n\tconst status = deriveStatus({ query, minLength, loading, error, results });\n\n\treturn {\n\t\tquery,\n\t\tsetQuery: handleSetQuery,\n\t\tresults,\n\t\tloading,\n\t\terror,\n\t\trateLimited,\n\t\treset,\n\t\tstatus,\n\t};\n}\n","import type { ReverseGeocodeAddress, WheraboutsClient } from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport interface LatLng {\n\tlat: number;\n\tlng: number;\n}\n\nexport interface UseReverseGeocodeResult {\n\taddress: ReverseGeocodeAddress | null;\n\tdistance: number | null;\n\terror: Error | null;\n\tloading: boolean;\n}\n\nexport function useReverseGeocode(\n\tclient: WheraboutsClient,\n\tcoords: LatLng | null\n): UseReverseGeocodeResult {\n\tconst [address, setAddress] = useState<ReverseGeocodeAddress | null>(null);\n\tconst [distance, setDistance] = useState<number | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\t// Depend on the primitive lat/lng rather than the coords object so the effect\n\t// re-runs only when the coordinates actually change, not on every new object\n\t// identity a caller may pass. Capturing these locals (not `coords`) also keeps\n\t// the dependency array exhaustive.\n\tconst lat = coords?.lat ?? null;\n\tconst lng = coords?.lng ?? null;\n\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (lat === null || lng === null) {\n\t\t\tsetAddress(null);\n\t\t\tsetDistance(null);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\tclient.addresses\n\t\t\t.reverse({ lat, lng }, { signal: controller.signal })\n\t\t\t.then((res) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetAddress(res.address);\n\t\t\t\t\tsetDistance(res.distance);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetLoading(false);\n\t\t\t\t}\n\t\t\t});\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t};\n\t}, [lat, lng, client]);\n\n\treturn { address, distance, loading, error };\n}\n","/** Minimal view of AbortSignal — only the `aborted` flag is needed here. */\nexport interface AbortLike {\n\taborted: boolean;\n}\n\nexport interface ResourceActions<T> {\n\tonError: (error: Error) => void;\n\tonSettled: () => void;\n\tonSuccess: (data: T) => void;\n}\n\n/**\n * Await `promise` and route the outcome through `actions`, skipping every\n * callback once `signal` is aborted (so a stale request can't clobber the\n * state of a newer one). Shared by the data-fetching hooks.\n */\nexport async function runResource<T>(\n\tpromise: Promise<T>,\n\tsignal: AbortLike,\n\tactions: ResourceActions<T>\n): Promise<void> {\n\ttry {\n\t\tconst data = await promise;\n\t\tif (!signal.aborted) {\n\t\t\tactions.onSuccess(data);\n\t\t}\n\t} catch (e) {\n\t\tif (!signal.aborted) {\n\t\t\tactions.onError(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t} finally {\n\t\tif (!signal.aborted) {\n\t\t\tactions.onSettled();\n\t\t}\n\t}\n}\n","import type {\n\tCallOptions,\n\tDirectionsParams,\n\tDirectionsResponse,\n\tIsochroneParams,\n\tIsochroneResponse,\n\tMatrixParams,\n\tMatrixResponse,\n\tWheraboutsClient,\n} from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { runResource } from \"./async-resource.ts\";\n\nexport interface RoutingResourceResult<T> {\n\tdata: T | null;\n\terror: Error | null;\n\tloading: boolean;\n}\n\ntype RoutingCall<P, R> = (\n\tclient: WheraboutsClient,\n\tparams: P,\n\toptions: CallOptions\n) => Promise<R>;\n\n/**\n * Shared effect skeleton for the routing hooks: fires `call` whenever the\n * (serialized) params change, aborts the previous request, and exposes\n * `{ data, loading, error }`. Pass `null` params to stay idle.\n */\nfunction useRoutingResource<P, R>(\n\tclient: WheraboutsClient,\n\tparams: P | null,\n\tcall: RoutingCall<P, R>\n): RoutingResourceResult<R> {\n\tconst [data, setData] = useState<R | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\t// Serialize params so stable values don't refire on every render.\n\tconst key = params ? JSON.stringify(params) : null;\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: `params` is tracked via its serialized `key`\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (!params) {\n\t\t\tsetData(null);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\trunResource(\n\t\t\tcall(client, params, { signal: controller.signal }),\n\t\t\tcontroller.signal,\n\t\t\t{\n\t\t\t\tonSuccess: setData,\n\t\t\t\tonError: setError,\n\t\t\t\tonSettled: () => setLoading(false),\n\t\t\t}\n\t\t);\n\n\t\treturn () => controller.abort();\n\t}, [key, client, call]);\n\n\treturn { data, loading, error };\n}\n\nconst directionsCall: RoutingCall<DirectionsParams, DirectionsResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.directions(params, options);\n\nconst matrixCall: RoutingCall<MatrixParams, MatrixResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.matrix(params, options);\n\nconst isochroneCall: RoutingCall<IsochroneParams, IsochroneResponse> = (\n\tclient,\n\tparams,\n\toptions\n) => client.routing.isochrone(params, options);\n\n/** Fetch turn-by-turn directions; pass `null` to stay idle. */\nexport function useDirections(\n\tclient: WheraboutsClient,\n\tparams: DirectionsParams | null\n): RoutingResourceResult<DirectionsResponse> {\n\treturn useRoutingResource(client, params, directionsCall);\n}\n\n/** Fetch a duration/distance matrix; pass `null` to stay idle. */\nexport function useMatrix(\n\tclient: WheraboutsClient,\n\tparams: MatrixParams | null\n): RoutingResourceResult<MatrixResponse> {\n\treturn useRoutingResource(client, params, matrixCall);\n}\n\n/** Fetch an isochrone polygon; pass `null` to stay idle. */\nexport function useIsochrone(\n\tclient: WheraboutsClient,\n\tparams: IsochroneParams | null\n): RoutingResourceResult<IsochroneResponse> {\n\treturn useRoutingResource(client, params, isochroneCall);\n}\n","import type { WheraboutsClient, ZoneRecord } from \"@wherabouts/sdk\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport type { LatLng } from \"./use-reverse-geocode.ts\";\n\nexport interface UseZoneContainsResult {\n\terror: Error | null;\n\tloading: boolean;\n\tzones: ZoneRecord[];\n}\n\nexport function useZoneContains(\n\tclient: WheraboutsClient,\n\tcoords: LatLng | null\n): UseZoneContainsResult {\n\tconst [zones, setZones] = useState<ZoneRecord[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst abortRef = useRef<AbortController | null>(null);\n\n\t// Depend on the primitive lat/lng rather than the coords object so the effect\n\t// re-runs only when the coordinates actually change, not on every new object\n\t// identity a caller may pass. Capturing these locals (not `coords`) also keeps\n\t// the dependency array exhaustive.\n\tconst lat = coords?.lat ?? null;\n\tconst lng = coords?.lng ?? null;\n\n\tuseEffect(() => {\n\t\tif (abortRef.current) {\n\t\t\tabortRef.current.abort();\n\t\t}\n\n\t\tif (lat === null || lng === null) {\n\t\t\tsetZones([]);\n\t\t\tsetLoading(false);\n\t\t\tsetError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tabortRef.current = controller;\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\tclient.zones\n\t\t\t.contains({ lat, lng }, { signal: controller.signal })\n\t\t\t.then((res) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetZones(res.zones);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\tsetLoading(false);\n\t\t\t\t}\n\t\t\t});\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t};\n\t}, [lat, lng, client]);\n\n\treturn { zones, loading, error };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wherabouts/react",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "React hooks for the Wherabouts location API",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,17 +37,16 @@
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/react": "^19",
40
- "@wherabouts.com/config": "workspace:*",
41
- "react": "catalog:",
42
- "@wherabouts/sdk": "workspace:*",
40
+ "react": "^19.2.3",
43
41
  "tsup": "^8.5.1",
44
42
  "typescript": "^5",
45
- "vitest": "^4.1.4"
43
+ "vitest": "^4.1.4",
44
+ "@wherabouts.com/config": "0.0.0",
45
+ "@wherabouts/sdk": "0.6.0"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "tsup",
49
49
  "check-types": "tsc --noEmit",
50
- "test": "vitest run",
51
- "prepublishOnly": "pnpm build"
50
+ "test": "vitest run"
52
51
  }
53
- }
52
+ }