@evanion/urn
@evanion/urn 2.1.0 and its patch releases up to 2.1.1, the version on npm. Values on this page were produced by running the source at f9b1d93, a later commit than the 2.1.0 tag, and are not re-executed.
Eliminate identifier ambiguity with RFC-compliant Universal Resource Names.
A bare 42 in a message does not say whether it names a game or an order. @evanion/urn writes and reads Uniform Resource Names (URNs), identifiers that carry their own context: urn:game:42 is a game and urn:order:42 is an order.
The Problem: The “Ambiguous ID” Trap
In systems that integrate multiple data sources, simple IDs like 123 are a liability. You cannot tell if 123 refers to a user, a product, or a transaction without knowing the external context. This leads to “type confusion,” where a product ID is accidentally treated as a user ID, or “collision risks,” where two different entities share the same numeric identifier.
Uniform Resource Names solve this by embedding the context directly into the identifier. Instead of passing a raw ID and a separate “type” flag, you pass a single string like urn:game:brass-birmingham. This makes your identifiers self-describing and safe to pass across service boundaries.
How @evanion/urn works
@evanion/urn reads a URN with parse, which returns its three primary parts: urn (the scheme), nid (the namespace identifier), and nss (the namespace-specific string). stringify joins these parts back into a single URN.
To manage different namespaces, you create a namespace class—a subclass of URN that sets a static nid property. For example, in a board game shop, a GameURN class would set nid to 'game'.
.('urn:game:brass-birmingham'); // -> { urn: 'urn', nid: 'game', nss: 'brass-birmingham' }The URN vocabulary
Every page in this section uses the following terms to describe the parts of a URN, such as urn:game:brass-birmingham?=edition=2018.
- Scheme: The first part, always
urnper RFC 8141 . - Namespace Identifier (NID): The second part (
game), which defines the kind of resource being named. - Namespace-Specific String (NSS): The third part (
brass-birmingham), which uniquely identifies the resource within that namespace. - Component: An optional tail after the NSS.
- r-component (
?+): Parameters for the service resolving the URN. - q-component (
?=): Parameters for the resource itself (e.g., an edition). - f-component (
#): A specific fragment or section within the resource.
- r-component (
- Namespace Class: A subclass of
URN(likeGameURN) that defines thenidand optional separators. - Foreign URN: A URN whose scheme or NID differs from the class being used to parse it. If
GameURNparsesurn:order:42, theorder:42part remains together in thenss.
Core capabilities
| Goal | Tool |
|---|---|
| Create a URN from an ID | stringify (on a namespace class or URN) |
| Split a URN into its parts | parse |
| Verify if a URN is in a specific namespace | belongsToNamespace or sameNamespace |
| Get the raw ID regardless of namespace | extractId |
| Screen a string without throwing | isValidFormat |
| Handle malformed input | ValidationError and InvalidError |
| Attach metadata (editions, sections) | q- and f-components |
| Safe encoding for titles | encodeNss and decodeNss |
| Compare two URNs | equals (RFC 8141 §3.1 equivalence) |
Design constraints
To maintain technical rigor and prevent common bugs, @evanion/urn explicitly avoids four behaviors:
- No automatic normalization:
parsepreserves the original case. Useequalsfor case-insensitive comparison. - No implicit encoding:
stringifythrows on literal spaces. You must useencodeNssexplicitly beforestringifywill accept such an NSS. - No deduplication: If an ID already contains a
:, it is preserved as part of the NSS to avoid losing data. - No resolution: The library names resources; it does not fetch them from a database.
Get started with your own namespace
To start minting URNs, you only need a namespace class and the basic parse/stringify model. Getting started shows you how to install the package and declare your first GameURN class.