IPv6 address parsing and stringifying utilities.

This module provides functions to convert between IPv6 colon-hexadecimal notation and bigint representation, enabling arithmetic operations on IP addresses.

Examples

Basic IPv6 operations

import { assertEquals } from "@std/assert";
import { parseAddressv6, stringifyAddressv6 } from "@hertzg/ip/addressv6";

const { address } = parseAddressv6("2001:db8::1");
assertEquals(address, 42540766411282592856903984951653826561n);

const next = address + 1n;
assertEquals(stringifyAddressv6(next), "2001:db8::2");

Zone IDs are carried, not applied

import { assertEquals } from "@std/assert";
import { parseAddressv6, stringifyAddressv6 } from "@hertzg/ip/addressv6";

const linkLocal = parseAddressv6("fe80::1%eth0");
assertEquals(linkLocal, { address: 0xfe800000000000000000000000000001n, zoneId: "eth0" });
assertEquals(stringifyAddressv6(linkLocal), "fe80::1%eth0");
assertEquals(stringifyAddressv6(linkLocal.address), "fe80::1");

Bitwise operations on IPv6 addresses

Since IPv6 addresses are plain bigints, you can use standard JavaScript bitwise operators directly. For NOT, mask the result with the maximum 128-bit value to stay within range.

import { assertEquals } from "@std/assert";
import { parseAddressv6, stringifyAddressv6 } from "@hertzg/ip/addressv6";

const ip = parseAddressv6("2001:db8::1").address;
const MAX_IPV6 = (1n << 128n) - 1n;

// Bitwise NOT (invert all bits, mask to 128 bits)
const inverted = ~ip & MAX_IPV6;
assertEquals(stringifyAddressv6(inverted), "dffe:f247:ffff:ffff:ffff:ffff:ffff:fffe");

// Bitwise AND (apply network mask to get network address)
const mask = (MAX_IPV6 << 96n) & MAX_IPV6; // /32 mask
const network = ip & mask;
assertEquals(stringifyAddressv6(network), "2001:db8::");

// Bitwise OR (set host bits)
const result = network | 0xFFn;
assertEquals(stringifyAddressv6(result), "2001:db8::ff");

// Direct comparison (no isEqual() needed)
assertEquals(parseAddressv6("::1").address === parseAddressv6("::1").address, true);
assertEquals(parseAddressv6("::1").address === parseAddressv6("::2").address, false);

Functions

f
compareAddressv6(
a: Addressv6,
b: Addressv6
): -1 | 0 | 1

Compares two IPv6 addresses for sorting, numerically ascending.

f
mapFromAddressv4(address: Addressv4): Addressv6

Converts an IPv4 address to its IPv4-mapped IPv6 representation.

f
parseAddressv6(address: string): ParsedAddressv6

Parses an IPv6 address in colon-hexadecimal notation, with an optional zone ID, to its numeric value.

f
stringifyAddressv6(address: Addressv6 | ParsedAddressv6): string

Stringifies an IPv6 address to compressed colon-hexadecimal notation.

f
stringifyAddressv6Expanded(address: Addressv6 | ParsedAddressv6): string

Stringifies an IPv6 address to full uncompressed colon-hexadecimal notation.

f
unmapToAddressv4(address: Addressv6): Addressv4

Extracts the IPv4 address from an IPv4-mapped IPv6 address.

Type Aliases

T
Addressv4 = number

An IPv4 address as a 32-bit unsigned integer, 0 to 4294967295. The primitive type is what carries the version: a number is IPv4, a bigint is IPv6 (ADR 0001).

T
Addressv6 = bigint

An IPv6 address as a 128-bit unsigned bigint, 0n to 2n ** 128n - 1n. The primitive type is what carries the version: a bigint is IPv6, a number is IPv4 (ADR 0001).

T
ParsedAddressv6 = { readonly address: Addressv6; readonly zoneId?: ZoneId; }

What parseAddressv6 returns and what stringifyAddressv6 accepts: the address, plus the zone ID if the notation had one. Read .address for the bare Addressv6; the zone never touches the value, and no operation in this package reads it.

T
ZoneId = string

The zone ID of an address, the interface tail after % in fe80::1%eth0 (RFC 4007 section 11). Carried verbatim by the Parsed* types; never percent-decoded, so %25eth0 is the zone 25eth0.