@namedone/autocomplete
v0.4.0
Published
Client SDK for the Name Done autocomplete API — lightning-fast name, address, and school lookups.
Maintainers
Readme
@namedone/autocomplete
Client SDK for the Name Done autocomplete API. Lightning-fast autocomplete for first names, last names, full names, formal names (title + name), schools, streets, addresses, UK postcodes, railway stations, airports, towns, wards, parishes, local authorities, and parliamentary constituencies.
Name Done is a commercial autocomplete API service with a free tier — sign up at auth.namedone.com/signup to get an API key.
- 📋 Pricing — free tier with 10,000 tokens/month
- 📖 API docs
- 📊 Data sources
- 🔑 Get an API key
Addresses use a smart autocomplete that strips leading numbers from the query, searches streets (optionally filtered by postcode), then prepends the numbers back onto the results.
Install
npm install @namedone/autocomplete
@namedone/tokenis included as a dependency — token caching is handled automatically.
Usage
Simplest
import { createClient } from "@namedone/autocomplete";
const nd = createClient("nd_...");
const { results } = await nd.firstNames("jo");
// → [{ id: "first-name-0", text: "Jonathan", type: "first-name" }, ...]One-shot
import { search } from "@namedone/autocomplete";
const { results } = await search("nd_...", "first-name", "jo");Full names
Combine first and last names into a single "Full name" field (no server endpoint — the SDK calls first-name and last-name in parallel):
// Single word → interleaves first and last names
const { results } = await nd.fullNames("jo");
// → [{ text: "John" }, { text: "Jones" }, { text: "Joseph" }, ...]
// Two words → combines first + last
const { results } = await nd.fullNames("john s");
// → [{ text: "John Smith" }, { text: "John Stevens" }, ...]Formal names
Title + name combinations with pattern control:
const { results } = await nd.formalNames("mr j");
// → [{ text: "Mr Jones" }, { text: "Mr Johnson" }, ...]
// Restrict to title + surname only (e.g. teacher fields)
const { results } = await nd.formalNames("mr j", { pattern: "title-last" });Convenience methods
| Method | Type |
|---|---|
| titles(query) | title |
| formalNames(query, opts?) | formal-name (SDK orchestrates formal-name + first-name/last-name/town) |
| fullNames(query, opts?) | full-name (SDK combines first-name + last-name — no server endpoint) |
| firstNames(query) | first-name |
| lastNames(query) | last-name |
| schools(query) | school |
| streets(query) | street |
| streetsInPostcode(postcode, query) | street (postcode-filtered) |
| addresses(query, opts?) | street (smart address autocomplete) |
| postcodes(query) | postcode |
| railwayStations(query) | railway-station |
| airports(query) | airport |
| towns(query) | town |
| wards(query) | ward |
| parishes(query) | parish |
| localAuthorities(query) | local-authority |
| constituencies(query) | constituency |
Generic search
const { results } = await nd.search("school", "st", { limit: 20 });Proximity sorting
Sort results by distance to one or more coordinate pairs (e.g. a previously selected postcode):
// Sort schools by proximity to a postcode's coordinates
const { results } = await nd.schools("st", {
sortByProximity: [{ lat: 51.5074, lng: -0.1278 }],
});
// Multiple origins — each result is sorted by its nearest origin
const { results } = await nd.railwayStations("lon", {
sortByProximity: [
{ lat: 51.5074, lng: -0.1278 }, // London
{ lat: 53.4808, lng: -2.2426 }, // Manchester
],
});Results without data.lat/data.lng are sorted to the end, preserving their original relative order. Sorting happens before simple mode and limit, so it works correctly even when simple strips data from the output.
Advanced — bring your own token
import { AutocompleteClient } from "@namedone/autocomplete";
const client = new AutocompleteClient({ token: "<jwt>" });API
createClient(apiKey) / createClient(opts)
Creates an AutocompleteClient with automatic token caching.
search(apiKey, type, query, opts?)
One-shot query. Reuses a module-level singleton client for token caching.
AutocompleteClient
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | — | API key (handles tokens automatically) |
| token | string | — | Static JWT (advanced) |
| tokenProvider | () => Promise<string> | — | Async function returning a JWT (advanced) |
| baseUrl | string | https://autocomplete.namedone.com | Autocomplete API base URL |
| tokenBaseUrl | string | https://token.namedone.com | Token API base URL |
| fetch | typeof fetch | global fetch | Custom fetch implementation |
| timeoutMs | number | 10000 | Request timeout |
| maxRetries | number | 2 | Max retry attempts on transient failures |
| retryDelayMs | number | 400 | Base delay for exponential backoff |
Error handling
All non-2xx responses and network failures are thrown as AutocompleteApiError:
import { AutocompleteApiError } from "@namedone/autocomplete";
try {
const { results } = await nd.firstNames("jo");
} catch (err) {
if (err instanceof AutocompleteApiError) {
console.log(err.statusCode); // 0 = network/timeout, 4xx/5xx = HTTP
console.log(err.code); // "network_error", "timeout", or server message
console.log(err.retryAfterMs); // ms from Retry-After header (429), if present
}
}Automatic retries — the client retries transient failures (network errors, timeouts, and HTTP 408, 425, 429, 500, 502, 503, 504) up to maxRetries times with exponential backoff + jitter. When the server provides a Retry-After header (e.g. on 429), that value is used instead of the backoff. Non-retryable errors (400, 401, 403, 404, etc.) are thrown immediately.
// Disable retries for a latency-sensitive use case
const nd = createClient({ apiKey: "nd_...", maxRetries: 0 });
// More aggressive retry for a background job
const nd = createClient({ apiKey: "nd_...", maxRetries: 5, retryDelayMs: 1000 });Links
License
MIT
