Component · for humans & their agents
Address Normalize
verified · first-partyactively maintained$0 during beta (was $79)
A fuzzy match scores "123 Main St E" and "123 Main St W" as near-identical -- one character apart, and two different streets half a mile apart. The merge is destructive: the losing record's data is gone.
by Code Recycle
Every claim on this page is refundable if it is untrue — refund policy.
Verified: 111 tests
Normalizes US street addresses to USPS Publication 28 conventions and compares two addresses as SAME, DIFFERENT or UNKNOWN, with a reason that names which component decided it.
Normalizes US street addresses to USPS Publication 28 conventions and compares two addresses as SAME, DIFFERENT or UNKNOWN, with a reason that names which component decided it.
THE SILENT FAILURE. Address matching is usually done one of two ways, and both are quietly wrong in opposite directions, and neither errors when it is wrong.
STRING EQUALITY CREATES DUPLICATES. '123 N Main St Apt 4' and '123 North Main Street #4' are the same physical mailbox and are not equal as strings, so a customer or an account gets created twice. Nothing throws; the duplicate surfaces months later because one copy got the invoice and the other got the notice.
FUZZY MATCHING DESTROYS DATA. '123 Main St E' and '123 Main St W' differ by one character and score as near-identical under a fuzzy ratio -- and are two different streets half a mile apart. A fuzzy merge silently combines two customers' records, and the merge is destructive: the losing record's data is gone. This library never computes an edit distance; addresses are parsed into structured fields first, and only the field that actually differs is compared.
THE ONE-SIDED UNIT. '500 Oak Ave Apt 12B' versus '500 Oak Ave' is not a match and not a non-match -- it is genuinely unknown whether the second record omitted the apartment number or really is the whole building's address. Answering that as a boolean is guessing, and whichever way it guesses is silently wrong some fraction of the time. This library's answer is a third value, UNKNOWN, and that is the point of the product, not a failure mode of it.
A TRAILING CITY WAS SILENTLY ABSORBED. An earlier version of this library accepted '123 Main St, Springfield' as valid, absorbing the city into the street name and setting the suffix and postdirectional to null -- then reported a confident DIFFERENT against the same address written with its city, on the most ordinary input shape there is: a caller who has not split line1 from city perfectly. The comma is now treated as structure: everything after it must be a complete secondary unit, or the input is refused by name.
VERIFIED: 111 tests, re-measured by running the suite, 6 deliberate defects applied to compareAddresses — 4 caught, 2 measured provably equivalent (houseNumber and boxNumber are always strings, so loose vs strict equality cannot differ for them; the proof ships in mutations.json)
DELIVERY: signed download of a hash-verified tarball, immediately on purchase. Permissive licence: unlimited products, unlimited clients, unlimited seats, no attribution, perpetual and irrevocable. One restriction, do not republish the source as source.
Interface
What you call, and what comes back. Types and signatures only — the implementation ships with the source.
export function compareAddresses(rawA: string, rawB: string): ComparisonResult;
export function normalizeAddress(input: string): NormalizeResult;
export function parseAddress(input: string): ParseResult; export type NormalizeResult = NormalizeSuccess | Exclude<ParseResult, { ok: true }>;
export type Directional = 'N' | 'S' | 'E' | 'W' | 'NE' | 'NW' | 'SE' | 'SW';
export type SecondaryDesignator = string;
export type ParsedAddress = StreetAddress | PoBoxAddress;
export type ParseResult = ParseSuccess | ParseFailure;
export type Verdict = 'SAME' | 'DIFFERENT' | 'UNKNOWN';01Capabilities
Does
- + Input validation
- + Entity resolution
Doesn’t
- No exclusions declared
02Requirements & stack
Depends on
No declared dependencies
Credentials needed
None declared
Stack
03Community
No endorsements yetNo verified confirmations yet — be the first.
Confirmations come from verified purchasers, installers, vetted reviewers, or an installation outcome your org reported through the agent tools. They grade quality — security is verified separately, and community votes can never override the security gate.
Sign in to confirm — weight comes from verified usage, not vote count.
Issues 1
Open an issue0 open · 0 answered · 0 fixed · 1 said it worked
- closedWorked for me — 111/111 vitest on Node 26.0.0, macOS 26.4Worked for me
04Trust Passport
Full passport →0/0 automated components pass. An automated score is never a security guarantee.
- publisher identity Publisher status verified; 1 verification(s) on file
- malicious pattern scan No known malicious-behavior patterns across 19 source file(s) plus listing text
- capability contract All 0 observed capability reference(s) match the declared manifest
- agent safety scan No injection patterns in agent-readable content
- provenance No release signature or provenance attestation
- behavioral sandbox Not performed in this environment — requires the production isolated runner (docs/sandbox-requirements.md). No untrusted code is ever executed on the application host.
Every listing must pass this review before it can be sold, and it is re-run on every release. Verification describes what we checked — it is not a guarantee that the software is safe.
05Versions
Full history →| Version | Channel | Released | Notes |
|---|---|---|---|
| 1.0.0 | stable | Aug 5, 2026 | First public release. |