npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wildboar/or-address

v1.0.0

Published

X.400 Message Handling System (MHS) O/R Address in TypeScript

Readme

X.400 Message Handling Service O/R Address Type

TypeScript implementation of the X.400 Message Handling System (MHS) originator/recipient address (ORAddress) from ITU-T X.411 / X.402, as used in PKI and PMI (PkiPmiExternalDataTypes). The library prints addresses in IETF RFC 1685 labelled form and IETF RFC 2156 MIXER std-or-address form, and encodes them as ASN.1.

These libraries were generated entirely or in part by the ASN.1 Compilation Service offered by Wildboar Software. The ASN.1 compiler itself is closed-source and proprietary, but some of the libraries produced with it are released publicly under the MIT license.

If you would like to see additional ASN.1 libraries in TypeScript or other programming languages, or if you have any other questions, please contact us at [email protected].

Usage

There is no whole-address equality method. X.400 does not define a single, unambiguous comparison of complete O/R addresses (printable vs teletex vs universal encodings, “any ADMD”, missing initials, and so on). Compare the parts you care about instead; see Comparing parts.

Creating an O/R address from a string

ORAddress.fromString parses a complete address. It defaults to IETF RFC 1685 labelled form (semicolon-separated label=value pairs). A doubled ;; is a literal semicolon in a value. Pass { rfc: 2156 } for MIXER IETF RFC 2156 std-or-address form. Parsing returns null when the string is not a valid address.

const address = ORAddress.fromString(
    "G=Jonathan;I=M;S=Wilbur;O=Wildboar Software;A=123;C=US",
)!;

address.built_in_standard_attributes.personal_name?.surname; // "Wilbur"
address.built_in_standard_attributes.organization_name;      // "Wildboar Software"
address.built_in_standard_attributes.administration_domain_name;
// { numeric: "123" }
address.built_in_standard_attributes.country_name;
// { iso_3166_alpha2_code: "US" }

const mixer = ORAddress.fromString(
    "/G=Andy/S=Wharol/O=MMNY/ADMD=ATT/C=US/",
    { rfc: 2156 },
)!;
mixer.toRFC2156String();
// "/G=Andy/S=Wharol/O=MMNY/ADMD=ATT/C=US/"

BuiltInStandardAttributes.fromString parses the same RFC 1685 syntax but returns only the built-in standard attributes (domain-defined and extension attributes are dropped). PersonalName.fromString parses the personal-name fragment (G=…;I=…;S=…;Q=…). PersonalName.fromRFC2156String parses a MIXER encoded personal name (Marshall.M.T.Rose). BuiltInDomainDefinedAttribute.fromString parses a single DDA:type=value pair.

Creating an O/R address from constructors

PersonalName is (surname, given_name?, initials?, generation_qualifier?). Country is a choice of ISO 3166-1 alpha-2 or an X.121 data country code. ADMD and PRMD are a choice of numeric or printable string. A single-space ADMD is the X.400 “any ADMD” value (ITU-T X.402 (1999), §18.3.1).

Organizational unit names are stored most-significant first (OU1, then OU2, …). RFC 1685 and RFC 2156 string forms list them in reverse.

const personalName = new PersonalName("Wilbur", "Jonathan", "M");

const builtIn = BuiltInStandardAttributes._from_object({
    country_name: { iso_3166_alpha2_code: "US" },
    administration_domain_name: { numeric: "123" },
    private_domain_name: { printable: "Wildboar" },
    organization_name: "Wildboar Software",
    personal_name: personalName,
    organizational_unit_names: ["Engineering", "Libraries"], // OU1, then OU2
});

const address = new ORAddress(
    builtIn,
    [new BuiltInDomainDefinedAttribute("Title", "Manager")],
);

address.determineNameForm(); // "mnem"

BuiltInStandardAttributes.fromJSON is another constructor-style path when you already have a JSON object (country-name, administration-domain-name, personal-name, and so on).

Printing (RFC 1685 and RFC 2156)

toString() is RFC 1685 with ; as the delimiter. toRFC2156String() is RFC 2156 std-or-address. Both ORAddress and BuiltInStandardAttributes implement these; the latter prints only the built-in standard attributes.

const address = ORAddress.fromString(
    "G=Jonathan;I=M;S=Wilbur;O=Wildboar Software;A=123;C=US",
)!;

String(address);
address.toString();
// "G=Jonathan;I=M;S=Wilbur;O=Wildboar Software;A=123;C=US"

address.toRFC2156String();
// "/G=Jonathan/I=M/S=Wilbur/O=Wildboar Software/ADMD=123/C=US/"

address.built_in_standard_attributes.toRFC2156String();
// same as above when there are no domain-defined or extension attributes

RFC 2156 quotes /, =, and $ in values with a $ prefix. Organizational units are emitted least-significant first (rightmost is most significant).

const withSlash = new ORAddress(
    BuiltInStandardAttributes._from_object({
        country_name: { iso_3166_alpha2_code: "US" },
        organization_name: "a/b",
    }),
);
withSlash.toRFC2156String(); // contains O=a$/b

const units = new ORAddress(
    BuiltInStandardAttributes._from_object({
        country_name: { iso_3166_alpha2_code: "US" },
        organization_name: "org",
        organizational_unit_names: ["high", "low"], // OU1=high, OU2=low
    }),
);
units.toRFC2156String(); // contains /OU=low/OU=high/

Comparing parts

Use field accessors and the equality helpers on the parts you need. Country comparison maps an X.121 DCC to ISO 3166-1 alpha-2, so C=US and DCC 310 match. ADMD comparison treats a single space as “any ADMD” and therefore equal to any other ADMD.

const isoUs = ORAddress.fromString("S=Wilbur;A=ATT;P=Wildboar;C=US")!;
const dccUs = new ORAddress(BuiltInStandardAttributes._from_object({
    country_name: { x121_dcc_code: "310" },
    administration_domain_name: { printable: "ATT" },
    private_domain_name: { printable: "Wildboar" },
    personal_name: new PersonalName("Wilbur"),
}));
const anyAdmd = new ORAddress(BuiltInStandardAttributes._from_object({
    country_name: { iso_3166_alpha2_code: "US" },
    administration_domain_name: { numeric: " " }, // X.400 "any ADMD"
    private_domain_name: { printable: "Wildboar" },
    personal_name: new PersonalName("Wilbur"),
}));
const otherPrmd = ORAddress.fromString("S=Wilbur;A=ATT;P=Other;C=US")!;

isoUs.isEqualCountry(dccUs);   // true  (US == X.121 310)
isoUs.getISO3166Country();     // "US"
dccUs.getISO3166Country();     // "US"

isoUs.isEqualADMD(anyAdmd);    // true  (either ADMD is " ")
isoUs.isEqualADMD(dccUs);      // true  (both "ATT")
isoUs.isEqualPRMD(dccUs);      // true
isoUs.isEqualPRMD(otherPrmd);  // false

isoUs.built_in_standard_attributes.isEqualCountry(
    dccUs.built_in_standard_attributes,
); // true
isoUs.built_in_standard_attributes.isEqualADMD(
    anyAdmd.built_in_standard_attributes,
); // true

Personal names compare component-wise. Pass true as the second argument to ignore initials (they are often omitted without meaning a different person). A missing given name or generation qualifier is still a mismatch:

const full = new PersonalName("Rose", "Marshall", "MT", "Jr");
const same = new PersonalName("Rose", "Marshall", "MT", "Jr");
const noInitials = new PersonalName("Rose", "Marshall", undefined, "Jr");
const otherGiven = new PersonalName("Rose", "Andrew", "MT", "Jr");

full.isEqualTo(same);                 // true
full.isEqualTo(noInitials);           // false
full.isEqualTo(noInitials, true);     // true  (tolerate missing / differing initials)
full.isEqualTo(otherGiven);           // false
full.isEqualTo(otherGiven, true);     // false

TeletexPersonalName and UniversalPersonalName have the same isEqualTo shape.

RFC 1685 display behavior

This library implements string display for several types according to IETF RFC 1685. If there are multiple conflicting attribute types using different encodings, it is not entirely clear which should be displayed. Consider the following passage:

If the attributes of an O/R address include characters from an extended character set, human users who do not normally use the same extended character set may have difficulty representing the O/R address or entering it into their messaging system. In this situation, an alias of the O/R address should be provided which is composed entirely of printable string characters.

When RFC 1685 was published, the “universal” equivalents of the X.400 MHS attributes were not defined, although teletex equivalents were. This library can still display and parse those encodings, but it prefers printable syntaxes, then teletex, when choosing what to print.

ESM only

This module is ESM-only. There is no CommonJS build.

AI Usage Statement

The code in lib/modules was overwhelmingly created by an ASN.1 compiler that was written manually by a human. Much of the code on top of that was written by AI. The JSDoc and much of this README file were written by AI.