pax_global_header 0000666 0000000 0000000 00000000064 15272410673 0014521 g ustar 00root root 0000000 0000000 52 comment=3f12c6b5d8f864e4b42a8d58e3df1b172cd120e3
beaugunderson-ip-address-438375e/ 0000775 0000000 0000000 00000000000 15272410673 0016677 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/.eslintignore 0000664 0000000 0000000 00000000023 15272410673 0021375 0 ustar 00root root 0000000 0000000 dist/
node_modules/ beaugunderson-ip-address-438375e/.eslintrc.js 0000664 0000000 0000000 00000005735 15272410673 0021150 0 ustar 00root root 0000000 0000000 module.exports = {
root: true,
env: {
browser: true,
node: true,
},
parser: '@typescript-eslint/parser',
plugins: ['filenames', 'import', 'prettier', 'sort-imports-es6-autofix', '@typescript-eslint'],
extends: ['airbnb-base', 'prettier'],
rules: {
'array-callback-return': 'off',
'arrow-body-style': 'off',
'class-methods-use-this': 'off',
'consistent-return': 'off',
'filenames/match-exported': 'error',
'import/default': 'error',
'import/extensions': ['warn', 'never'],
'import/first': 'off',
'import/named': 'error',
'import/newline-after-import': 'warn',
'import/no-cycle': 'off',
'import/no-extraneous-dependencies': 'off',
'import/no-named-as-default-member': 'error',
'import/no-named-as-default': 'error',
'import/no-unresolved': 'off',
'import/order': 'off',
'import/prefer-default-export': 'off',
'lines-between-class-members': 'off',
// Masks, prefix lengths and the NAT64 and Teredo encodings are all defined
// in terms of shifts and xors, so the rule fires on correct code
// throughout and its inline suppressions outnumbered its findings.
'no-bitwise': 'off',
'no-case-declarations': 'off',
'no-cond-assign': ['error', 'except-parens'],
'no-continue': 'off',
'no-param-reassign': [
'error',
{
props: true,
// allow reassigning evt.target.value
ignorePropertyModificationsFor: ['evt'],
},
],
'no-plusplus': 'off',
'no-return-assign': 'off',
'no-underscore-dangle': 'off',
'no-use-before-define': 'off',
'no-useless-constructor': 'off',
'prettier/prettier': [
'error',
{
singleQuote: true,
printWidth: 99,
trailingComma: 'all',
},
],
// override this from airbnb's guide specifically to allow for..of loops
'no-restricted-syntax': [
'error',
{
selector: 'ForInStatement',
message:
'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.',
},
{
selector: 'LabeledStatement',
message:
'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand',
},
{
selector: 'WithStatement',
message:
'`with` is disallowed in strict mode because it makes code impossible to predict and optimize.',
},
],
'@typescript-eslint/no-unused-vars': 'error',
// preferable to built in 'sort-imports' because it handles default imports better and has better auto-fix
'sort-imports-es6-autofix/sort-imports-es6': [
'error',
{ ignoreCase: true, memberSyntaxSortOrder: ['none', 'all', 'single', 'multiple'] },
],
},
overrides: [
{
// Build scripts report progress on stdout.
files: ['scripts/**/*.ts'],
rules: {
'no-console': 'off',
},
},
],
};
beaugunderson-ip-address-438375e/.github/ 0000775 0000000 0000000 00000000000 15272410673 0020237 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/.github/workflows/ 0000775 0000000 0000000 00000000000 15272410673 0022274 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/.github/workflows/ci.yml 0000664 0000000 0000000 00000006217 15272410673 0023420 0 ustar 00root root 0000000 0000000 name: CI
on:
push:
branches:
- main
pull_request:
# Fork pull requests get this same read-only token and no secrets, so a
# contributor's branch can run the suite without being handed anything.
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
# Formatting and lint findings are reported, not corrected, in CI. Correcting
# them here would mean granting a workflow write access to the repository and
# would still leave fork pull requests to fix by hand, so the same check runs
# from a pre-commit hook, where `npm run lint:fix` is one command away.
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
cache: npm
- run: npm ci
- run: npm run lint
# The API reference in the README is generated from the source, down to
# the line numbers its links point at, so any change under src leaves it
# stale until it is rebuilt.
- name: Check the generated README is current
run: npm run docs:check
test:
name: test-${{ matrix.node-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: ['20', '22', '24', '25']
steps:
# Third-party actions are pinned to a commit, not a tag: a tag is
# mutable and this workflow runs on pull requests from forks.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: ./coverage.sh
name: Run tests
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
# Tokenless upload; public repositories do not need a token, and a
# fork pull request would not have access to one anyway.
fail_ci_if_error: false
# The oldest node `engines` claims. The dev toolchain (mocha, tsx, c8) and the
# lockfile's npm version both need a modern node, so the suite itself cannot
# run here; instead this builds dist on a current node and requires it under
# node 12, which is what a consumer on an old runtime does and the only place
# emitted-syntax regressions show up.
smoke:
name: smoke-12
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
cache: npm
- run: npm ci
- run: npm run build
# Switching the active node after the build; nothing below runs npm, so
# node 12's bundled npm 6 never has to read the lockfile.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '12'
- run: node test/node-12-smoke.js
name: Run dist smoke test
beaugunderson-ip-address-438375e/.github/workflows/release.yml 0000664 0000000 0000000 00000001636 15272410673 0024445 0 ustar 00root root 0000000 0000000 name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- run: npm install -g npm@latest
- run: npm ci
- run: npm test
- run: npm publish --provenance --access public
# Pinned to a commit rather than a tag: this job holds the npm
# trusted-publishing identity and a write-scoped token, so the third-party
# code it runs should not be able to change under a moved tag.
- uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
with:
generate_release_notes: true
beaugunderson-ip-address-438375e/.gitignore 0000664 0000000 0000000 00000000250 15272410673 0020664 0 ustar 00root root 0000000 0000000 node_modules
.git
.tox
tmp/
*.egg-info
LOCK
.coveralls.yml
.lvimrc
.DS_Store
*.swp
*.pyc
*.old
*.log
*.lock
test.sh
test/unused/
coverage/
docs/
dist/
.nyc_output/
beaugunderson-ip-address-438375e/.mocharc.yml 0000664 0000000 0000000 00000000211 15272410673 0021106 0 ustar 00root root 0000000 0000000 recursive: true
reporter: spec
node-option:
- import=tsx
- import=source-map-support/register
inline-diffs: false
spec: test/**/*.ts
beaugunderson-ip-address-438375e/.prettierignore 0000664 0000000 0000000 00000000236 15272410673 0021743 0 ustar 00root root 0000000 0000000 # Vendored test fixtures, kept in the shape they arrived in so they stay
# comparable against their source.
test/data/
# Build output.
dist/
coverage/
docs/
beaugunderson-ip-address-438375e/.prettierrc 0000664 0000000 0000000 00000000110 15272410673 0021053 0 ustar 00root root 0000000 0000000 {
"printWidth": 99,
"singleQuote": true,
"trailingComma": "all"
}
beaugunderson-ip-address-438375e/.vscode/ 0000775 0000000 0000000 00000000000 15272410673 0020240 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/.vscode/settings.json 0000664 0000000 0000000 00000000513 15272410673 0022772 0 ustar 00root root 0000000 0000000 {
"typescript.tsdk": "node_modules/typescript/lib",
"eslint.options": {
"configFile": "./.eslintrc.js"
},
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
"coverage/**": true,
"node_modules/**": true,
"dist/**": true,
"build/**": true,
"assets/**": true,
"tmp/**": true
}
}
beaugunderson-ip-address-438375e/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000006223 15272410673 0021501 0 ustar 00root root 0000000 0000000 # Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at beau@beaugunderson.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
beaugunderson-ip-address-438375e/LICENSE 0000664 0000000 0000000 00000002045 15272410673 0017705 0 ustar 00root root 0000000 0000000 Copyright (C) 2011 by Beau Gunderson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
beaugunderson-ip-address-438375e/README.md 0000664 0000000 0000000 00000137150 15272410673 0020165 0 ustar 00root root 0000000 0000000 [](https://github.com/beaugunderson/ip-address/actions/workflows/ci.yml)
[![codecov]](https://codecov.io/github/beaugunderson/ip-address?branch=main)
[![downloads]](https://www.npmjs.com/package/ip-address)
[![npm]](https://www.npmjs.com/package/ip-address)
[codecov]: https://codecov.io/github/beaugunderson/ip-address/coverage.svg?branch=main
[downloads]: https://img.shields.io/npm/dm/ip-address.svg
[npm]: https://img.shields.io/npm/v/ip-address.svg
## ip-address
`ip-address` is a library for validating and manipulating IPv4 and IPv6 addresses in JavaScript and TypeScript.
### Install
```sh
npm install ip-address
```
### Examples
```ts
import { Address4, Address6 } from 'ip-address';
// Validation
Address4.isValid('192.168.1.1'); // true
Address6.isValid('2001:db8::1'); // true
Address6.isValid('not an address'); // false
// Parsing (throws AddressError on invalid input)
const v4 = new Address4('192.168.1.1/24');
const v6 = new Address6('2001:db8::1/64');
// Subnet membership
const host = new Address4('192.168.1.42');
const network = new Address4('192.168.1.0/24');
host.isInSubnet(network); // true
// Subnet range
network.startAddress().correctForm(); // '192.168.1.0'
network.endAddress().correctForm(); // '192.168.1.255'
// Strict network-address check (host bits must be zero).
// isValid() accepts CIDRs with host bits set — '192.168.1.5/24' is a valid
// host-with-subnet, but it isn't a network address.
const cidr = new Address4('192.168.1.5/24');
Address4.isValid('192.168.1.5/24'); // true
cidr.correctForm() === cidr.startAddress().correctForm(); // false
// Address properties
const link = new Address6('fe80::1');
link.isLinkLocal(); // true
link.isMulticast(); // false
link.isLoopback(); // false
new Address4('192.168.1.1').isPrivate(); // true (RFC 1918)
new Address6('fc00::1').isULA(); // true (RFC 4193)
// Numeric and byte representations
v4.bigInt(); // 3232235777n
v4.toArray(); // [192, 168, 1, 1]
v6.canonicalForm(); // '2001:0db8:0000:0000:0000:0000:0000:0001'
// Embedded IPv4 + Teredo
const teredo = new Address6('2001:0:ce49:7601:e866:efff:62c3:fffe');
teredo.inspectTeredo().client4; // '157.60.0.1'
// Parse host + port from a URL
Address6.fromURL('http://[2001:db8::1]:8080/').port; // 8080
```
### Features
- Written in TypeScript with full type definitions; usable from CommonJS and ESM
- Zero runtime dependencies
- Parses dotted-quad IPv4 and [RFC 4291](https://datatracker.ietf.org/doc/html/rfc4291) IPv6 notation, including subnets and zones. The `inet_aton` forms (`2130706433`, `0x7f000001`, `127.1`) and leading-zero octets are rejected by design — see [SECURITY.md](./SECURITY.md#classifiers-are-not-an-ssrf-defense)
- Parses IPv6 hosts (and ports) from URLs via `Address6.fromURL(url)`
- Subnet membership checks (`isInSubnet`) and range queries (`startAddress` / `endAddress`)
- Special-property checks: private (RFC 1918) / ULA (RFC 4193), loopback, link-local, multicast, broadcast, unspecified, CGNAT, documentation, Teredo, 6to4, v4-in-v6
- Decodes [Teredo](http://en.wikipedia.org/wiki/Teredo_tunneling#IPv6_addressing) and 6to4 tunneling information
- Conversions: canonical/correct form, hex, binary, decimal, byte arrays, BigInt, `in-addr.arpa` / `ip6.arpa`
- Runs in Node.js and the browser
- Thousands of test cases
### Terminology
A few terms used throughout the API can be confusing if you haven't worked deeply with IPv6 before:
- **Correct form** — the shortest valid representation, per [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros stripped, the longest run of zero groups collapsed to `::`, and hex digits lowercased (e.g. `2001:db8::1`). This is what most software displays.
- **Canonical form** — the fully expanded representation: all 8 groups, each padded to 4 hex digits, no `::` collapsing (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and byte-exact comparison.
- **Subnet** — the network portion of an address expressed as a CIDR prefix length (e.g. `/24` for IPv4, `/64` for IPv6). `startAddress()` / `endAddress()` return the bounds of the subnet's range.
- **Zone** — the IPv6 scope identifier appended after `%`, used to disambiguate link-local addresses across interfaces (e.g. `fe80::1%eth0`).
- **v4-in-v6** — mixed notation that embeds an IPv4 address as the last 32 bits of an IPv6 address, e.g. `::ffff:192.168.0.1`. Used for IPv4-mapped IPv6 addresses.
- **Teredo** — a tunneling protocol that encodes an IPv4 endpoint, port, and flags inside a `2001::/32` IPv6 address. `inspectTeredo()` decodes those fields.
- **6to4** — a tunneling protocol that embeds a full 32-bit IPv4 address in bits 16–47 of a `2002::/16` IPv6 address, i.e. the second and third groups (`192.0.2.4` becomes `2002:c000:204::`). `inspect6to4()` decodes the embedded v4 address.
### API
Address4 — Represents an IPv4 address
**Constructor**
- `new Address4(address: string): Address4`
**Static methods**
- `static isValid(address: string): boolean` — Returns true if the given string is a valid IPv4 address (with optional CIDR subnet), false otherwise. Host bits in the subnet portion are allowed (e.g. `192.168.1.5/24` is valid); for strict network-address validation compare `correctForm()` to `startAddress().correctForm()`, or use `networkForm()`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L62)
- `static fromAddressAndMask(address: string, mask: string): Address4` — Construct an `Address4` from an address and a dotted-decimal subnet mask given as separate strings (e.g. as returned by Node's `os.networkInterfaces()`). Throws `AddressError` if the mask is non-contiguous (e.g. `255.0.255.0`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L119)
- `static fromAddressAndWildcardMask(address: string, wildcardMask: string): Address4` — Construct an `Address4` from an address and a Cisco-style wildcard mask given as separate strings (e.g. `0.0.0.255` for a `/24`). The wildcard mask is the bitwise inverse of the subnet mask. Throws `AddressError` if the mask is non-contiguous (e.g. `0.255.0.255`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L133)
- `static fromWildcard(input: string): Address4` — Construct an `Address4` from a wildcard pattern with trailing `*` octets. The number of trailing wildcards determines the prefix length: each `*` represents 8 bits. Only trailing whole-octet wildcards are supported. Partial-octet wildcards (e.g. `192.168.0.1*`) and interior wildcards (e.g. `192.*.0.1`) throw `AddressError`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L154)
- `static fromHex(hex: string): Address4` — Converts a hex string to an IPv4 address object. Accepts 8 hex digits with optional `:` separators (e.g. `'7f000001'` or `'7f:00:00:01'`). Throws `AddressError` for any other length or for non-hex characters. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L189)
- `static fromInteger(integer: number): Address4` — Converts an integer into a IPv4 address object. The integer must be a non-negative safe integer in the range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L212)
- `static fromArpa(arpaFormAddress: string): Address4` — Return an address from in-addr.arpa form: the four octets reversed, with or without the `.in-addr.arpa` suffix and root dot, in any case. Throws `AddressError` unless the reversed labels form a valid IPv4 address, so `fromArpa(x.reverseForm())` round-trips reverseForm. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L231)
- `static fromBigInt(bigInt: bigint): Address4` — Converts a BigInt to a v4 address object. The value must be in the range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L422)
- `static fromByteArray(bytes: number[]): Address4` — Convert a byte array to an Address4 object. Throws `AddressError` unless given exactly 4 integers from 0 to 255. Signed bytes are rejected, so this differs from `Address6.fromByteArray`, which folds them; the two contracts converge on this stricter form in the next major version. To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L440)
- `static fromUnsignedByteArray(bytes: number[]): Address4` — Convert an unsigned byte array to an Address4 object. Throws `AddressError` unless given exactly 4 bytes, and rejects values outside 0 to 255 when parsing the resulting address. To convert from a Node.js `Buffer`, spread it: `Address4.fromUnsignedByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L456)
**Instance methods**
- `parse(address: string): string[]` — Parses an IPv4 address string into its four octet groups and stores the result on `this.parsedAddress`. Called automatically by the constructor; you typically don't need to call it directly. Throws `AddressError` if the input is not a valid IPv4 address. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L79)
- `correctForm(): string` — Returns the address in correct form: octets joined with `.` and any leading zeros stripped (e.g. `192.168.1.1`). For IPv4 this matches the canonical dotted-decimal representation. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L100)
- `toHex(): string` — Converts an IPv4 address object to a hex string [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L254)
- `toArray(): number[]` — Converts an IPv4 address object to an array of bytes. To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L264)
- `toGroup6(): string` — Converts an IPv4 address object to an IPv6 address group [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L272)
- `bigInt(): bigint` — Returns the address as a `bigint` [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L291)
- `startAddress(): Address4` — The first address in the range given by this address' subnet. Often referred to as the Network Address. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L308)
- `startAddressExclusive(): Address4` — The first host address in the range given by this address's subnet ie the first address after the Network Address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L317)
- `offset(n: number | bigint): Address4` — Returns the address `n` addresses after this one (or before, when `n` is negative), keeping this address's subnet mask. Throws `AddressError` when the result would fall outside the IPv4 address space or `n` is not an integer. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L332)
- `nextNetwork(): Address4` — Returns the network that follows this address's network: the address after endAddress, with the same subnet mask. Throws `AddressError` when this network is the last one in the address space. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L346)
- `endAddress(): Address4` — The last address in the range given by this address' subnet Often referred to as the Broadcast [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L369)
- `endAddressExclusive(): Address4` — The last host address in the range given by this address's subnet ie the last address prior to the Broadcast Address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L378)
- `subnetMaskAddress(): Address4` — The dotted-decimal form of the subnet mask, e.g. `255.255.240.0` for a `/20`. Returns an `Address4`; call `.correctForm()` for the string. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L388)
- `wildcardMask(): Address4` — The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is the bitwise inverse of `subnetMaskAddress()`. Returns an `Address4`; call `.correctForm()` for the string. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L400)
- `networkForm(): string` — The network address in CIDR string form, e.g. `192.168.1.0/24` for `192.168.1.5/24`. For an address with no explicit subnet the prefix is `/32`, e.g. `networkForm()` on `192.168.1.5` returns `192.168.1.5/32`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L412)
- `mask(mask?: number): string` — Returns the first n bits of the address, defaulting to the subnet mask [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L470)
- `getBitsBase2(start: number, end: number): string` — Returns the bits in the given range as a base-2 string [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L482)
- `reverseForm(options?: ReverseFormOptions): string` — Return the reversed in-addr.arpa form of the address, e.g. `42.2.0.192.in-addr.arpa.` for `192.0.2.42`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L493)
- `isMulticast(): boolean` — Returns true if the given address is a multicast address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L531)
- `isPrivate(): boolean` — Returns true if the address is in one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private address ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L539)
- `isLoopback(): boolean` — Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L547)
- `isLinkLocal(): boolean` — Returns true if the address is in the link-local range `169.254.0.0/16` ([RFC 3927](https://datatracker.ietf.org/doc/html/rfc3927)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L555)
- `isUnspecified(): boolean` — Returns true if the address is the unspecified address `0.0.0.0`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L563)
- `isBroadcast(): boolean` — Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L571)
- `isCGNAT(): boolean` — Returns true if the address is in the carrier-grade NAT range `100.64.0.0/10` ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L579)
- `isDocumentation(): boolean` — Returns true if the address is in one of the documentation ranges `192.0.2.0/24`, `198.51.100.0/24`, or `203.0.113.0/24` ([RFC 5737](https://datatracker.ietf.org/doc/html/rfc5737)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L588)
- `isBenchmarking(): boolean` — Returns true if the address is in the benchmarking range `198.18.0.0/15` ([RFC 2544](https://datatracker.ietf.org/doc/html/rfc2544)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L596)
- `isReserved(): boolean` — Returns true if the address is in the reserved range `240.0.0.0/4` ([RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112)), which includes the limited broadcast address. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L605)
- `isGlobal(): boolean` — Returns true if the address is globally reachable: not multicast, and not in any block the [IANA IPv4 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/) marks as not globally reachable. That covers everything the individual classifiers name (private, loopback, link-local, CGNAT, unspecified, broadcast, documentation, benchmarking, reserved) and the blocks they do not, such as `0.0.0.0/8` and the IETF protocol assignments in `192.0.0.0/24`. This is the single predicate to use where a request must not reach an internal or special-purpose destination; see SECURITY.md. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L620)
- `binaryZeroPad(): string` — Returns a zero-padded base-2 string representation of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L628)
- `groupForV6(): string` — Groups an IPv4 address for inclusion at the end of an IPv6 address. Returns an HTML fragment: each half of the address is wrapped in a `` carrying the group classes an address-inspector UI hovers on. The address content is HTML-escaped; anything you concatenate around it is your responsibility. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L644)
**Properties**
- `address: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L14)
- `addressMinusSuffix: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L15)
- `groups: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L16)
- `parsedAddress: string[]` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L17)
- `parsedSubnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L18)
- `subnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L19)
- `subnetMask: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L20)
- `v4: boolean` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L21)
- `isCorrect: () => boolean` — Returns true if the address is correct, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L108)
- `isInSubnet: (address: Address4 | Address6) => boolean` — Returns true if the given address is in the subnet of the current address. An `Address6` is never in the subnet of an `Address4`; convert with `to4()` or `Address6.fromAddress4()` to compare across families. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L513)
- `isHostInSubnet: (address: Address4 | Address6) => boolean` — Returns true if this address's host bits fall inside the given subnet, ignoring this address's own subnet mask. Prefer this over `isInSubnet` when classifying a single address, so the answer doesn't change with the CIDR suffix the caller happened to write — notably when the address came from untrusted input and the result backs a trust-boundary decision. An `Address6` is never in the subnet of an `Address4`; convert with `to4()` or `Address6.fromAddress4()` to compare across families. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L525)
Address6 — Represents an IPv6 address
**Constructor**
- `new Address6(address: string, optionalGroups?: number): Address6`
**Static methods**
- `static isValid(address: string): boolean` — Returns true if the given string is a valid IPv6 address (with optional CIDR subnet and zone identifier), false otherwise. Host bits in the subnet portion are allowed (e.g. `2001:db8::1/32` is valid); for strict network-address validation compare `correctForm()` to `startAddress().correctForm()`, or use `networkForm()`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L182)
- `static fromBigInt(bigInt: bigint): Address6` — Convert a BigInt to a v6 address object. The value must be in the range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L203)
- `static fromURL(url: string): { error: string; address: null; port: null } | { error?: undefined; address: Address6; port: number | null }` — Parse a URL (with optional bracketed host and port) into an address and port. Returns either `{ address, port }` on success or `{ error, address: null, port: null }` if the URL could not be parsed. Ports are returned as numbers (or `null` if absent or out of range). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L228)
- `static fromAddressAndMask(address: string, mask: string): Address6` — Construct an `Address6` from an address and a hex subnet mask given as separate strings (e.g. as returned by Node's `os.networkInterfaces()`). Throws `AddressError` if the mask is non-contiguous (e.g. `ffff::ffff`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L295)
- `static fromAddressAndWildcardMask(address: string, wildcardMask: string): Address6` — Construct an `Address6` from an address and a Cisco-style wildcard mask given as separate strings (e.g. `::ffff:ffff:ffff:ffff` for a `/64`). The wildcard mask is the bitwise inverse of the subnet mask. Throws `AddressError` if the mask is non-contiguous. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L309)
- `static fromWildcard(input: string): Address6` — Construct an `Address6` from a wildcard pattern with trailing `*` groups. The number of trailing wildcards determines the prefix length: each `*` represents 16 bits. `::` is expanded to zero groups (not wildcards) before evaluating trailing wildcards. Only trailing whole-group wildcards are supported. Partial-group wildcards (e.g. `2001:db8::0*`) and interior wildcards (e.g. `*::1`) throw `AddressError`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L331)
- `static fromAddress4(address: string): Address6` — Create an IPv6-mapped address given an IPv4 address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L392)
- `static fromArpa(arpaFormAddress: string): Address6` — Return an address from ip6.arpa form. A full 32-nibble name gives a /128 address; a shorter name, as used for a delegated reverse zone, gives the network it covers, with a subnet mask of four bits per nibble, so `fromArpa(x.reverseForm())` round-trips reverseForm for any prefix. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L412)
- `static fromAddress4Nat64(address: string, prefix?: string): Address6` — Embed an IPv4 address into a NAT64 IPv6 address using the encoding defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052). The default prefix is the well-known prefix `64:ff9b::/96`. The prefix length must be one of 32, 40, 48, 56, 64, or 96; for prefixes shorter than /64 the IPv4 octets are split around the reserved bits 64–71. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1122)
- `static fromByteArray(bytes: number[]): Address6` — Convert a byte array to an Address6 object. Accepts unsigned bytes (0 to 255) or signed bytes (-128 to 127, as an `Int8Array` or a Java `byte[]` holds them), folding signed values to their unsigned equivalent. Throws `AddressError` unless given exactly 16 integers from -128 to 255. To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1237)
- `static fromUnsignedByteArray(bytes: number[]): Address6` — Convert an unsigned byte array to an Address6 object. Throws `AddressError` unless given exactly 16 integers from 0 to 255. To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1254)
**Instance methods**
- `microsoftTranscription(): string` — Return the Microsoft UNC transcription of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L437)
- `mask(mask?: number): string` — Return the first n bits of the address, defaulting to the subnet mask [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L446)
- `possibleSubnets(subnetSize?: number): string` — Return the number of possible subnets of a given size in the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L456)
- `startAddress(): Address6` — The first address in the range given by this address' subnet Often referred to as the Network Address. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L481)
- `startAddressExclusive(): Address6` — The first host address in the range given by this address's subnet ie the first address after the Network Address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L490)
- `endAddress(): Address6` — The last address in the range given by this address's subnet. IPv6 has no broadcast address, so this is an ordinary assignable address (in a 64-bit-interface-identifier subnet it falls inside the reserved subnet-anycast block of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L510)
- `endAddressExclusive(): Address6` — The address one before endAddress. This is the IPv6 counterpart of the IPv4 method that skips the broadcast address; IPv6 has no broadcast, so it drops exactly one address and does not model the 128 reserved subnet-anycast identifiers of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L521)
- `offset(n: number | bigint): Address6` — Returns the address `n` addresses after this one (or before, when `n` is negative), keeping this address's subnet mask. Throws `AddressError` when the result would fall outside the IPv6 address space or `n` is not an integer. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L536)
- `nextNetwork(): Address6` — Returns the network that follows this address's network: the address after endAddress, with the same subnet mask. Throws `AddressError` when this network is the last one in the address space. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L550)
- `subnetMaskAddress(): Address6` — The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a `/64`. Returns an `Address6`; call `.correctForm()` for the string. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L565)
- `wildcardMask(): Address6` — The Cisco-style wildcard mask, e.g. `::ffff:ffff:ffff:ffff` for a `/64`. This is the bitwise inverse of `subnetMaskAddress()`. Returns an `Address6`; call `.correctForm()` for the string. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L577)
- `networkForm(): string` — The network address in CIDR string form, e.g. `2001:db8::/32` for `2001:db8::1/32`. For an address with no explicit subnet the prefix is `/128`, e.g. `networkForm()` on `2001:db8::1` returns `2001:db8::1/128`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L590)
- `getScope(): string` — Return the scope of the address. The 4-bit scope field ([RFC 4291 §2.7](https://datatracker.ietf.org/doc/html/rfc4291#section-2.7)) is only defined for multicast addresses; for unicast addresses the scope is derived from the address type per [RFC 4007 §6](https://datatracker.ietf.org/doc/html/rfc4007#section-6). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L602)
- `getType(): string` — Return the type of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L629)
- `getBits(start: number, end: number): bigint` — Return the bits in the given range as a BigInt [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L644)
- `getBitsBase2(start: number, end: number): string` — Return the bits in the given range as a base-2 string [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L652)
- `getBitsBase16(start: number, end: number): string` — Return the bits in the given range as a base-16 string [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L660)
- `getBitsPastSubnet(): string` — Return the bits that are set past the subnet mask length [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L676)
- `reverseForm(options?: ReverseFormOptions): string` — Return the reversed ip6.arpa form of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L686)
- `correctForm(): string` — Returns the address in correct form, per [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros stripped, the longest run of zero groups collapsed to `::`, and hex digits lowercased (e.g. `2001:db8::1`). This is the recommended form for display. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L721)
- `binaryZeroPad(): string` — Return a zero-padded base-2 string representation of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L783)
- `parse4in6(address: string): string` — Parses a v4-in-v6 string (e.g. `::ffff:192.168.0.1`) by extracting the trailing IPv4 address into `this.address4` / `this.parsedAddress4` and returning the address with the v4 portion converted to two v6 groups. Used internally by `parse()`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L797)
- `parse(address: string): string[]` — Parses an IPv6 address string into its 8 hexadecimal groups (expanding any `::` elision and any trailing v4-in-v6 portion) and stores the result on `this.parsedAddress`. Called automatically by the constructor; you typically don't need to call it directly. Throws `AddressError` if the input is malformed. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L854)
- `canonicalForm(): string` — Returns the canonical (fully expanded) form of the address: all 8 groups, each padded to 4 hex digits, with no `::` collapsing (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and byte-exact comparison. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L937)
- `decimal(): string` — Return the decimal form of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L945)
- `bigInt(): bigint` — Return the address as a BigInt [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L953)
- `to4(): Address4` — Return the last two groups of this address as an IPv4 address string. If this address carries a CIDR prefix that covers the trailing 32 bits (i.e. `subnetMask >= 96`), the resulting `Address4` inherits the corresponding v4 prefix (`subnetMask - 96`); otherwise it defaults to `/32`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L968)
- `to4in6(): string` — Return the v4-in-v6 form of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L992)
- `inspectTeredo(): TeredoProperties` — Decodes the Teredo tunneling fields embedded in this address. Returns the Teredo prefix, server IPv4, client IPv4, raw flag bits, cone-NAT flag, UDP port, and Microsoft-format flag breakdown (reserved, universal/local, group/individual, nonce). Only meaningful for addresses in `2001::/32`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1013)
- `inspect6to4(): SixToFourProperties` — Decodes the 6to4 tunneling fields embedded in this address. Returns the 6to4 prefix and the embedded IPv4 gateway address. Only meaningful for addresses in `2002::/16`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1076)
- `to6to4(): Address6 | null` — Return a v6 6to4 address from a v6 v4inv6 address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1096)
- `toAddress4Nat64(prefix?: string): Address4 | null` — Extract the embedded IPv4 address from a NAT64 IPv6 address using the encoding defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052). The default prefix is the well-known prefix `64:ff9b::/96`. Returns `null` if this address is not contained within the given prefix. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1165)
- `toByteArray(): number[]` — Return a byte array. To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1200)
- `toUnsignedByteArray(): number[]` — Return an unsigned byte array. To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1219)
- `isCanonical(): boolean` — Returns true if the address is in the canonical form, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1301)
- `isLinkLocal(): boolean` — Returns true if the address is a link-local unicast address in `fe80::/10` ([RFC 4291 §2.4](https://datatracker.ietf.org/doc/html/rfc4291#section-2.4)) or an IPv4-mapped / NAT64 address whose embedded IPv4 address is link-local (`169.254.0.0/16`, e.g. `::ffff:169.254.169.254`), false otherwise. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1312)
- `isMulticast(): boolean` — Returns true if the address is a multicast address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1325)
- `is4(): boolean` — Returns true if the address was written in v4-in-v6 dotted-quad notation (e.g. `::ffff:127.0.0.1`), false otherwise. This is a notation-level flag and does not reflect whether the address bits lie in the IPv4-mapped (`::ffff:0:0/96`) subnet — for that, see isMapped4. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1342)
- `isMapped4(): boolean` — Returns true if the address is an IPv4-mapped IPv6 address in `::ffff:0:0/96` ([RFC 4291 §2.5.5.2](https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2)), false otherwise. Unlike is4, this checks the underlying address bits rather than the textual notation, so `::ffff:127.0.0.1` and `::ffff:7f00:1` both return true. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1354)
- `embeddedIPv4(): Address4 | null` — If this address embeds a routable IPv4 address — i.e. it is IPv4-mapped (`::ffff:0:0/96`) or sits in the NAT64 well-known prefix (`64:ff9b::/96`, [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052)) — return that embedded address as an Address4; otherwise return null. The special-property checks (`isLoopback`, `isLinkLocal`, `isMulticast`, `isUnspecified`, `isPrivate`, `isCGNAT`, `isBroadcast`) call this first and delegate to the embedded Address4 when present, so a literal such as `::ffff:127.0.0.1` is classified by what it actually reaches (loopback) rather than by its IPv6 wrapper (which `getType()` reports as IPv4-mapped). This matters wherever the checks back a trust-boundary decision (e.g. an SSRF allow/deny filter): without normalization, `::ffff:10.0.0.1`, `::ffff:169.254.169.254`, `64:ff9b::7f00:1`, etc. would all read as non-internal. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1375)
- `isTeredo(): boolean` — Returns true if the address is a Teredo address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1387)
- `is6to4(): boolean` — Returns true if the address is a 6to4 address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1395)
- `isLoopback(): boolean` — Returns true if the address is a loopback address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1403)
- `isULA(): boolean` — Returns true if the address is a Unique Local Address in `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)). ULAs are the IPv6 equivalent of IPv4 [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private addresses. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1416)
- `isPrivate(): boolean` — Returns true if the address is private, i.e. a Unique Local Address in `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)), an address in the NAT64 local-use range `64:ff9b:1::/48` ([RFC 8215](https://datatracker.ietf.org/doc/html/rfc8215)), or an IPv4-mapped / NAT64 well-known address whose embedded IPv4 address is in one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private ranges (e.g. `::ffff:10.0.0.1`). This is the IPv6 counterpart to Address4.isPrivate; use it instead of isULA when you need to catch mapped RFC 1918 addresses as well as native ULAs. The local-use NAT64 range is reported private as a whole rather than by its embedded IPv4 address: an operator may carve a prefix of any RFC 6052 length out of `64:ff9b:1::/48`, so the same bits decode to different IPv4 addresses under different deployments and no single decoding is correct. Use toAddress4Nat64 with the deployment's prefix to decode one. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1438)
- `isCGNAT(): boolean` — Returns true if the address is an IPv4-mapped / NAT64 address whose embedded IPv4 address is in the carrier-grade NAT range `100.64.0.0/10` ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)), false otherwise. There is no native IPv6 CGNAT range, so this only ever returns true for an embedded IPv4 address (e.g. `::ffff:100.64.0.1`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1455)
- `isBroadcast(): boolean` — Returns true if the address is an IPv4-mapped / NAT64 address whose embedded IPv4 address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)), false otherwise. There is no IPv6 broadcast, so this only ever returns true for an embedded IPv4 address (e.g. `::ffff:255.255.255.255`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1472)
- `isUnspecified(): boolean` — Returns true if the address is the unspecified address `::`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1485)
- `isDocumentation(): boolean` — Returns true if the address is in the documentation prefix `2001:db8::/32` ([RFC 3849](https://datatracker.ietf.org/doc/html/rfc3849)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1498)
- `isBenchmarking(): boolean` — Returns true if the address is in the benchmarking range `2001:2::/48` ([RFC 5180](https://datatracker.ietf.org/doc/html/rfc5180)) or is an IPv4-mapped / NAT64 address whose embedded IPv4 address is in `198.18.0.0/15`, false otherwise. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1509)
- `isGlobal(): boolean` — Returns true if the address is globally reachable: inside the global unicast allocation `2000::/3` (the only range the [IANA IPv6 Address Space Registry](https://www.iana.org/assignments/ipv6-address-space/) assigns for global unicast; everything else is reserved, ULA, link-local, or multicast) and not in any block the [IANA IPv6 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv6-special-registry/) marks as not globally reachable. An IPv4-mapped or NAT64 well-known address answers for its embedded IPv4 address, so `::ffff:10.0.0.1` and `64:ff9b::7f00:1` are not global. Teredo (`2001::/32`) and 6to4 (`2002::/16`) are not global either: the registry lists them as N/A and a packet to one needs a relay. This covers everything the individual classifiers name and the blocks they do not: the discard-only prefix `100::/64`, the IETF protocol assignments in `2001::/23`, the deprecated site-local `fec0::/10` and IPv4-compatible `::/96` ranges, and unallocated space such as `4000::/3`. It is the single predicate to use where a request must not reach an internal or special-purpose destination; see SECURITY.md. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1538)
- `href(optionalPort?: string | number): string` — Returns the address as an HTTP URL with the host bracketed, e.g. `http://[2001:db8::1]/`. If `optionalPort` is provided it is appended, e.g. `http://[2001:db8::1]:8080/`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1557)
- `link(options?: { className?: string; prefix?: string; v4?: boolean }): string` — Returns an HTML `` element whose `href` encodes the address in a URL hash fragment (default prefix `/#address=`). Useful for linking between pages of an address-inspector UI. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1575)
- `group(): string` — Groups an address. Returns an HTML fragment: each group is wrapped in a `` carrying the group classes an address-inspector UI hovers on. The address content is HTML-escaped; anything you concatenate around it is your responsibility. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1620)
- `regularExpressionString(substringSearch?: boolean): string` — Generate a regular expression string that can be used to find or validate all variations of this address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1672)
- `regularExpression(substringSearch?: boolean): RegExp` — Generate a regular expression that can be used to find or validate all variations of this address. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1726)
**Properties**
- `address4: Address4` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L97)
- `address: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L98)
- `addressMinusSuffix: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L99)
- `elidedGroups: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L100)
- `elisionBegin: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L101)
- `elisionEnd: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L102)
- `groups: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L103)
- `parsedAddress4: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L104)
- `parsedAddress: string[]` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L105)
- `parsedSubnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L106)
- `subnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L107)
- `subnetMask: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L108)
- `v4: boolean` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L109)
- `zone: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L110)
- `isInSubnet: (address: Address4 | Address6) => boolean` — Returns true if the given address is in the subnet of the current address. An `Address4` is never in the subnet of an `Address6`; convert with `Address6.fromAddress4()` or `to4()` to compare across families. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1277)
- `isHostInSubnet: (address: Address4 | Address6) => boolean` — Returns true if this address's host bits fall inside the given subnet, ignoring this address's own subnet mask. Prefer this over `isInSubnet` when classifying a single address, so the answer doesn't change with the CIDR suffix the caller happened to write — notably when the address came from untrusted input and the result backs a trust-boundary decision. An `Address4` is never in the subnet of an `Address6`; convert with `Address6.fromAddress4()` or `to4()` to compare across families. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1289)
- `isCorrect: () => boolean` — Returns true if the address is correct, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1295)
AddressError
**Constructor**
- `new AddressError(message: string, parseMessage?: string): AddressError`
**Properties**
- `parseMessage: string` — The offending address with the portion that failed to parse wrapped in ``, e.g. `2001:db8:::1`. Present only on errors thrown from a parse path that can point at a specific substring. This is an HTML fragment intended for an address-inspector UI. The address content is HTML-escaped, so it is safe to insert as-is; treat it as markup rather than as a plain-text message, and use `message` for anything that renders as text. [src](https://github.com/beaugunderson/ip-address/blob/main/src/address-error.ts#L13)
### Security
Vulnerabilities go through [GitHub's private vulnerability reporting](https://github.com/beaugunderson/ip-address/security/advisories/new); [SECURITY.md](./SECURITY.md) has the scope and what to expect. Confirmed issues get a fix, a release, and a public [advisory](https://github.com/beaugunderson/ip-address/security/advisories) with a CVE, rather than a quiet patch.
Releases are built and published by CI through npm trusted publishing. Every version from 10.2.1 onward carries a provenance attestation tying the tarball to the commit and workflow that built it. Check it with `npm audit signatures`.
If you are using the address-property checks as a security control, read [that section of SECURITY.md](./SECURITY.md#classifiers-are-not-an-ssrf-defense) first. `isPrivate()`, `isLoopback()`, `isInSubnet()` and their siblings classify an address that has already been parsed, which makes them one layer of an SSRF guard rather than the whole of it. A hostname that resolves to an internal address, a DNS record that changes after your check, or a redirect will all sail past a guard built only on them. Within that layer, use `isGlobal()` rather than an OR of the named classifiers: it is false for every block the IANA special-purpose registries mark as not globally reachable, including the ones with no classifier of their own.
### Used by
`ip-address` is downloaded ~86 million times per week, mostly via the Node proxy/agent ecosystem. The dependency chain runs through a handful of widely-used packages:
- [**socks**](https://github.com/JoshGlazebrook/socks) (~53M weekly) — SOCKS4/5 client for Node; depends on `ip-address` directly. The single biggest source of downloads.
- [**socks-proxy-agent**](https://github.com/TooTallNate/proxy-agents/tree/main/packages/socks-proxy-agent) (~55M weekly) — `http.Agent` for SOCKS proxies; depends on `socks`. Bundled by virtually every CLI that respects `HTTPS_PROXY`.
- [**npm**](https://github.com/npm/cli) and [**pnpm**](https://github.com/pnpm/pnpm) — both bundle `socks-proxy-agent` through their HTTP fetch stack (`make-fetch-happen` → `@npmcli/agent`), so every Node install on the planet pulls in `ip-address` as a transitive dependency.
- [**Puppeteer**](https://github.com/puppeteer/puppeteer) — `@puppeteer/browsers` uses `proxy-agent` for browser-binary downloads, which routes through `socks-proxy-agent` → `socks` → `ip-address`.
- [**proxy-agent**](https://github.com/TooTallNate/proxy-agents/tree/main/packages/proxy-agent) (~28M weekly) and [**pac-proxy-agent**](https://github.com/TooTallNate/proxy-agents/tree/main/packages/pac-proxy-agent) (~27M weekly) — auto-detecting proxy agents (HTTP/HTTPS/SOCKS/PAC) used widely in scraping, headless-browser, and CI tooling.
- [**cacache**](https://github.com/npm/cacache) (~40M weekly) — npm's content-addressable cache; pulls in the same fetch stack.
Beyond the proxy chain, `ip-address` has been used by Juniper Networks' Contrail, Ably's proxy-protocol implementation, Rackspace's serialization framework, IPFS, and the [SwitchyOmega](https://github.com/FelisCatus/SwitchyOmega) Chrome extension, among many others.
beaugunderson-ip-address-438375e/SECURITY.md 0000664 0000000 0000000 00000006427 15272410673 0020501 0 ustar 00root root 0000000 0000000 # Security policy
## Reporting a vulnerability
Report privately through [GitHub's private vulnerability reporting](https://github.com/beaugunderson/ip-address/security/advisories/new). Please don't open a public issue for a suspected vulnerability.
The most useful report is a short proof of concept: the input string, the method you called, what came back, and what you expected instead. If the problem is that this library disagrees with something else about what an address means, name the other parser. A resolver, a URL implementation, another library. That is what makes the disagreement reproducible.
Reports are acknowledged as soon as practical. Confirmed issues get a fix, a release, and a published advisory with a CVE. Reporters are credited by GitHub handle unless they would rather not be.
## Supported versions
Fixes go out against the latest published version. There are no long-term support branches, so upgrading is the supported path.
## Scope
In scope is anything that makes this library report something untrue about an address. A validation gap. A parse result that disagrees with the resolver the address will actually be handed to. A classifier returning the wrong answer for well-formed input. A crash on input that should have been rejected cleanly.
Out of scope are vulnerabilities in packages that depend on this one, and reports whose only substance is that an application used these methods as its sole defense. The next section explains why.
## Classifiers are not an SSRF defense
`isPrivate()`, `isLoopback()`, `isLinkLocal()`, `isInSubnet()` and their siblings answer a question about an address that has already been parsed. That makes them one useful layer in a Server-Side Request Forgery guard. It does not make them a guard.
Within that layer, ask one question, not several. `isGlobal()` is false for multicast, for every block the IANA special-purpose registries mark as not globally reachable, and for IPv6 space outside the `2000::/3` global unicast allocation, and an IPv4-mapped or NAT64 address answers for the IPv4 address it embeds. A guard written as an OR of named classifiers (`isPrivate() || isLoopback() || isLinkLocal() || …`) covers only the ranges it names, and the registries hold more ranges than there are names: `0.0.0.0/8`, the IETF protocol assignments in `192.0.0.0/24` and `2001::/23`, the documentation and benchmarking blocks, the discard-only prefix `100::/64`, the deprecated site-local `fec0::/10`. `test/data/iana-corpus.json` pins `isGlobal()` to the registries at every block boundary.
```js
if (!address.isGlobal()) reject();
```
Plenty gets past them, because plenty never reaches this library at all: a hostname that resolves to an internal address, a DNS record that changes between your check and your connection, a redirect to somewhere new.
`isValid()` returning `false` deserves particular care. It means "not a valid literal of this family". It does not mean "will not reach an internal host". `2130706433`, `0x7f000001` and `127.1` are all rejected here, and all three resolve to loopback. A guard that treats a rejected string as safe to pass along has an opening.
A guard that holds up resolves the hostname itself and checks the resolved address against the socket it is about to open, on every hop. Use these methods inside that, not instead of it.
beaugunderson-ip-address-438375e/coverage.sh 0000775 0000000 0000000 00000000076 15272410673 0021034 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
set -e
mkdir -p coverage
npm run test-ci
beaugunderson-ip-address-438375e/hooks/ 0000775 0000000 0000000 00000000000 15272410673 0020022 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/hooks/README.md 0000664 0000000 0000000 00000001350 15272410673 0021300 0 ustar 00root root 0000000 0000000 # Commit checks
`npm run docs:check` renders the API reference in memory and compares it with
`README.md`. It writes nothing and fails with the regeneration command when the
README is stale. CI and `hooks/pre-commit` use the same check.
The hook refuses unstaged changes to documentation inputs before checking them:
`src/`, `scripts/`, `README.md`, `tsconfig.json`, `package.json`, and the lockfile.
Stage the intended source and regenerated README together. The hook never
regenerates, stages, stashes, or discards user edits.
Run `npm run docs` explicitly to update the README. The fixture-based tests in
`test/docs-check-test.ts` exercise stale/current output and partial staging
without modifying the real repository's index or README.
beaugunderson-ip-address-438375e/hooks/pre-commit 0000775 0000000 0000000 00000001637 15272410673 0022033 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Installed by the prepare script, which points core.hooksPath at this
# directory. CI runs the same check, so catching it here saves a round trip.
set -e
# The checker reads the working tree. Refuse mixed index/worktree inputs rather
# than letting an unstaged fix hide a stale commit, or staging over user edits.
if ! git diff --quiet -- src scripts README.md tsconfig.json package.json package-lock.json; then
echo "Docs inputs have unstaged changes; stage the intended inputs before committing."
exit 1
fi
if [ -n "$(git ls-files --others --exclude-standard -- src scripts README.md tsconfig.json package.json package-lock.json)" ]; then
echo "Docs inputs include untracked files; stage the intended inputs before committing."
exit 1
fi
npm run --silent docs:check
if ! npm run --silent lint; then
echo
echo 'Lint failed. Run `npm run lint:fix` to correct what is mechanical.'
exit 1
fi
beaugunderson-ip-address-438375e/package-lock.json 0000664 0000000 0000000 00000617313 15272410673 0022126 0 ustar 00root root 0000000 0000000 {
"name": "ip-address",
"version": "10.7.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ip-address",
"version": "10.7.6",
"license": "MIT",
"devDependencies": {
"@types/chai": "^5.2.3",
"@types/mocha": "^10.0.10",
"@typescript-eslint/eslint-plugin": "^8.59.1",
"@typescript-eslint/parser": "^8.59.1",
"c8": "^11.0.0",
"chai": "^6.2.2",
"eslint": "^8.57.1",
"eslint_d": "^14.0.4",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
"mocha": "^12.0.3",
"monocart-coverage-reports": "^2.12.11",
"prettier": "^3.8.3",
"source-map-support": "^0.5.21",
"tsx": "^4.21.0",
"typedoc": "^0.28.19",
"typescript": "<5.6.0"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@bcoe/v8-coverage": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
"integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
"integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
"integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
"integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
"integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
"integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
"integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
"integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
"integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
"integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
"integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
"integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
"integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
"integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
"integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
"integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
"integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
"integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
"integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
"integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
"integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
"integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
"integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
"integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
"integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
"integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
"integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
"integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
},
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
}
},
"node_modules/@eslint-community/regexpp": {
"version": "4.12.2",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
"integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
"node_modules/@eslint/config-array": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz",
"integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/object-schema": "^2.1.4",
"debug": "^4.3.1",
"minimatch": "^3.1.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/core": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz",
"integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/eslintrc": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
"integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^9.6.0",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
"minimatch": "^3.1.2",
"strip-json-comments": "^3.1.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/eslintrc/node_modules/globals": {
"version": "13.24.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
"integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"type-fest": "^0.20.2"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/eslintrc/node_modules/type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
"license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/js": {
"version": "8.57.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@eslint/object-schema": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz",
"integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/plugin-kit": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz",
"integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^1.2.1",
"levn": "^0.4.1"
},
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz",
"integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@gerrit0/mini-shiki": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.23.0.tgz",
"integrity": "sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/engine-oniguruma": "^3.23.0",
"@shikijs/langs": "^3.23.0",
"@shikijs/themes": "^3.23.0",
"@shikijs/types": "^3.23.0",
"@shikijs/vscode-textmate": "^10.0.2"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
"integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
"deprecated": "Use @eslint/config-array instead",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@humanwhocodes/object-schema": "^2.0.3",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
"engines": {
"node": ">=10.10.0"
}
},
"node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
"dev": true,
"engines": {
"node": ">=12.22"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/nzakas"
}
},
"node_modules/@humanwhocodes/object-schema": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"deprecated": "Use @eslint/object-schema instead",
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/@humanwhocodes/retry": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz",
"integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=18.18"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/nzakas"
}
},
"node_modules/@istanbuljs/schema": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.stat": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.walk": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/@pkgr/core": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/pkgr"
}
},
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
"integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
"dev": true,
"license": "MIT"
},
"node_modules/@shikijs/engine-oniguruma": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz",
"integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "3.23.0",
"@shikijs/vscode-textmate": "^10.0.2"
}
},
"node_modules/@shikijs/langs": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz",
"integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "3.23.0"
}
},
"node_modules/@shikijs/themes": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz",
"integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "3.23.0"
}
},
"node_modules/@shikijs/types": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz",
"integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4"
}
},
"node_modules/@shikijs/types/node_modules/@types/hast": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
"integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "*"
}
},
"node_modules/@shikijs/vscode-textmate": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
"integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/chai": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
"integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/deep-eql": "*",
"assertion-error": "^2.0.1"
}
},
"node_modules/@types/deep-eql": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
"integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/mocha": {
"version": "10.0.10",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz",
"integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/unist": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.8.tgz",
"integrity": "sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==",
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.1.tgz",
"integrity": "sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.59.1",
"@typescript-eslint/type-utils": "8.59.1",
"@typescript-eslint/utils": "8.59.1",
"@typescript-eslint/visitor-keys": "8.59.1",
"ignore": "^7.0.5",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.5.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^8.59.1",
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.1.tgz",
"integrity": "sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.59.1",
"@typescript-eslint/types": "8.59.1",
"@typescript-eslint/typescript-estree": "8.59.1",
"@typescript-eslint/visitor-keys": "8.59.1",
"debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/project-service": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.1.tgz",
"integrity": "sha512-+MuHQlHiEr00Of/IQbE/MmEoi44znZHbR/Pz7Opq4HryUOlRi+/44dro9Ycy8Fyo+/024IWtw8m4JUMCGTYxDg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.59.1",
"@typescript-eslint/types": "^8.59.1",
"debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.1.tgz",
"integrity": "sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.59.1",
"@typescript-eslint/visitor-keys": "8.59.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.1.tgz",
"integrity": "sha512-/0nEyPbX7gRsk0Uwfe4ALwwgxuA66d/l2mhRDNlAvaj4U3juhUtJNq0DsY8M2AYwwb9rEq2hrC3IcIcEt++iJA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.1.tgz",
"integrity": "sha512-klWPBR2ciQHS3f++ug/mVnWKPjBUo7icEL3FAO1lhAR1Z1i5NQYZ1EannMSRYcq5qCv5wNALlXr6fksRHyYl7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.59.1",
"@typescript-eslint/typescript-estree": "8.59.1",
"@typescript-eslint/utils": "8.59.1",
"debug": "^4.4.3",
"ts-api-utils": "^2.5.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz",
"integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.1.tgz",
"integrity": "sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.59.1",
"@typescript-eslint/tsconfig-utils": "8.59.1",
"@typescript-eslint/types": "8.59.1",
"@typescript-eslint/visitor-keys": "8.59.1",
"debug": "^4.4.3",
"minimatch": "^10.2.2",
"semver": "^7.7.3",
"tinyglobby": "^0.2.15",
"ts-api-utils": "^2.5.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
"version": "10.2.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
"integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"brace-expansion": "^5.0.5"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.1.tgz",
"integrity": "sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.59.1",
"@typescript-eslint/types": "8.59.1",
"@typescript-eslint/typescript-estree": "8.59.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.59.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.1.tgz",
"integrity": "sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.59.1",
"eslint-visitor-keys": "^5.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
"dev": true,
"license": "ISC"
},
"node_modules/acorn": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/acorn-loose": {
"version": "8.5.2",
"resolved": "https://registry.npmjs.org/acorn-loose/-/acorn-loose-8.5.2.tgz",
"integrity": "sha512-PPvV6g8UGMGgjrMu+n/f9E/tCSkNQ2Y97eFvuVdJfG11+xdIeDcLyNdC8SHcrHbRqkfwLASdplyR6B6sKM1U4A==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.15.0"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.5",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
"integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.11.0"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ajv": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
"integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0"
},
"node_modules/array-buffer-byte-length": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
"integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"is-array-buffer": "^3.0.5"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array-includes": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
"integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"define-properties": "^1.2.1",
"es-abstract": "^1.24.0",
"es-object-atoms": "^1.1.1",
"get-intrinsic": "^1.3.0",
"is-string": "^1.1.1",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array.prototype.findlastindex": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
"integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.9",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"es-shim-unscopables": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array.prototype.flat": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
"integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.5",
"es-shim-unscopables": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array.prototype.flatmap": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
"integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.5",
"es-shim-unscopables": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/arraybuffer.prototype.slice": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
"integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"array-buffer-byte-length": "^1.0.1",
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.5",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"is-array-buffer": "^3.0.4"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/assertion-error": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
}
},
"node_modules/async-function": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"possible-typed-array-names": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/browser-stdout": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
"dev": true
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"node_modules/c8": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/c8/-/c8-11.0.0.tgz",
"integrity": "sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg==",
"dev": true,
"license": "ISC",
"dependencies": {
"@bcoe/v8-coverage": "^1.0.1",
"@istanbuljs/schema": "^0.1.3",
"find-up": "^5.0.0",
"foreground-child": "^3.1.1",
"istanbul-lib-coverage": "^3.2.0",
"istanbul-lib-report": "^3.0.1",
"istanbul-reports": "^3.1.6",
"test-exclude": "^8.0.0",
"v8-to-istanbul": "^9.0.0",
"yargs": "^17.7.2",
"yargs-parser": "^21.1.1"
},
"bin": {
"c8": "bin/c8.js"
},
"engines": {
"node": "20 || >=22"
},
"peerDependencies": {
"monocart-coverage-reports": "^2"
},
"peerDependenciesMeta": {
"monocart-coverage-reports": {
"optional": true
}
}
},
"node_modules/c8/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/c8/node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/c8/node_modules/foreground-child": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
"integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
"dev": true,
"license": "ISC",
"dependencies": {
"cross-spawn": "^7.0.6",
"signal-exit": "^4.0.1"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/c8/node_modules/glob": {
"version": "13.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
"integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"minimatch": "^10.2.2",
"minipass": "^7.1.3",
"path-scurry": "^2.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/c8/node_modules/minimatch": {
"version": "10.2.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"brace-expansion": "^5.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/c8/node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/c8/node_modules/test-exclude": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz",
"integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"@istanbuljs/schema": "^0.1.2",
"glob": "^13.0.6",
"minimatch": "^10.2.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/call-bind": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
"integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"get-intrinsic": "^1.3.0",
"set-function-length": "^1.2.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/chai": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
"integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/chokidar": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"dev": true,
"license": "MIT",
"dependencies": {
"readdirp": "^5.0.0"
},
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/cliui/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/cliui/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/cliui/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"license": "MIT"
},
"node_modules/cliui/node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/commander": {
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
"integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=20"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
"node_modules/confusing-browser-globals": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
"integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
"dev": true,
"license": "MIT"
},
"node_modules/console-grid": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/console-grid/-/console-grid-2.2.4.tgz",
"integrity": "sha512-OLjCRTiHhOpTRo9lQp/2FgJDyq5uQHwkEmVJulEnQ6JVf27oKKzXHZnNOv/e72V4++UdMZCrDWtvXW5sx4lyQg==",
"dev": true,
"license": "MIT"
},
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true,
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/data-view-buffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
"integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-data-view": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/data-view-byte-length": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
"integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-data-view": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/inspect-js"
}
},
"node_modules/data-view-byte-offset": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
"integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"is-data-view": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/define-properties": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
"dev": true,
"dependencies": {
"define-data-property": "^1.0.1",
"has-property-descriptors": "^1.0.0",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/diff": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
"integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"dev": true,
"dependencies": {
"esutils": "^2.0.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/eight-colors": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/eight-colors/-/eight-colors-1.3.3.tgz",
"integrity": "sha512-4B54S2Qi4pJjeHmCbDIsveQZWQ/TSSQng4ixYJ9/SYHHpeS5nYK0pzcHvWzWUfRsvJQjwoIENhAwqg59thQceg==",
"dev": true,
"license": "MIT"
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/es-abstract": {
"version": "1.24.2",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz",
"integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==",
"dev": true,
"license": "MIT",
"dependencies": {
"array-buffer-byte-length": "^1.0.2",
"arraybuffer.prototype.slice": "^1.0.4",
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"data-view-buffer": "^1.0.2",
"data-view-byte-length": "^1.0.2",
"data-view-byte-offset": "^1.0.1",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"es-set-tostringtag": "^2.1.0",
"es-to-primitive": "^1.3.0",
"function.prototype.name": "^1.1.8",
"get-intrinsic": "^1.3.0",
"get-proto": "^1.0.1",
"get-symbol-description": "^1.1.0",
"globalthis": "^1.0.4",
"gopd": "^1.2.0",
"has-property-descriptors": "^1.0.2",
"has-proto": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"internal-slot": "^1.1.0",
"is-array-buffer": "^3.0.5",
"is-callable": "^1.2.7",
"is-data-view": "^1.0.2",
"is-negative-zero": "^2.0.3",
"is-regex": "^1.2.1",
"is-set": "^2.0.3",
"is-shared-array-buffer": "^1.0.4",
"is-string": "^1.1.1",
"is-typed-array": "^1.1.15",
"is-weakref": "^1.1.1",
"math-intrinsics": "^1.1.0",
"object-inspect": "^1.13.4",
"object-keys": "^1.1.1",
"object.assign": "^4.1.7",
"own-keys": "^1.0.1",
"regexp.prototype.flags": "^1.5.4",
"safe-array-concat": "^1.1.3",
"safe-push-apply": "^1.0.0",
"safe-regex-test": "^1.1.0",
"set-proto": "^1.0.0",
"stop-iteration-iterator": "^1.1.0",
"string.prototype.trim": "^1.2.10",
"string.prototype.trimend": "^1.0.9",
"string.prototype.trimstart": "^1.0.8",
"typed-array-buffer": "^1.0.3",
"typed-array-byte-length": "^1.0.3",
"typed-array-byte-offset": "^1.0.4",
"typed-array-length": "^1.0.7",
"unbox-primitive": "^1.1.0",
"which-typed-array": "^1.1.19"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-shim-unscopables": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
"integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-to-primitive": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
"integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-callable": "^1.2.7",
"is-date-object": "^1.0.5",
"is-symbol": "^1.0.4"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/esbuild": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
"integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.1",
"@esbuild/android-arm": "0.28.1",
"@esbuild/android-arm64": "0.28.1",
"@esbuild/android-x64": "0.28.1",
"@esbuild/darwin-arm64": "0.28.1",
"@esbuild/darwin-x64": "0.28.1",
"@esbuild/freebsd-arm64": "0.28.1",
"@esbuild/freebsd-x64": "0.28.1",
"@esbuild/linux-arm": "0.28.1",
"@esbuild/linux-arm64": "0.28.1",
"@esbuild/linux-ia32": "0.28.1",
"@esbuild/linux-loong64": "0.28.1",
"@esbuild/linux-mips64el": "0.28.1",
"@esbuild/linux-ppc64": "0.28.1",
"@esbuild/linux-riscv64": "0.28.1",
"@esbuild/linux-s390x": "0.28.1",
"@esbuild/linux-x64": "0.28.1",
"@esbuild/netbsd-arm64": "0.28.1",
"@esbuild/netbsd-x64": "0.28.1",
"@esbuild/openbsd-arm64": "0.28.1",
"@esbuild/openbsd-x64": "0.28.1",
"@esbuild/openharmony-arm64": "0.28.1",
"@esbuild/sunos-x64": "0.28.1",
"@esbuild/win32-arm64": "0.28.1",
"@esbuild/win32-ia32": "0.28.1",
"@esbuild/win32-x64": "0.28.1"
}
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/eslint": {
"version": "8.57.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.4",
"@eslint/js": "8.57.1",
"@humanwhocodes/config-array": "^0.13.0",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.2",
"eslint-visitor-keys": "^3.4.3",
"espree": "^9.6.1",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^6.0.1",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
"globals": "^13.19.0",
"graphemer": "^1.4.0",
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
"optionator": "^0.9.3",
"strip-ansi": "^6.0.1",
"text-table": "^0.2.0"
},
"bin": {
"eslint": "bin/eslint.js"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint_d": {
"version": "14.0.4",
"resolved": "https://registry.npmjs.org/eslint_d/-/eslint_d-14.0.4.tgz",
"integrity": "sha512-VZuLiR03gKOCbXptTSrjfhmL4GBfGswyq2gJWUSDqMSc37XR2ryuKUtnLe1Y3+cphI7Rn7S9sHgXAFYDno3RiQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"eslint": "^9.8.0",
"supports-color": "^9.4.0"
},
"bin": {
"eslint_d": "bin/eslint_d.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/eslint_d/node_modules/@eslint/eslintrc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
"integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^10.0.1",
"globals": "^14.0.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
"minimatch": "^3.1.2",
"strip-json-comments": "^3.1.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint_d/node_modules/@eslint/js": {
"version": "9.11.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.1.tgz",
"integrity": "sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/eslint_d/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/eslint_d/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/eslint_d/node_modules/chalk/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/eslint_d/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/eslint_d/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"license": "MIT"
},
"node_modules/eslint_d/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint_d/node_modules/eslint": {
"version": "9.11.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.1.tgz",
"integrity": "sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.11.0",
"@eslint/config-array": "^0.18.0",
"@eslint/core": "^0.6.0",
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "9.11.1",
"@eslint/plugin-kit": "^0.2.0",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.3.0",
"@nodelib/fs.walk": "^1.2.8",
"@types/estree": "^1.0.6",
"@types/json-schema": "^7.0.15",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.0.2",
"eslint-visitor-keys": "^4.0.0",
"espree": "^10.1.0",
"esquery": "^1.5.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^8.0.0",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
"json-stable-stringify-without-jsonify": "^1.0.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
"optionator": "^0.9.3",
"strip-ansi": "^6.0.1",
"text-table": "^0.2.0"
},
"bin": {
"eslint": "bin/eslint.js"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://eslint.org/donate"
},
"peerDependencies": {
"jiti": "*"
},
"peerDependenciesMeta": {
"jiti": {
"optional": true
}
}
},
"node_modules/eslint_d/node_modules/eslint-scope": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz",
"integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint_d/node_modules/eslint-visitor-keys": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz",
"integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint_d/node_modules/espree": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz",
"integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.12.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^4.1.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint_d/node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"flat-cache": "^4.0.0"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/eslint_d/node_modules/flat-cache": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
"dev": true,
"license": "MIT",
"dependencies": {
"flatted": "^3.2.9",
"keyv": "^4.5.4"
},
"engines": {
"node": ">=16"
}
},
"node_modules/eslint_d/node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/eslint_d/node_modules/globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint_d/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/eslint_d/node_modules/supports-color": {
"version": "9.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
"integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/eslint-config-airbnb-base": {
"version": "15.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
"integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
"dev": true,
"license": "MIT",
"dependencies": {
"confusing-browser-globals": "^1.0.10",
"object.assign": "^4.1.2",
"object.entries": "^1.1.5",
"semver": "^6.3.0"
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
},
"peerDependencies": {
"eslint": "^7.32.0 || ^8.2.0",
"eslint-plugin-import": "^2.25.2"
}
},
"node_modules/eslint-config-airbnb-base/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/eslint-config-prettier": {
"version": "10.1.8",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true,
"license": "MIT",
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
"funding": {
"url": "https://opencollective.com/eslint-config-prettier"
},
"peerDependencies": {
"eslint": ">=7.0.0"
}
},
"node_modules/eslint-import-resolver-node": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
"dev": true,
"dependencies": {
"debug": "^3.2.7",
"is-core-module": "^2.13.0",
"resolve": "^1.22.4"
}
},
"node_modules/eslint-import-resolver-node/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/eslint-module-utils": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
"integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^3.2.7"
},
"engines": {
"node": ">=4"
},
"peerDependenciesMeta": {
"eslint": {
"optional": true
}
}
},
"node_modules/eslint-module-utils/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/eslint-plugin-filenames": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-filenames/-/eslint-plugin-filenames-1.3.2.tgz",
"integrity": "sha512-tqxJTiEM5a0JmRCUYQmxw23vtTxrb2+a3Q2mMOPhFxvt7ZQQJmdiuMby9B/vUAuVMghyP7oET+nIf6EO6CBd/w==",
"dev": true,
"dependencies": {
"lodash.camelcase": "4.3.0",
"lodash.kebabcase": "4.1.1",
"lodash.snakecase": "4.1.1",
"lodash.upperfirst": "4.3.1"
},
"peerDependencies": {
"eslint": "*"
}
},
"node_modules/eslint-plugin-import": {
"version": "2.32.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
"array.prototype.findlastindex": "^1.2.6",
"array.prototype.flat": "^1.3.3",
"array.prototype.flatmap": "^1.3.3",
"debug": "^3.2.7",
"doctrine": "^2.1.0",
"eslint-import-resolver-node": "^0.3.9",
"eslint-module-utils": "^2.12.1",
"hasown": "^2.0.2",
"is-core-module": "^2.16.1",
"is-glob": "^4.0.3",
"minimatch": "^3.1.2",
"object.fromentries": "^2.0.8",
"object.groupby": "^1.0.3",
"object.values": "^1.2.1",
"semver": "^6.3.1",
"string.prototype.trimend": "^1.0.9",
"tsconfig-paths": "^3.15.0"
},
"engines": {
"node": ">=4"
},
"peerDependencies": {
"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
}
},
"node_modules/eslint-plugin-import/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/eslint-plugin-import/node_modules/doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"dependencies": {
"esutils": "^2.0.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/eslint-plugin-import/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/eslint-plugin-prettier": {
"version": "5.5.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz",
"integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==",
"dev": true,
"license": "MIT",
"dependencies": {
"prettier-linter-helpers": "^1.0.1",
"synckit": "^0.11.12"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint-plugin-prettier"
},
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
"@types/eslint": {
"optional": true
},
"eslint-config-prettier": {
"optional": true
}
}
},
"node_modules/eslint-plugin-sort-imports-es6-autofix": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-sort-imports-es6-autofix/-/eslint-plugin-sort-imports-es6-autofix-0.6.0.tgz",
"integrity": "sha512-2NVaBGF9NN+727Fyq+jJYihdIeegjXeUUrZED9Q8FVB8MsV3YQEyXG96GVnXqWt0pmn7xfCZOZf3uKnIhBrfeQ==",
"dev": true,
"peerDependencies": {
"eslint": ">=7.7.0"
}
},
"node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
"dev": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/eslint/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/eslint/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/eslint/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/eslint/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint/node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.3"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/eslint/node_modules/globals": {
"version": "13.22.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz",
"integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/eslint/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/eslint/node_modules/type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/espree": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/esquery": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
"integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
"dev": true,
"dependencies": {
"estraverse": "^5.1.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"dependencies": {
"estraverse": "^5.2.0"
},
"engines": {
"node": ">=4.0"
}
},
"node_modules/estraverse": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
"engines": {
"node": ">=4.0"
}
},
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
"node_modules/fastq": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
"dev": true,
"dependencies": {
"reusify": "^1.0.4"
}
},
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
"dev": true,
"dependencies": {
"flat-cache": "^3.0.4"
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"dependencies": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/find-up-simple": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz",
"integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/flat-cache": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz",
"integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==",
"dev": true,
"dependencies": {
"flatted": "^3.2.7",
"keyv": "^4.5.3",
"rimraf": "^3.0.2"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/flatted": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true,
"license": "ISC"
},
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/foreground-child": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-4.0.3.tgz",
"integrity": "sha512-yeXZaNbCBGaT9giTpLPBdtedzjwhlJBUoL/R4BVQU5mn0TQXOHwVIl1Q2DMuBIdNno4ktA1abZ7dQFVxD6uHxw==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"signal-exit": "^4.0.1"
},
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/foreground-child/node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/function.prototype.name": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
"integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"define-properties": "^1.2.1",
"functions-have-names": "^1.2.3",
"hasown": "^2.0.2",
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/functions-have-names": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/generator-function": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
"integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/get-symbol-description": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
"integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/globalthis": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"define-properties": "^1.2.1",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/graphemer": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true
},
"node_modules/has-bigints": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
"integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-proto": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
"integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
"dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true,
"engines": {
"node": ">=0.8.19"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
"integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"hasown": "^2.0.2",
"side-channel": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
"integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-async-function": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
"integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"async-function": "^1.0.0",
"call-bound": "^1.0.3",
"get-proto": "^1.0.1",
"has-tostringtag": "^1.0.2",
"safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-bigint": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
"integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-bigints": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-boolean-object": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
"integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-core-module": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-data-view": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
"integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"get-intrinsic": "^1.2.6",
"is-typed-array": "^1.1.13"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-date-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
"integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-finalizationregistry": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
"integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/is-generator-function": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
"integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.4",
"generator-function": "^2.0.0",
"get-proto": "^1.0.1",
"has-tostringtag": "^1.0.2",
"safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-negative-zero": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
"integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-number-object": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
"integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-path-inside": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-set": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-shared-array-buffer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
"integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-string": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
"integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-symbol": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
"integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"has-symbols": "^1.1.0",
"safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-unicode-supported": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-weakmap": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-weakref": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
"integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-weakset": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
"integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"dev": true,
"license": "MIT"
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
"node_modules/istanbul-lib-coverage": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
"integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=8"
}
},
"node_modules/istanbul-lib-report": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
"integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
"dev": true,
"dependencies": {
"istanbul-lib-coverage": "^3.0.0",
"make-dir": "^4.0.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/istanbul-lib-report/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/istanbul-lib-report/node_modules/make-dir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
"integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
"dev": true,
"dependencies": {
"semver": "^7.5.3"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/istanbul-lib-report/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/istanbul-reports": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
"integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"html-escaper": "^2.0.0",
"istanbul-lib-report": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/js-yaml": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
"integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"license": "MIT"
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true
},
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"dev": true,
"license": "MIT",
"dependencies": {
"json-buffer": "3.0.1"
}
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
"dev": true,
"dependencies": {
"prelude-ls": "^1.2.1",
"type-check": "~0.4.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/linkify-it": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz",
"integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/markdown-it"
}
],
"license": "MIT",
"dependencies": {
"uc.micro": "^2.0.0"
}
},
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"dependencies": {
"p-locate": "^5.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
"dev": true
},
"node_modules/lodash.kebabcase": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
"integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==",
"dev": true
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
"node_modules/lodash.snakecase": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==",
"dev": true
},
"node_modules/lodash.upperfirst": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz",
"integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==",
"dev": true
},
"node_modules/lunr": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
"dev": true,
"license": "MIT"
},
"node_modules/lz-utils": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/lz-utils/-/lz-utils-2.1.1.tgz",
"integrity": "sha512-d3Thjos0PSJQAoyMj6vipSSrtrRHS7DImqUNR8x9NW3+zQIftPIbMJAWhi5nPdg5Q9zHz6lxtN8kp/VdMlhi/Q==",
"dev": true,
"license": "MIT"
},
"node_modules/markdown-it": {
"version": "14.3.3",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.3.tgz",
"integrity": "sha512-L//tDAkjTjJCU6pBUSBTgs3Kg4InVaZuUZog/b6V12UKhcDQ7S78877ibbCanRExwPuYP1CZD7Gd2dxSy1GXRg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/markdown-it"
}
],
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.5.0",
"linkify-it": "^5.0.2",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
},
"bin": {
"markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
"dev": true,
"license": "MIT"
},
"node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
"integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
"dev": true,
"license": "BlueOak-1.0.0",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/mocha": {
"version": "12.0.3",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-12.0.3.tgz",
"integrity": "sha512-beammieDdiWdkjANWeWPpkxUROYGi5FN88fPOkLiticz7HTg3Y+Pho3EYE6SUdcuWnZ3h2WD8EXCA55JF4o6wg==",
"dev": true,
"license": "MIT",
"dependencies": {
"browser-stdout": "^1.3.1",
"chokidar": "^5.0.0",
"debug": "^4.3.5",
"diff": "^9.0.0",
"find-up-simple": "^1.0.1",
"glob": "^13.0.0",
"is-path-inside": "^4.0.0",
"is-unicode-supported": "^0.1.0",
"js-yaml": "^5.0.0",
"minimatch": "^10.2.2",
"ms": "^2.1.3",
"picocolors": "^1.1.1",
"serialize-javascript": "^7.1.1",
"strip-json-comments": "^5.0.3",
"supports-color": "^8.1.1",
"workerpool": "^10.0.0"
},
"bin": {
"mocha": "bin/mocha.js"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/mocha/node_modules/argparse": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-3.0.4.tgz",
"integrity": "sha512-fwWK3Zq22l4XJJjx5mcBHGikIk+hJqO+32dPm0Jur7+rtG5x1scOjSfdT9ZKeWHPpsya/l0HHK4tDImBkTrtvA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"license": "PSF-2.0"
},
"node_modules/mocha/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/mocha/node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/mocha/node_modules/glob": {
"version": "13.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
"integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"minimatch": "^10.2.2",
"minipass": "^7.1.3",
"path-scurry": "^2.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/mocha/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/mocha/node_modules/is-path-inside": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz",
"integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mocha/node_modules/js-yaml": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.5.0.tgz",
"integrity": "sha512-paNr4LFIFPjeeSmwNYdrb8FafLLG/Cr2Af3GjbsHJ5CxIjH4r0c2emlmRdAtpPAieP1gRVzk6buBbVP5gBMGAg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"license": "MIT",
"dependencies": {
"argparse": "^3.0.3"
},
"bin": {
"js-yaml": "bin/js-yaml.mjs"
}
},
"node_modules/mocha/node_modules/minimatch": {
"version": "10.2.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
"integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"brace-expansion": "^5.0.8"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/mocha/node_modules/strip-json-comments": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz",
"integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/monocart-coverage-reports": {
"version": "2.12.11",
"resolved": "https://registry.npmjs.org/monocart-coverage-reports/-/monocart-coverage-reports-2.12.11.tgz",
"integrity": "sha512-yo4/FdUdFIWoc9OjhBZCNXM95tYHS4e8nov9Q3AGbpvteT/W5aQSc4B+Q0nhmedZFvjvm3BUH/Xu9GT2n/0wkw==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.16.0",
"acorn-loose": "^8.5.2",
"acorn-walk": "^8.3.5",
"commander": "^14.0.3",
"console-grid": "^2.2.4",
"eight-colors": "^1.3.3",
"foreground-child": "^4.0.3",
"istanbul-lib-coverage": "^3.2.2",
"istanbul-lib-report": "^3.0.1",
"istanbul-reports": "^3.2.0",
"lz-utils": "^2.1.1",
"monocart-locator": "^1.0.3"
},
"bin": {
"mcr": "lib/cli.js"
}
},
"node_modules/monocart-locator": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/monocart-locator/-/monocart-locator-1.0.3.tgz",
"integrity": "sha512-pe29W2XAoA1WQmZZqxXoP7s06ZEXUhcb81086v68cqjk1HnVL7Q/iU/WJnnetxjPcLqwb4qG8vaSGUOMQU602g==",
"dev": true,
"license": "MIT"
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT"
},
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/object.assign": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0",
"has-symbols": "^1.1.0",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object.entries": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
"integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/object.fromentries": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
"integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.2",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object.groupby": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/object.values": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
"integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"dependencies": {
"wrappy": "1"
}
},
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
"integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
"dev": true,
"dependencies": {
"@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
"type-check": "^0.4.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/own-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
"integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.6",
"object-keys": "^1.1.1",
"safe-push-apply": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"dependencies": {
"yocto-queue": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-locate": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"dependencies": {
"p-limit": "^3.0.2"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/path-scurry": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
"integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/path-scurry/node_modules/lru-cache": {
"version": "11.2.6",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz",
"integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==",
"dev": true,
"license": "BlueOak-1.0.0",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "ISC"
},
"node_modules/possible-typed-array-names": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true,
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/prettier": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-linter-helpers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz",
"integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-diff": "^1.1.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/punycode.js": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/readdirp": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz",
"integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
"integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.9",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0",
"get-intrinsic": "^1.2.7",
"get-proto": "^1.0.1",
"which-builtin-type": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-errors": "^1.3.0",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"set-function-name": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/resolve": {
"version": "1.22.6",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz",
"integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==",
"dev": true,
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
}
},
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"queue-microtask": "^1.2.2"
}
},
"node_modules/safe-array-concat": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz",
"integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.9",
"call-bound": "^1.0.4",
"get-intrinsic": "^1.3.0",
"has-symbols": "^1.1.0",
"isarray": "^2.0.5"
},
"engines": {
"node": ">=0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-push-apply": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
"integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"isarray": "^2.0.5"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-regex-test": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"is-regex": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/semver": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/serialize-javascript": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.4.tgz",
"integrity": "sha512-FqlEuoTq/zRmA4Lg6aOqyH3lCHbUtCB0bmHCeFniX2GBdDqMJM3FwdvEhlE5Pim1dlt2FfBdVPmUNNiGhhKqpw==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/set-function-name": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"functions-have-names": "^1.2.3",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/set-proto": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
"integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/side-channel": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3",
"side-channel-list": "^1.0.0",
"side-channel-map": "^1.0.1",
"side-channel-weakmap": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-list": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
"integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.4"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-map": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-weakmap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3",
"side-channel-map": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/stop-iteration-iterator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
"integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"internal-slot": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/string-width/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/string.prototype.trim": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
"integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.2",
"define-data-property": "^1.1.4",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.5",
"es-object-atoms": "^1.0.0",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/string.prototype.trimend": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
"integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.2",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/string.prototype.trimstart": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/synckit": {
"version": "0.11.12",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz",
"integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.2.9"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/synckit"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true
},
"node_modules/tinyglobby": {
"version": "0.2.16",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.4"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/tinyglobby/node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/ts-api-utils": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
"integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18.12"
},
"peerDependencies": {
"typescript": ">=4.8.4"
}
},
"node_modules/tsconfig-paths": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/json5": "^0.0.29",
"json5": "^1.0.2",
"minimist": "^1.2.6",
"strip-bom": "^3.0.0"
}
},
"node_modules/tsconfig-paths/node_modules/json5": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"minimist": "^1.2.0"
},
"bin": {
"json5": "lib/cli.js"
}
},
"node_modules/tsconfig-paths/node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/tsx": {
"version": "4.23.1",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.1.tgz",
"integrity": "sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "~0.28.0"
},
"bin": {
"tsx": "dist/cli.mjs"
},
"engines": {
"node": ">=18.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
}
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
"dependencies": {
"prelude-ls": "^1.2.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/typed-array-byte-length": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
"integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"for-each": "^0.3.3",
"gopd": "^1.2.0",
"has-proto": "^1.2.0",
"is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typed-array-byte-offset": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
"integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"for-each": "^0.3.3",
"gopd": "^1.2.0",
"has-proto": "^1.2.0",
"is-typed-array": "^1.1.15",
"reflect.getprototypeof": "^1.0.9"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typed-array-length": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
"integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"for-each": "^0.3.3",
"gopd": "^1.0.1",
"is-typed-array": "^1.1.13",
"possible-typed-array-names": "^1.0.0",
"reflect.getprototypeof": "^1.0.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typedoc": {
"version": "0.28.19",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.19.tgz",
"integrity": "sha512-wKh+lhdmMFivMlc6vRRcMGXeGEHGU2g8a2CkPTJjJlwRf1iXbimWIPcFolCqe4E0d/FRtGszpIrsp3WLpDB8Pw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@gerrit0/mini-shiki": "^3.23.0",
"lunr": "^2.3.9",
"markdown-it": "^14.1.1",
"minimatch": "^10.2.5",
"yaml": "^2.8.3"
},
"bin": {
"typedoc": "bin/typedoc"
},
"engines": {
"node": ">= 18",
"pnpm": ">= 10"
},
"peerDependencies": {
"typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x"
}
},
"node_modules/typedoc/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/typedoc/node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/typedoc/node_modules/minimatch": {
"version": "10.2.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
"integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"brace-expansion": "^5.0.5"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/typescript": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"dev": true,
"license": "MIT"
},
"node_modules/unbox-primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
"integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-bigints": "^1.0.2",
"has-symbols": "^1.1.0",
"which-boxed-primitive": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
},
"node_modules/v8-to-istanbul": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
"integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
"dev": true,
"license": "ISC",
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.12",
"@types/istanbul-lib-coverage": "^2.0.1",
"convert-source-map": "^2.0.0"
},
"engines": {
"node": ">=10.12.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/which-boxed-primitive": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
"integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-bigint": "^1.1.0",
"is-boolean-object": "^1.2.1",
"is-number-object": "^1.1.1",
"is-string": "^1.1.1",
"is-symbol": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-builtin-type": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
"integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"function.prototype.name": "^1.1.6",
"has-tostringtag": "^1.0.2",
"is-async-function": "^2.0.0",
"is-date-object": "^1.1.0",
"is-finalizationregistry": "^1.1.0",
"is-generator-function": "^1.0.10",
"is-regex": "^1.2.1",
"is-weakref": "^1.0.2",
"isarray": "^2.0.5",
"which-boxed-primitive": "^1.1.0",
"which-collection": "^1.0.2",
"which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-collection": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-map": "^2.0.3",
"is-set": "^2.0.3",
"is-weakmap": "^2.0.2",
"is-weakset": "^2.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-typed-array": {
"version": "1.1.20",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
"integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
"dev": true,
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"for-each": "^0.3.5",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/workerpool": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-10.0.3.tgz",
"integrity": "sha512-6z2Iis68Wqth93/G/wJP9u+R3O+d2XTlgWChGCwuT1qLbBsOYueGRZuJ++v3mtDP5KjYdy+WzvWC+VWETSVXJA==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=10"
}
},
"node_modules/yaml": {
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
"dev": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14.6"
},
"funding": {
"url": "https://github.com/sponsors/eemeli"
}
},
"node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
}
}
beaugunderson-ip-address-438375e/package.json 0000664 0000000 0000000 00000004471 15272410673 0021173 0 ustar 00root root 0000000 0000000 {
"name": "ip-address",
"description": "A library for parsing IPv4 and IPv6 IP addresses in node and the browser.",
"keywords": [
"ip",
"ipv4",
"ipv6",
"address",
"cidr",
"subnet",
"netmask",
"validate",
"validation",
"parse",
"arpa",
"bigint",
"browser"
],
"version": "10.7.6",
"author": "Beau Gunderson (https://beaugunderson.com/)",
"license": "MIT",
"main": "dist/ip-address.js",
"types": "dist/ip-address.d.ts",
"scripts": {
"docs": "tsx scripts/build-readme.ts",
"docs:check": "tsx scripts/build-readme.ts --check",
"build": "rm -rf dist; mkdir dist; tsc",
"prepack": "npm run docs && npm run build",
"prepare": "git config core.hooksPath hooks || true",
"lint": "prettier --check . && eslint . --ext .ts,.js --max-warnings 0",
"lint:fix": "prettier --write . && eslint . --ext .ts,.js --max-warnings 0 --fix",
"test-ci": "c8 --experimental-monocart mocha",
"test": "mocha",
"watch": "mocha --watch"
},
"c8": {
"include": [
"src/**/*.ts"
],
"exclude": [
"**/*.d.ts",
"src/ip-address.ts",
"src/v4/constants.ts",
"src/v6/constants.ts"
],
"reporter": [
"html",
"lcov",
"text"
]
},
"engines": {
"node": ">= 12"
},
"sideEffects": false,
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "https://github.com/beaugunderson/ip-address.git"
},
"overrides": {
"diff": "^8.0.3",
"serialize-javascript": "^7.0.5",
"@eslint/plugin-kit": "^0.7.1"
},
"devDependencies": {
"@types/chai": "^5.2.3",
"@types/mocha": "^10.0.10",
"@typescript-eslint/eslint-plugin": "^8.59.1",
"@typescript-eslint/parser": "^8.59.1",
"c8": "^11.0.0",
"chai": "^6.2.2",
"eslint": "^8.57.1",
"eslint_d": "^14.0.4",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
"mocha": "^12.0.3",
"monocart-coverage-reports": "^2.12.11",
"prettier": "^3.8.3",
"source-map-support": "^0.5.21",
"tsx": "^4.21.0",
"typedoc": "^0.28.19",
"typescript": "<5.6.0"
}
}
beaugunderson-ip-address-438375e/scripts/ 0000775 0000000 0000000 00000000000 15272410673 0020366 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/scripts/build-readme.ts 0000664 0000000 0000000 00000020607 15272410673 0023275 0 ustar 00root root 0000000 0000000 #!/usr/bin/env tsx
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as TypeDoc from 'typedoc';
const ROOT = path.resolve(__dirname, '..');
const TEMPLATE_PATH = path.join(ROOT, 'scripts/readme-template.md');
const README_PATH = path.join(ROOT, 'README.md');
const ENTRY_POINTS = [path.join(ROOT, 'src/ip-address.ts')];
const REPO_BLOB_BASE = 'https://github.com/beaugunderson/ip-address/blob/main';
const START_MARKER = '';
const END_MARKER = '';
type SourceRef = { fileName: string; line: number };
function summaryFor(reflection: TypeDoc.Reflection): string {
const parts = reflection.comment?.summary;
if (!parts || parts.length === 0) return '';
return parts
.map((p) => p.text)
.join('')
.replace(/\s+/g, ' ')
.trim();
}
function renderType(type: TypeDoc.SomeType | undefined): string {
return type ? type.toString() : 'void';
}
function renderParams(sig: TypeDoc.SignatureReflection): string {
return (
(sig.parameters ?? [])
// `this` is a TypeScript type annotation, not an argument callers pass
.filter((p) => p.name !== 'this')
.map((p) => {
// TypeDoc sets isOptional inconsistently for parameters carrying a
// default, so treat the presence of a default as optional too
const optional = p.flags.isOptional || p.defaultValue !== undefined ? '?' : '';
return `${p.name}${optional}: ${renderType(p.type)}`;
})
.join(', ')
);
}
function renderSignature(name: string, sig: TypeDoc.SignatureReflection): string {
return `${name}(${renderParams(sig)}): ${renderType(sig.type)}`;
}
/**
* Properties holding a function (the prototype-assigned `isInSubnet` and
* friends) render through the same parameter rules as methods, so a `this`
* annotation doesn't read as a caller-supplied argument.
*/
function renderPropertyType(type: TypeDoc.SomeType | undefined): string {
const sig = type?.type === 'reflection' ? type.declaration.signatures?.[0] : undefined;
return sig ? `(${renderParams(sig)}) => ${renderType(sig.type)}` : renderType(type);
}
function sourceLink(sources: SourceRef[] | undefined): string {
if (!sources || sources.length === 0) return '';
const { fileName, line } = sources[0];
const relativePath = fileName.startsWith('src/') ? fileName : `src/${fileName}`;
return `[src](${REPO_BLOB_BASE}/${relativePath}#L${line})`;
}
function renderMethod(method: TypeDoc.DeclarationReflection): string[] {
const { isStatic } = method.flags;
const sigs = method.signatures ?? [];
const lines: string[] = [];
for (const sig of sigs) {
const prefix = isStatic ? 'static ' : '';
const code = `\`${prefix}${renderSignature(method.name, sig)}\``;
const summary = summaryFor(sig) || summaryFor(method);
const link = sourceLink(method.sources as SourceRef[] | undefined);
const tail = [summary, link].filter(Boolean).join(' ');
lines.push(`- ${code}${tail ? ` — ${tail}` : ''}`);
}
return lines;
}
function renderProperty(prop: TypeDoc.DeclarationReflection): string {
const { isStatic } = prop.flags;
const prefix = isStatic ? 'static ' : '';
const typeStr = renderPropertyType(prop.type);
const code = `\`${prefix}${prop.name}: ${typeStr}\``;
const summary = summaryFor(prop);
const link = sourceLink(prop.sources as SourceRef[] | undefined);
const tail = [summary, link].filter(Boolean).join(' ');
return `- ${code}${tail ? ` — ${tail}` : ''}`;
}
const CLASS_ORDER = ['Address4', 'Address6', 'AddressError'];
function escapeHtml(text: string): string {
return text
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"');
}
/**
* The one-line blurb shown next to the class name on the collapsed row. The
* summary is markdown, but a `` element renders HTML rather than
* markdown, so backtick spans become `` and the rest is escaped.
*/
function renderSummaryLine(summary: string): string {
return summary
.split(/(`[^`]+`)/)
.map((part) =>
part.startsWith('`') && part.endsWith('`') && part.length > 1
? `${escapeHtml(part.slice(1, -1))}`
: escapeHtml(part),
)
.join('');
}
function firstSentence(summary: string): string {
const match = summary.match(/^(.*?[.!?])(\s|$)/);
return match ? match[1] : summary;
}
function renderClass(cls: TypeDoc.DeclarationReflection): string {
const out: string[] = [];
const summary = summaryFor(cls);
const anchor = cls.name.toLowerCase();
// Each class is collapsed so the reader can open one at a time; the API
// block is tens of thousands of characters when laid out flat. The anchor
// keeps `README.md#address6` style deep links working now that the class
// name lives in a `` rather than a markdown heading.
const lead = summary ? firstSentence(summary) : '';
const blurb = lead ? ` — ${renderSummaryLine(lead)}` : '';
out.push('');
out.push(
`${escapeHtml(cls.name)}${blurb}
`,
);
out.push('');
// The collapsed row already carries the first sentence, so the body repeats
// the summary only when there is more to it than that.
if (summary && summary !== lead) {
out.push(summary);
out.push('');
}
const ctor = cls.children?.find((c) => c.kind === TypeDoc.ReflectionKind.Constructor);
if (ctor && ctor.signatures) {
out.push('**Constructor**');
out.push('');
for (const sig of ctor.signatures) {
out.push(`- \`new ${renderSignature(cls.name, sig)}\``);
}
out.push('');
}
const staticMethods: string[] = [];
const instanceMethods: string[] = [];
const properties: string[] = [];
for (const child of cls.children ?? []) {
if (child.flags.isPrivate) continue;
if (child.name.startsWith('_')) continue;
if (child.kind === TypeDoc.ReflectionKind.Method) {
const rendered = renderMethod(child);
if (child.flags.isStatic) staticMethods.push(...rendered);
else instanceMethods.push(...rendered);
} else if (child.kind === TypeDoc.ReflectionKind.Property) {
properties.push(renderProperty(child));
}
}
if (staticMethods.length) {
out.push('**Static methods**');
out.push('');
out.push(...staticMethods);
out.push('');
}
if (instanceMethods.length) {
out.push('**Instance methods**');
out.push('');
out.push(...instanceMethods);
out.push('');
}
if (properties.length) {
out.push('**Properties**');
out.push('');
out.push(...properties);
out.push('');
}
out.push(' ');
out.push('');
return out.join('\n');
}
async function main() {
const app = await TypeDoc.Application.bootstrapWithPlugins({
entryPoints: ENTRY_POINTS,
tsconfig: path.join(ROOT, 'tsconfig.json'),
excludePrivate: true,
excludeInternal: true,
excludeExternals: true,
skipErrorChecking: true,
sort: ['source-order'],
logLevel: 'Error',
blockTags: ['@param', '@returns', '@example', '@throws', '@deprecated', '@see'],
});
const project = await app.convert();
if (!project) throw new Error('TypeDoc failed to convert the project');
const classes = (project.children ?? [])
.filter((c) => c.kind === TypeDoc.ReflectionKind.Class)
.sort((a, b) => CLASS_ORDER.indexOf(a.name) - CLASS_ORDER.indexOf(b.name));
const sections: string[] = [];
for (const cls of classes) {
sections.push(renderClass(cls));
}
const apiBlock = sections.join('\n').trimEnd();
const template = fs.readFileSync(TEMPLATE_PATH, 'utf8');
const startIdx = template.indexOf(START_MARKER);
const endIdx = template.indexOf(END_MARKER);
if (startIdx === -1 || endIdx === -1) {
throw new Error(`Markers ${START_MARKER} / ${END_MARKER} not found in template`);
}
const before = template.slice(0, startIdx + START_MARKER.length);
const after = template.slice(endIdx);
const next = `${before}\n\n${apiBlock}\n\n${after}`;
if (process.argv.includes('--check')) {
if (!fs.existsSync(README_PATH) || fs.readFileSync(README_PATH, 'utf8') !== next) {
throw new Error('README.md is out of date; run `npm run docs` and stage the result.');
}
console.log('README.md is current (no files written).');
} else {
fs.writeFileSync(README_PATH, next);
console.log(
`Wrote ${README_PATH} (${classes.length} classes, ${apiBlock.length} chars of API)`,
);
}
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
beaugunderson-ip-address-438375e/scripts/gen-iana-corpus.py 0000775 0000000 0000000 00000014576 15272410673 0023750 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
"""Regenerate test/data/iana-corpus.json from the IANA special-purpose
address registries.
scripts/gen-iana-corpus.py # regenerate from the checked-in CSVs
scripts/gen-iana-corpus.py --fetch # refresh the CSVs from iana.org first
For every block in both special-purpose registries and in the IPv6 Address
Space Registry, the corpus holds the block's first and last address, the
addresses one step outside it on each side, and one in the middle, plus every
IPv4-mapped and NAT64 well-known form of the IPv4 probes.
Each probe carries the expected answer from the registry (its most specific
block and whether that block is globally reachable) and Python's own
classification for cross-checking. test/iana-corpus-test.ts asserts the
library agrees.
"""
import csv
import ipaddress
import json
import re
import sys
import urllib.request
from pathlib import Path
DATA = Path(__file__).resolve().parent.parent / "test" / "data"
REGISTRIES = {
4: "https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry-1.csv",
6: "https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry-1.csv",
}
def csv_path(version):
return DATA / f"iana-ipv{version}-special-registry.csv"
def fetch():
for version, url in REGISTRIES.items():
with urllib.request.urlopen(url) as response:
csv_path(version).write_bytes(response.read())
def reachability(value):
"""Map the registry's 'Globally Reachable' column to True, False, or None.
N/A (Teredo, 6to4) is not reachable without a relay; a blank cell inherits
the containing block's answer.
"""
value = value.strip()
if value.startswith("True"):
return True
if value.startswith("False") or value.startswith("N/A"):
return False
return None
def load_blocks(version):
blocks = []
with csv_path(version).open() as f:
for row in csv.DictReader(f):
for cidr in re.findall(r"[0-9a-fA-F:.]+/\d+", row["Address Block"]):
blocks.append((ipaddress.ip_network(cidr), row["Name"], reachability(row["Globally Reachable"])))
return blocks
def registry_answer(address, blocks):
"""The most specific block containing the address, and whether the registry
marks the address globally reachable (True when no block contains it)."""
containing = sorted((b for b in blocks if address in b[0]), key=lambda b: b[0].prefixlen, reverse=True)
name = containing[0][1] if containing else None
for _, _, reachable in containing:
if reachable is not None:
return name, reachable
return name, True
def probes(net):
first, last = int(net.network_address), int(net.broadcast_address)
maxv = (1 << net.max_prefixlen) - 1
candidates = {first, last, first - 1, last + 1, first + 1, last - 1, first + (last - first) // 2}
make = net.network_address.__class__
return [make(c) for c in sorted(candidates) if 0 <= c <= maxv]
def python_view(address):
return {
"loopback": address.is_loopback,
"linkLocal": address.is_link_local,
"multicast": address.is_multicast,
"unspecified": address.is_unspecified,
"global": address.is_global,
}
EMBEDDING = (ipaddress.ip_network("::ffff:0:0/96"), ipaddress.ip_network("64:ff9b::/96"))
ADDRESS_SPACE_CSV = DATA / "iana-ipv6-address-space.csv"
def load_address_space():
"""The IANA IPv6 Address Space Registry: which top-level blocks are
allocated for global unicast at all (only 2000::/3 is)."""
blocks = []
with ADDRESS_SPACE_CSV.open() as f:
for row in csv.DictReader(f):
blocks.append((ipaddress.ip_network(row["IPv6 Prefix"]), row["Allocation"]))
return blocks
def allocation(address, space):
return next(alloc for net, alloc in space if address in net)
def entry(address, blocks, family, space):
name, reachable = registry_answer(address, blocks[family])
result = {
"address": str(address),
"family": family,
"block": name,
"global": reachable and not address.is_multicast,
"python": python_view(address),
}
# Only the Global Unicast allocation can hold a globally reachable IPv6
# address; the reserved, ULA, link-local and multicast allocations cannot.
if family == 6:
result["allocation"] = allocation(address, space)
result["global"] = result["global"] and result["allocation"] == "Global Unicast"
# An IPv4-mapped or NAT64 well-known address answers for the IPv4 address
# it embeds, so a probe of those blocks takes the embedded address's answer.
if family == 6 and any(address in net for net in EMBEDDING):
embedded = ipaddress.IPv4Address(int(address) & 0xFFFFFFFF)
_, reachable = registry_answer(embedded, blocks[4])
result["embedded"] = str(embedded)
result["global"] = reachable and not embedded.is_multicast
return result
def main():
if "--fetch" in sys.argv:
fetch()
blocks = {4: load_blocks(4), 6: load_blocks(6)}
space = load_address_space()
corpus = []
for version in (4, 6):
for net, _, _ in blocks[version]:
for address in probes(net):
corpus.append(entry(address, blocks, version, space))
# The address-space allocations' own boundaries (fec0::/10, 4000::/3, ...)
for net, _ in space:
for address in probes(net):
corpus.append(entry(address, blocks, 6, space))
# IPv4-mapped and NAT64 well-known forms answer for the embedded IPv4
# address, so their expectation is the IPv4 probe's, not the IPv6 block's.
for v4 in [c for c in corpus if c["family"] == 4]:
n = int(ipaddress.IPv4Address(v4["address"]))
for kind, prefix in (("IPv4-mapped", 0xFFFF << 32), ("NAT64 well-known", 0x0064FF9B << 96)):
address = ipaddress.IPv6Address(prefix | n)
corpus.append({
"address": str(address),
"family": 6,
"block": f"{kind} form of {v4['address']} ({v4['block']})",
"embedded": v4["address"],
"global": v4["global"],
"python": python_view(address),
})
out = DATA / "iana-corpus.json"
out.write_text(json.dumps(corpus, indent=1) + "\n")
print(f"{len(corpus)} probes from {len(blocks[4])} IPv4 and {len(blocks[6])} IPv6 blocks -> {out}")
if __name__ == "__main__":
main()
beaugunderson-ip-address-438375e/scripts/readme-template.md 0000664 0000000 0000000 00000020373 15272410673 0023763 0 ustar 00root root 0000000 0000000 [](https://github.com/beaugunderson/ip-address/actions/workflows/ci.yml)
[![codecov]](https://codecov.io/github/beaugunderson/ip-address?branch=main)
[![downloads]](https://www.npmjs.com/package/ip-address)
[![npm]](https://www.npmjs.com/package/ip-address)
[codecov]: https://codecov.io/github/beaugunderson/ip-address/coverage.svg?branch=main
[downloads]: https://img.shields.io/npm/dm/ip-address.svg
[npm]: https://img.shields.io/npm/v/ip-address.svg
## ip-address
`ip-address` is a library for validating and manipulating IPv4 and IPv6 addresses in JavaScript and TypeScript.
### Install
```sh
npm install ip-address
```
### Examples
```ts
import { Address4, Address6 } from 'ip-address';
// Validation
Address4.isValid('192.168.1.1'); // true
Address6.isValid('2001:db8::1'); // true
Address6.isValid('not an address'); // false
// Parsing (throws AddressError on invalid input)
const v4 = new Address4('192.168.1.1/24');
const v6 = new Address6('2001:db8::1/64');
// Subnet membership
const host = new Address4('192.168.1.42');
const network = new Address4('192.168.1.0/24');
host.isInSubnet(network); // true
// Subnet range
network.startAddress().correctForm(); // '192.168.1.0'
network.endAddress().correctForm(); // '192.168.1.255'
// Strict network-address check (host bits must be zero).
// isValid() accepts CIDRs with host bits set — '192.168.1.5/24' is a valid
// host-with-subnet, but it isn't a network address.
const cidr = new Address4('192.168.1.5/24');
Address4.isValid('192.168.1.5/24'); // true
cidr.correctForm() === cidr.startAddress().correctForm(); // false
// Address properties
const link = new Address6('fe80::1');
link.isLinkLocal(); // true
link.isMulticast(); // false
link.isLoopback(); // false
new Address4('192.168.1.1').isPrivate(); // true (RFC 1918)
new Address6('fc00::1').isULA(); // true (RFC 4193)
// Numeric and byte representations
v4.bigInt(); // 3232235777n
v4.toArray(); // [192, 168, 1, 1]
v6.canonicalForm(); // '2001:0db8:0000:0000:0000:0000:0000:0001'
// Embedded IPv4 + Teredo
const teredo = new Address6('2001:0:ce49:7601:e866:efff:62c3:fffe');
teredo.inspectTeredo().client4; // '157.60.0.1'
// Parse host + port from a URL
Address6.fromURL('http://[2001:db8::1]:8080/').port; // 8080
```
### Features
- Written in TypeScript with full type definitions; usable from CommonJS and ESM
- Zero runtime dependencies
- Parses dotted-quad IPv4 and [RFC 4291](https://datatracker.ietf.org/doc/html/rfc4291) IPv6 notation, including subnets and zones. The `inet_aton` forms (`2130706433`, `0x7f000001`, `127.1`) and leading-zero octets are rejected by design — see [SECURITY.md](./SECURITY.md#classifiers-are-not-an-ssrf-defense)
- Parses IPv6 hosts (and ports) from URLs via `Address6.fromURL(url)`
- Subnet membership checks (`isInSubnet`) and range queries (`startAddress` / `endAddress`)
- Special-property checks: private (RFC 1918) / ULA (RFC 4193), loopback, link-local, multicast, broadcast, unspecified, CGNAT, documentation, Teredo, 6to4, v4-in-v6
- Decodes [Teredo](http://en.wikipedia.org/wiki/Teredo_tunneling#IPv6_addressing) and 6to4 tunneling information
- Conversions: canonical/correct form, hex, binary, decimal, byte arrays, BigInt, `in-addr.arpa` / `ip6.arpa`
- Runs in Node.js and the browser
- Thousands of test cases
### Terminology
A few terms used throughout the API can be confusing if you haven't worked deeply with IPv6 before:
- **Correct form** — the shortest valid representation, per [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros stripped, the longest run of zero groups collapsed to `::`, and hex digits lowercased (e.g. `2001:db8::1`). This is what most software displays.
- **Canonical form** — the fully expanded representation: all 8 groups, each padded to 4 hex digits, no `::` collapsing (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and byte-exact comparison.
- **Subnet** — the network portion of an address expressed as a CIDR prefix length (e.g. `/24` for IPv4, `/64` for IPv6). `startAddress()` / `endAddress()` return the bounds of the subnet's range.
- **Zone** — the IPv6 scope identifier appended after `%`, used to disambiguate link-local addresses across interfaces (e.g. `fe80::1%eth0`).
- **v4-in-v6** — mixed notation that embeds an IPv4 address as the last 32 bits of an IPv6 address, e.g. `::ffff:192.168.0.1`. Used for IPv4-mapped IPv6 addresses.
- **Teredo** — a tunneling protocol that encodes an IPv4 endpoint, port, and flags inside a `2001::/32` IPv6 address. `inspectTeredo()` decodes those fields.
- **6to4** — a tunneling protocol that embeds a full 32-bit IPv4 address in bits 16–47 of a `2002::/16` IPv6 address, i.e. the second and third groups (`192.0.2.4` becomes `2002:c000:204::`). `inspect6to4()` decodes the embedded v4 address.
### API
### Security
Vulnerabilities go through [GitHub's private vulnerability reporting](https://github.com/beaugunderson/ip-address/security/advisories/new); [SECURITY.md](./SECURITY.md) has the scope and what to expect. Confirmed issues get a fix, a release, and a public [advisory](https://github.com/beaugunderson/ip-address/security/advisories) with a CVE, rather than a quiet patch.
Releases are built and published by CI through npm trusted publishing. Every version from 10.2.1 onward carries a provenance attestation tying the tarball to the commit and workflow that built it. Check it with `npm audit signatures`.
If you are using the address-property checks as a security control, read [that section of SECURITY.md](./SECURITY.md#classifiers-are-not-an-ssrf-defense) first. `isPrivate()`, `isLoopback()`, `isInSubnet()` and their siblings classify an address that has already been parsed, which makes them one layer of an SSRF guard rather than the whole of it. A hostname that resolves to an internal address, a DNS record that changes after your check, or a redirect will all sail past a guard built only on them. Within that layer, use `isGlobal()` rather than an OR of the named classifiers: it is false for every block the IANA special-purpose registries mark as not globally reachable, including the ones with no classifier of their own.
### Used by
`ip-address` is downloaded ~86 million times per week, mostly via the Node proxy/agent ecosystem. The dependency chain runs through a handful of widely-used packages:
- [**socks**](https://github.com/JoshGlazebrook/socks) (~53M weekly) — SOCKS4/5 client for Node; depends on `ip-address` directly. The single biggest source of downloads.
- [**socks-proxy-agent**](https://github.com/TooTallNate/proxy-agents/tree/main/packages/socks-proxy-agent) (~55M weekly) — `http.Agent` for SOCKS proxies; depends on `socks`. Bundled by virtually every CLI that respects `HTTPS_PROXY`.
- [**npm**](https://github.com/npm/cli) and [**pnpm**](https://github.com/pnpm/pnpm) — both bundle `socks-proxy-agent` through their HTTP fetch stack (`make-fetch-happen` → `@npmcli/agent`), so every Node install on the planet pulls in `ip-address` as a transitive dependency.
- [**Puppeteer**](https://github.com/puppeteer/puppeteer) — `@puppeteer/browsers` uses `proxy-agent` for browser-binary downloads, which routes through `socks-proxy-agent` → `socks` → `ip-address`.
- [**proxy-agent**](https://github.com/TooTallNate/proxy-agents/tree/main/packages/proxy-agent) (~28M weekly) and [**pac-proxy-agent**](https://github.com/TooTallNate/proxy-agents/tree/main/packages/pac-proxy-agent) (~27M weekly) — auto-detecting proxy agents (HTTP/HTTPS/SOCKS/PAC) used widely in scraping, headless-browser, and CI tooling.
- [**cacache**](https://github.com/npm/cacache) (~40M weekly) — npm's content-addressable cache; pulls in the same fetch stack.
Beyond the proxy chain, `ip-address` has been used by Juniper Networks' Contrail, Ably's proxy-protocol implementation, Rackspace's serialization framework, IPFS, and the [SwitchyOmega](https://github.com/FelisCatus/SwitchyOmega) Chrome extension, among many others.
beaugunderson-ip-address-438375e/src/ 0000775 0000000 0000000 00000000000 15272410673 0017466 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/src/address-error.ts 0000664 0000000 0000000 00000001372 15272410673 0022615 0 ustar 00root root 0000000 0000000 export class AddressError extends Error {
/**
* The offending address with the portion that failed to parse wrapped in
* ``, e.g. `2001:db8:::1`. Present only on errors thrown from a
* parse path that can point at a specific substring.
*
* This is an HTML fragment intended for an address-inspector UI. The
* address content is HTML-escaped, so it is safe to insert as-is; treat it
* as markup rather than as a plain-text message, and use `message` for
* anything that renders as text.
*/
parseMessage?: string;
constructor(message: string, parseMessage?: string) {
super(message);
this.name = 'AddressError';
this.parseMessage = parseMessage;
}
}
beaugunderson-ip-address-438375e/src/common.ts 0000664 0000000 0000000 00000014327 15272410673 0021335 0 ustar 00root root 0000000 0000000 import { Address4 } from './ipv4';
import { Address6 } from './ipv6';
import { AddressError } from './address-error';
export interface ReverseFormOptions {
omitSuffix?: boolean;
}
/**
* Returns whether this address's *network* is contained within `address`,
* i.e. whether every address this one can represent also falls inside
* `address`. A network wider than `address` is not contained in it, so
* `10.0.0.0/8` is not in `10.0.0.0/16`.
*
* To ask whether the address itself falls inside a range, ignoring any CIDR
* suffix it was written with, use {@link isHostInSubnet} instead. That is the
* question the special-use classifiers ask.
*/
export function isInSubnet(this: Address4 | Address6, address: Address4 | Address6) {
if (this.subnetMask < address.subnetMask) {
return false;
}
return isHostInSubnet.call(this, address);
}
/**
* Returns whether this address's host bits fall inside `address`, ignoring
* this address's own subnet mask.
*
* This is the primitive the special-use classifiers (`isLoopback`,
* `isPrivate`, `isLinkLocal`, `getType`, …) are built on: they answer a
* question about the address, so the answer must not change with the CIDR
* suffix the caller happened to write. Use this rather than
* {@link isInSubnet} when classifying a single address — notably when the
* address came from untrusted input and the result backs a trust-boundary
* decision such as an SSRF allow/deny filter.
*
* An address of one family is never inside a network of the other, so an
* `Address4` against an `Address6` (or the reverse) is `false`. To compare
* across families, convert first: `Address6.fromAddress4()`, `to4()`, or
* `toAddress4Nat64()`.
*/
export function isHostInSubnet(this: Address4 | Address6, address: Address4 | Address6) {
// mask() is a bit string of the family's width, and the leading bits of a
// 32-bit string can coincide with those of a 128-bit one (a00::1 and
// 10.0.0.0/8 both mask to 00001010), so the widths must agree before the
// strings are compared.
if (this.binaryZeroPad().length !== address.binaryZeroPad().length) {
return false;
}
return this.mask(address.subnetMask) === address.mask();
}
/**
* One parsed row of an IANA special-purpose address registry: the block, and
* whether the registry marks it globally reachable (`null` when the column is
* blank, in which case the containing block answers).
*/
export interface SpecialPurposeEntry {
subnet: A;
reachable: boolean | null;
}
/**
* Returns whether the registry marks this address globally reachable: the
* answer of the most specific entry containing it that has one, or `true`
* when no entry contains it.
*/
export function isGloballyReachable(
this: A,
entries: ReadonlyArray>,
): boolean {
let best: SpecialPurposeEntry | null = null;
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
if (
entry.reachable !== null &&
isHostInSubnet.call(this, entry.subnet) &&
(best === null || entry.subnet.subnetMask > best.subnet.subnetMask)
) {
best = entry;
}
}
return best === null ? true : (best.reachable as boolean);
}
/**
* Adds `n` to `value` and returns the result, throwing `AddressError` unless
* `n` is an integer and the result stays within `[0, 2**bits - 1]`.
*/
export function offsetBigInt(
value: bigint,
n: number | bigint,
bits: number,
family: string,
): bigint {
if (typeof n === 'number' && !Number.isSafeInteger(n)) {
throw new AddressError(`${family} offset must be an integer`);
}
if (typeof n !== 'number' && typeof n !== 'bigint') {
throw new AddressError(`${family} offset must be an integer`);
}
const result = value + BigInt(n);
if (result < BigInt(0) || result > (BigInt(1) << BigInt(bits)) - BigInt(1)) {
throw new AddressError(`${family} offset leaves the address space`);
}
return result;
}
export function isCorrect(defaultBits: number) {
return function isCorrectForm(this: Address4 | Address6) {
if (this.addressMinusSuffix !== this.correctForm()) {
return false;
}
if (this.subnetMask === defaultBits && !this.parsedSubnet) {
return true;
}
return this.parsedSubnet === String(this.subnetMask);
};
}
/**
* Returns the prefix length (number of leading 1 bits) of a contiguous
* subnet mask. Throws `AddressError` if the mask is non-contiguous (e.g.
* `255.0.255.0`).
*/
export function prefixLengthFromMask(value: bigint, totalBits: number): number {
const binary = value.toString(2).padStart(totalBits, '0');
if (binary.length > totalBits) {
throw new AddressError('Invalid subnet mask.');
}
const firstZero = binary.indexOf('0');
if (firstZero === -1) {
return totalBits;
}
if (binary.slice(firstZero).includes('1')) {
throw new AddressError('Invalid subnet mask.');
}
return firstZero;
}
/**
* Throws `AddressError` unless `bytes` holds exactly `byteCount` integers,
* each from `minimum` to 255. Pass a `minimum` of `-128` where signed bytes
* are accepted and folded to unsigned, and `0` where they are not.
*/
export function assertByteArray(
bytes: number[],
byteCount: number,
family: 'IPv4' | 'IPv6',
minimum: number,
): void {
if (bytes.length !== byteCount) {
throw new AddressError(`${family} addresses require exactly ${byteCount} bytes`);
}
for (let i = 0; i < bytes.length; i++) {
if (!Number.isInteger(bytes[i]) || bytes[i] < minimum || bytes[i] > 255) {
throw new AddressError(`All bytes must be integers between ${minimum} and 255`);
}
}
}
export function numberToPaddedHex(number: number) {
return number.toString(16).padStart(2, '0');
}
export function stringToPaddedHex(numberString: string) {
return numberToPaddedHex(parseInt(numberString, 10));
}
/**
* @param binaryValue Binary representation of a value (e.g. `10`)
* @param position Byte position, where 0 is the least significant bit
*/
export function testBit(binaryValue: string, position: number): boolean {
const { length } = binaryValue;
if (position >= length) {
return false;
}
const positionInString = length - position - 1;
return binaryValue.substring(positionInString, positionInString + 1) === '1';
}
beaugunderson-ip-address-438375e/src/ip-address.ts 0000664 0000000 0000000 00000000300 15272410673 0022062 0 ustar 00root root 0000000 0000000 export { Address4 } from './ipv4';
export { Address6 } from './ipv6';
export { AddressError } from './address-error';
import * as helpers from './v6/helpers';
export const v6 = { helpers };
beaugunderson-ip-address-438375e/src/ipv4.ts 0000664 0000000 0000000 00000053757 15272410673 0020741 0 ustar 00root root 0000000 0000000 /* eslint-disable no-param-reassign */
import * as common from './common';
import * as constants from './v4/constants';
import { AddressError } from './address-error';
const isCorrect4 = common.isCorrect(constants.BITS);
/**
* Represents an IPv4 address
* @param {string} address - An IPv4 address string
*/
export class Address4 {
address: string;
addressMinusSuffix: string = '';
groups: number = constants.GROUPS;
parsedAddress: string[] = [];
parsedSubnet: string = '';
subnet: string = '/32';
subnetMask: number = 32;
v4: boolean = true;
private _binaryZeroPad?: string;
constructor(address: string) {
this.address = address;
const subnet = constants.RE_SUBNET_STRING.exec(address);
if (subnet) {
this.parsedSubnet = subnet[0].replace('/', '');
this.subnetMask = parseInt(this.parsedSubnet, 10);
this.subnet = `/${this.subnetMask}`;
if (this.subnetMask < 0 || this.subnetMask > constants.BITS) {
throw new AddressError('Invalid subnet mask.');
}
address = address.replace(constants.RE_SUBNET_STRING, '');
}
// Four three-digit octets and three dots: the longest well-formed address
// is 15 characters. Longer input is rejected before parsing, as Address6
// does at its own limit.
const longest = constants.GROUPS * 4 - 1;
if (address.length > longest) {
throw new AddressError(`IPv4 addresses are at most ${longest} characters.`);
}
this.addressMinusSuffix = address;
this.parsedAddress = this.parse(address);
}
/**
* Returns true if the given string is a valid IPv4 address (with optional
* CIDR subnet), false otherwise. Host bits in the subnet portion are
* allowed (e.g. `192.168.1.5/24` is valid); for strict network-address
* validation compare `correctForm()` to `startAddress().correctForm()`,
* or use `networkForm()`.
*/
static isValid(address: string): boolean {
try {
// eslint-disable-next-line no-new
new Address4(address);
return true;
} catch {
return false;
}
}
/**
* Parses an IPv4 address string into its four octet groups and stores the
* result on `this.parsedAddress`. Called automatically by the constructor;
* you typically don't need to call it directly. Throws `AddressError` if
* the input is not a valid IPv4 address.
*/
parse(address: string) {
const groups = address.split('.');
// Checked before the general match so the error names the actual problem.
// Address6 rejects the same notation on its v4-in-v6 path.
if (groups.some((group) => /^0\d/.test(group))) {
throw new AddressError("IPv4 addresses can't have leading zeroes.");
}
if (!address.match(constants.RE_ADDRESS)) {
throw new AddressError('Invalid IPv4 address.');
}
return groups;
}
/**
* Returns the address in correct form: octets joined with `.` and any
* leading zeros stripped (e.g. `192.168.1.1`). For IPv4 this matches the
* canonical dotted-decimal representation.
*/
correctForm(): string {
return this.parsedAddress.map((part) => parseInt(part, 10)).join('.');
}
/**
* Returns true if the address is correct, false otherwise
* @returns {Boolean}
*/
isCorrect = isCorrect4;
/**
* Construct an `Address4` from an address and a dotted-decimal subnet
* mask given as separate strings (e.g. as returned by Node's
* `os.networkInterfaces()`). Throws `AddressError` if the mask is
* non-contiguous (e.g. `255.0.255.0`).
* @example
* var address = Address4.fromAddressAndMask('192.168.1.1', '255.255.255.0');
* address.subnetMask; // 24
*/
static fromAddressAndMask(address: string, mask: string): Address4 {
const bits = common.prefixLengthFromMask(new Address4(mask).bigInt(), constants.BITS);
return new Address4(`${address}/${bits}`);
}
/**
* Construct an `Address4` from an address and a Cisco-style wildcard mask
* given as separate strings (e.g. `0.0.0.255` for a `/24`). The wildcard
* mask is the bitwise inverse of the subnet mask. Throws `AddressError`
* if the mask is non-contiguous (e.g. `0.255.0.255`).
* @example
* var address = Address4.fromAddressAndWildcardMask('10.0.0.1', '0.0.0.255');
* address.subnetMask; // 24
*/
static fromAddressAndWildcardMask(address: string, wildcardMask: string): Address4 {
const wildcard = new Address4(wildcardMask).bigInt();
const allOnes = (BigInt(1) << BigInt(constants.BITS)) - BigInt(1);
const mask = wildcard ^ allOnes;
const bits = common.prefixLengthFromMask(mask, constants.BITS);
return new Address4(`${address}/${bits}`);
}
/**
* Construct an `Address4` from a wildcard pattern with trailing `*`
* octets. The number of trailing wildcards determines the prefix
* length: each `*` represents 8 bits.
*
* Only trailing whole-octet wildcards are supported. Partial-octet
* wildcards (e.g. `192.168.0.1*`) and interior wildcards (e.g.
* `192.*.0.1`) throw `AddressError`.
* @example
* Address4.fromWildcard('192.168.0.*').subnet; // '/24'
* Address4.fromWildcard('192.168.*.*').subnet; // '/16'
* Address4.fromWildcard('*.*.*.*').subnet; // '/0'
*/
static fromWildcard(input: string): Address4 {
const groups = input.split('.');
if (groups.length !== constants.GROUPS) {
throw new AddressError('Wildcard pattern must have 4 octets');
}
let firstWildcard = -1;
for (let i = 0; i < groups.length; i++) {
if (groups[i] === '*') {
if (firstWildcard === -1) {
firstWildcard = i;
}
} else if (firstWildcard !== -1) {
throw new AddressError(
'Wildcard `*` must only appear in trailing octets (e.g. `192.168.0.*`)',
);
}
}
const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
const replaced = groups.map((g) => (g === '*' ? '0' : g));
const subnetBits = constants.BITS - trailing * 8;
return new Address4(`${replaced.join('.')}/${subnetBits}`);
}
/**
* Converts a hex string to an IPv4 address object. Accepts 8 hex digits
* with optional `:` separators (e.g. `'7f000001'` or `'7f:00:00:01'`).
* Throws `AddressError` for any other length or for non-hex characters.
* @param {string} hex - a hex string to convert
* @returns {Address4}
*/
static fromHex(hex: string): Address4 {
const stripped = hex.replace(/:/g, '');
if (!/^[0-9a-fA-F]{8}$/.test(stripped)) {
throw new AddressError('IPv4 hex must be exactly 8 hex digits');
}
const groups = [];
for (let i = 0; i < 8; i += 2) {
groups.push(parseInt(stripped.slice(i, i + 2), 16));
}
return new Address4(groups.join('.'));
}
/**
* Converts an integer into a IPv4 address object. The integer must be a
* non-negative safe integer in the range `[0, 2**32 - 1]`; otherwise
* `AddressError` is thrown.
* @param {integer} integer - a number to convert
* @returns {Address4}
*/
static fromInteger(integer: number): Address4 {
if (!Number.isInteger(integer) || integer < 0 || integer > 0xffffffff) {
throw new AddressError('IPv4 integer must be in the range 0 to 2**32 - 1');
}
return Address4.fromHex(integer.toString(16).padStart(8, '0'));
}
/**
* Return an address from in-addr.arpa form: the four octets reversed, with
* or without the `.in-addr.arpa` suffix and root dot, in any case. Throws
* `AddressError` unless the reversed labels form a valid IPv4 address, so
* `fromArpa(x.reverseForm())` round-trips {@link reverseForm}.
* @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
* @returns {Adress4}
* @example
* var address = Address4.fromArpa('42.2.0.192.in-addr.arpa.')
* address.correctForm(); // '192.0.2.42'
*/
static fromArpa(arpaFormAddress: string): Address4 {
// A 15-character address, a "/32" prefix length and ".in-addr.arpa.": the
// longest name is 32 characters. Longer input is rejected before its
// labels are split, as the constructor does at its own limit.
const longest = constants.GROUPS * 4 - 1 + '/32'.length + '.in-addr.arpa.'.length;
if (arpaFormAddress.length > longest) {
throw new AddressError(`in-addr.arpa names are at most ${longest} characters.`);
}
// remove an ending ".in-addr.arpa", in any case and with or without the
// root dot, as Address6.fromArpa does for ".ip6.arpa"
const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.?$/i, '');
const address = leader.split('.').reverse().join('.');
return new Address4(address);
}
/**
* Converts an IPv4 address object to a hex string
* @returns {String}
*/
toHex(): string {
return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(':');
}
/**
* Converts an IPv4 address object to an array of bytes.
*
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`.
* @returns {Array}
*/
toArray(): number[] {
return this.parsedAddress.map((part) => parseInt(part, 10));
}
/**
* Converts an IPv4 address object to an IPv6 address group
* @returns {String}
*/
toGroup6(): string {
const output = [];
let i;
for (i = 0; i < constants.GROUPS; i += 2) {
output.push(
`${common.stringToPaddedHex(this.parsedAddress[i])}${common.stringToPaddedHex(
this.parsedAddress[i + 1],
)}`,
);
}
return output.join(':');
}
/**
* Returns the address as a `bigint`
* @returns {bigint}
*/
bigInt(): bigint {
return BigInt(`0x${this.parsedAddress.map((n) => common.stringToPaddedHex(n)).join('')}`);
}
/**
* Helper function getting start address.
* @returns {bigint}
*/
_startAddress(): bigint {
return BigInt(`0b${this.mask() + '0'.repeat(constants.BITS - this.subnetMask)}`);
}
/**
* The first address in the range given by this address' subnet.
* Often referred to as the Network Address.
* @returns {Address4}
*/
startAddress(): Address4 {
return Address4.fromBigInt(this._startAddress());
}
/**
* The first host address in the range given by this address's subnet ie
* the first address after the Network Address
* @returns {Address4}
*/
startAddressExclusive(): Address4 {
const adjust = BigInt('1');
return Address4.fromBigInt(this._startAddress() + adjust);
}
/**
* Returns the address `n` addresses after this one (or before, when `n` is
* negative), keeping this address's subnet mask. Throws `AddressError` when
* the result would fall outside the IPv4 address space or `n` is not an
* integer.
* @param {number | bigint} n
* @returns {Address4}
* @example
* new Address4('10.0.0.0/24').offset(1).correctForm(); // '10.0.0.1'
*/
offset(n: number | bigint): Address4 {
return Address4.fromBigInt(
common.offsetBigInt(this.bigInt(), n, constants.BITS, 'IPv4'),
).withSubnetMask(this.subnetMask);
}
/**
* Returns the network that follows this address's network: the address after
* {@link endAddress}, with the same subnet mask. Throws `AddressError` when
* this network is the last one in the address space.
* @returns {Address4}
* @example
* new Address4('10.0.0.0/24').nextNetwork().networkForm(); // '10.0.1.0/24'
*/
nextNetwork(): Address4 {
return Address4.fromBigInt(
common.offsetBigInt(this._endAddress(), 1, constants.BITS, 'IPv4'),
).withSubnetMask(this.subnetMask);
}
private withSubnetMask(subnetMask: number): Address4 {
return new Address4(`${this.correctForm()}/${subnetMask}`);
}
/**
* Helper function getting end address.
* @returns {bigint}
*/
_endAddress(): bigint {
return BigInt(`0b${this.mask() + '1'.repeat(constants.BITS - this.subnetMask)}`);
}
/**
* The last address in the range given by this address' subnet
* Often referred to as the Broadcast
* @returns {Address4}
*/
endAddress(): Address4 {
return Address4.fromBigInt(this._endAddress());
}
/**
* The last host address in the range given by this address's subnet ie
* the last address prior to the Broadcast Address
* @returns {Address4}
*/
endAddressExclusive(): Address4 {
const adjust = BigInt('1');
return Address4.fromBigInt(this._endAddress() - adjust);
}
/**
* The dotted-decimal form of the subnet mask, e.g. `255.255.240.0` for
* a `/20`. Returns an `Address4`; call `.correctForm()` for the string.
* @returns {Address4}
*/
subnetMaskAddress(): Address4 {
return Address4.fromBigInt(
BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants.BITS - this.subnetMask)}`),
);
}
/**
* The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is
* the bitwise inverse of `subnetMaskAddress()`. Returns an `Address4`;
* call `.correctForm()` for the string.
* @returns {Address4}
*/
wildcardMask(): Address4 {
return Address4.fromBigInt(
BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants.BITS - this.subnetMask)}`),
);
}
/**
* The network address in CIDR string form, e.g. `192.168.1.0/24` for
* `192.168.1.5/24`. For an address with no explicit subnet the prefix is
* `/32`, e.g. `networkForm()` on `192.168.1.5` returns `192.168.1.5/32`.
* @returns {string}
*/
networkForm(): string {
return `${this.startAddress().correctForm()}/${this.subnetMask}`;
}
/**
* Converts a BigInt to a v4 address object. The value must be in the
* range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown.
* @param {bigint} bigInt - a BigInt to convert
* @returns {Address4}
*/
static fromBigInt(bigInt: bigint): Address4 {
if (bigInt < BigInt(0) || bigInt > BigInt(0xffffffff)) {
throw new AddressError('IPv4 BigInt must be in the range 0 to 2**32 - 1');
}
return Address4.fromHex(bigInt.toString(16).padStart(8, '0'));
}
/**
* Convert a byte array to an Address4 object. Throws `AddressError` unless
* given exactly 4 integers from 0 to 255. Signed bytes are rejected, so
* this differs from `Address6.fromByteArray`, which folds them; the two
* contracts converge on this stricter form in the next major version.
*
* To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`.
* @param {Array} bytes - an array of 4 bytes (0-255)
* @returns {Address4}
*/
static fromByteArray(bytes: Array): Address4 {
common.assertByteArray(bytes, 4, 'IPv4', 0);
return this.fromUnsignedByteArray(bytes);
}
/**
* Convert an unsigned byte array to an Address4 object. Throws
* `AddressError` unless given exactly 4 bytes, and rejects values outside
* 0 to 255 when parsing the resulting address.
*
* To convert from a Node.js `Buffer`, spread it:
* `Address4.fromUnsignedByteArray([...buf])`.
* @param {Array} bytes - an array of 4 unsigned bytes (0-255)
* @returns {Address4}
*/
static fromUnsignedByteArray(bytes: Array): Address4 {
if (bytes.length !== 4) {
throw new AddressError('IPv4 addresses require exactly 4 bytes');
}
const address = bytes.join('.');
return new Address4(address);
}
/**
* Returns the first n bits of the address, defaulting to the
* subnet mask
* @returns {String}
*/
mask(mask?: number): string {
if (mask === undefined) {
mask = this.subnetMask;
}
return this.getBitsBase2(0, mask);
}
/**
* Returns the bits in the given range as a base-2 string
* @returns {string}
*/
getBitsBase2(start: number, end: number): string {
return this.binaryZeroPad().slice(start, end);
}
/**
* Return the reversed in-addr.arpa form of the address, e.g.
* `42.2.0.192.in-addr.arpa.` for `192.0.2.42`.
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
* @returns {String}
*/
reverseForm(options?: common.ReverseFormOptions): string {
if (!options) {
options = {};
}
const reversed = this.correctForm().split('.').reverse().join('.');
if (options.omitSuffix) {
return reversed;
}
return `${reversed}.in-addr.arpa.`;
}
/**
* Returns true if the given address is in the subnet of the current address.
* An `Address6` is never in the subnet of an `Address4`; convert with
* `to4()` or `Address6.fromAddress4()` to compare across families.
* @returns {boolean}
*/
isInSubnet = common.isInSubnet;
/**
* Returns true if this address's host bits fall inside the given subnet,
* ignoring this address's own subnet mask. Prefer this over `isInSubnet`
* when classifying a single address, so the answer doesn't change with the
* CIDR suffix the caller happened to write — notably when the address came
* from untrusted input and the result backs a trust-boundary decision.
* An `Address6` is never in the subnet of an `Address4`; convert with
* `to4()` or `Address6.fromAddress4()` to compare across families.
* @returns {boolean}
*/
isHostInSubnet = common.isHostInSubnet;
/**
* Returns true if the given address is a multicast address
* @returns {boolean}
*/
isMulticast(): boolean {
return this.isHostInSubnet(MULTICAST_V4);
}
/**
* Returns true if the address is in one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private address ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`).
* @returns {boolean}
*/
isPrivate(): boolean {
return PRIVATE_V4.some((subnet) => this.isHostInSubnet(subnet));
}
/**
* Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)).
* @returns {boolean}
*/
isLoopback(): boolean {
return this.isHostInSubnet(LOOPBACK_V4);
}
/**
* Returns true if the address is in the link-local range `169.254.0.0/16` ([RFC 3927](https://datatracker.ietf.org/doc/html/rfc3927)).
* @returns {boolean}
*/
isLinkLocal(): boolean {
return this.isHostInSubnet(LINK_LOCAL_V4);
}
/**
* Returns true if the address is the unspecified address `0.0.0.0`.
* @returns {boolean}
*/
isUnspecified(): boolean {
return this.isHostInSubnet(UNSPECIFIED_V4);
}
/**
* Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)).
* @returns {boolean}
*/
isBroadcast(): boolean {
return this.isHostInSubnet(BROADCAST_V4);
}
/**
* Returns true if the address is in the carrier-grade NAT range `100.64.0.0/10` ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)).
* @returns {boolean}
*/
isCGNAT(): boolean {
return this.isHostInSubnet(CGNAT_V4);
}
/**
* Returns true if the address is in one of the documentation ranges
* `192.0.2.0/24`, `198.51.100.0/24`, or `203.0.113.0/24` ([RFC 5737](https://datatracker.ietf.org/doc/html/rfc5737)).
* @returns {boolean}
*/
isDocumentation(): boolean {
return DOCUMENTATION_V4.some((subnet) => this.isHostInSubnet(subnet));
}
/**
* Returns true if the address is in the benchmarking range `198.18.0.0/15` ([RFC 2544](https://datatracker.ietf.org/doc/html/rfc2544)).
* @returns {boolean}
*/
isBenchmarking(): boolean {
return this.isHostInSubnet(BENCHMARKING_V4);
}
/**
* Returns true if the address is in the reserved range `240.0.0.0/4` ([RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112)),
* which includes the limited broadcast address.
* @returns {boolean}
*/
isReserved(): boolean {
return this.isHostInSubnet(RESERVED_V4);
}
/**
* Returns true if the address is globally reachable: not multicast, and not
* in any block the [IANA IPv4 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/)
* marks as not globally reachable. That covers everything the individual
* classifiers name (private, loopback, link-local, CGNAT, unspecified,
* broadcast, documentation, benchmarking, reserved) and the blocks they do
* not, such as `0.0.0.0/8` and the IETF protocol assignments in
* `192.0.0.0/24`. This is the single predicate to use where a request must
* not reach an internal or special-purpose destination; see SECURITY.md.
* @returns {boolean}
*/
isGlobal(): boolean {
return !this.isMulticast() && common.isGloballyReachable.call(this, SPECIAL_PURPOSE_V4);
}
/**
* Returns a zero-padded base-2 string representation of the address
* @returns {string}
*/
binaryZeroPad(): string {
if (this._binaryZeroPad === undefined) {
this._binaryZeroPad = this.bigInt().toString(2).padStart(constants.BITS, '0');
}
return this._binaryZeroPad;
}
/**
* Groups an IPv4 address for inclusion at the end of an IPv6 address.
*
* Returns an HTML fragment: each half of the address is wrapped in a
* `` carrying the group classes an address-inspector UI hovers on.
* The address content is HTML-escaped; anything you concatenate around it
* is your responsibility.
* @returns {String}
*/
groupForV6(): string {
const segments = this.parsedAddress;
return this.correctForm().replace(
constants.RE_ADDRESS,
`${segments
.slice(0, 2)
.join('.')}.${segments
.slice(2, 4)
.join('.')}`,
);
}
}
const MULTICAST_V4 = new Address4('224.0.0.0/4');
const PRIVATE_V4 = [
new Address4('10.0.0.0/8'),
new Address4('172.16.0.0/12'),
new Address4('192.168.0.0/16'),
];
const LOOPBACK_V4 = new Address4('127.0.0.0/8');
const LINK_LOCAL_V4 = new Address4('169.254.0.0/16');
const UNSPECIFIED_V4 = new Address4('0.0.0.0/32');
const BROADCAST_V4 = new Address4('255.255.255.255/32');
const CGNAT_V4 = new Address4('100.64.0.0/10');
const DOCUMENTATION_V4 = [
new Address4('192.0.2.0/24'),
new Address4('198.51.100.0/24'),
new Address4('203.0.113.0/24'),
];
const BENCHMARKING_V4 = new Address4('198.18.0.0/15');
const RESERVED_V4 = new Address4('240.0.0.0/4');
const SPECIAL_PURPOSE_V4 = constants.SPECIAL_PURPOSE.map(([cidr, , reachable]) => ({
subnet: new Address4(cidr),
reachable,
}));
beaugunderson-ip-address-438375e/src/ipv6.ts 0000664 0000000 0000000 00000155221 15272410673 0020730 0 ustar 00root root 0000000 0000000 /* eslint-disable prefer-destructuring */
/* eslint-disable no-param-reassign */
import * as common from './common';
import * as constants4 from './v4/constants';
import * as constants6 from './v6/constants';
import * as helpers from './v6/helpers';
import { Address4 } from './ipv4';
import {
ADDRESS_BOUNDARY,
possibleElisions,
simpleRegularExpression,
} from './v6/regular-expressions';
import { AddressError } from './address-error';
import { testBit } from './common';
const isCorrect6 = common.isCorrect(constants6.BITS);
function assert(condition: any): asserts condition {
if (!condition) {
throw new Error('Assertion failed.');
}
}
function addCommas(number: string): string {
const r = /(\d+)(\d{3})/;
while (r.test(number)) {
number = number.replace(r, '$1,$2');
}
return number;
}
function spanLeadingZeroes4(n: string): string {
n = n.replace(/^(0{1,})([1-9]+)$/, '$1$2');
n = n.replace(/^(0{1,})(0)$/, '$1$2');
return n;
}
/*
* A helper function to compact an array
*/
function compact(address: string[], slice: number[]) {
const s1 = [];
const s2 = [];
let i;
for (i = 0; i < address.length; i++) {
if (i < slice[0]) {
s1.push(address[i]);
} else if (i > slice[1]) {
s2.push(address[i]);
}
}
return s1.concat(['compact']).concat(s2);
}
function paddedHex(octet: string): string {
return parseInt(octet, 16).toString(16).padStart(4, '0');
}
function unsignByte(b: number) {
return b & 0xff;
}
interface SixToFourProperties {
prefix: string;
gateway: string;
}
interface TeredoProperties {
prefix: string;
server4: string;
client4: string;
flags: string;
coneNat: boolean;
microsoft: {
reserved: boolean;
universalLocal: boolean;
groupIndividual: boolean;
nonce: string;
};
udpPort: string;
}
/**
* Represents an IPv6 address
* @param {string} address - An IPv6 address string
* @param {number} [groups=8] - How many octets to parse
* @example
* var address = new Address6('2001::/32');
*/
export class Address6 {
address4?: Address4;
address: string;
addressMinusSuffix: string = '';
elidedGroups?: number;
elisionBegin?: number;
elisionEnd?: number;
groups: number;
parsedAddress4?: string;
parsedAddress: string[];
parsedSubnet: string = '';
subnet: string = '/128';
subnetMask: number = 128;
v4: boolean = false;
zone: string = '';
private _binaryZeroPad?: string;
constructor(address: string, optionalGroups?: number) {
if (optionalGroups === undefined) {
this.groups = constants6.GROUPS;
} else {
this.groups = optionalGroups;
}
this.address = address;
const subnet = constants6.RE_SUBNET_STRING.exec(address);
if (subnet) {
this.parsedSubnet = subnet[0].replace('/', '');
this.subnetMask = parseInt(this.parsedSubnet, 10);
this.subnet = `/${this.subnetMask}`;
if (
Number.isNaN(this.subnetMask) ||
this.subnetMask < 0 ||
this.subnetMask > constants6.BITS
) {
throw new AddressError('Invalid subnet mask.');
}
address = address.replace(constants6.RE_SUBNET_STRING, '');
}
// RE_SUBNET_STRING anchors on the end of the address, so it strips only
// the trailing suffix. A second one left behind (`::/0/1`) is malformed
// and must be rejected rather than parsed as an address group.
if (/\//.test(address)) {
throw new AddressError('Invalid subnet mask.');
}
// A zone runs from the first `%` to the end of the input and holds no line
// terminator. Finding it by index reads the input once, where matching
// RE_ZONE_STRING retries from every `%` that a line terminator disqualifies.
const zoneStart = address.indexOf('%');
if (zoneStart !== -1 && /^.*$/.test(address.slice(zoneStart))) {
this.zone = address.slice(zoneStart);
address = address.slice(0, zoneStart);
}
// The longest well-formed address is all but the last two groups written
// as four hex digits with their colons, then a 15-character dotted quad:
// 5 * (groups - 2) + 15, which is 45 for eight groups, the same line
// CPython's ipaddress module draws. Rejecting longer input here keeps the
// parse diagnostics, which wrap every offending character in a span,
// proportional to an address rather than to whatever was passed in.
const longest = this.groups * 5 + 5;
if (address.length > longest) {
throw new AddressError(`IPv6 addresses are at most ${longest} characters.`);
}
this.addressMinusSuffix = address;
this.parsedAddress = this.parse(this.addressMinusSuffix);
}
/**
* Returns true if the given string is a valid IPv6 address (with optional
* CIDR subnet and zone identifier), false otherwise. Host bits in the
* subnet portion are allowed (e.g. `2001:db8::1/32` is valid); for strict
* network-address validation compare `correctForm()` to
* `startAddress().correctForm()`, or use `networkForm()`.
*/
static isValid(address: string): boolean {
try {
// eslint-disable-next-line no-new
new Address6(address);
return true;
} catch {
return false;
}
}
/**
* Convert a BigInt to a v6 address object. The value must be in the
* range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown.
* @param {bigint} bigInt - a BigInt to convert
* @returns {Address6}
* @example
* var bigInt = BigInt('1000000000000');
* var address = Address6.fromBigInt(bigInt);
* address.correctForm(); // '::e8:d4a5:1000'
*/
static fromBigInt(bigInt: bigint): Address6 {
if (bigInt < BigInt(0) || bigInt > (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1)) {
throw new AddressError('IPv6 BigInt must be in the range 0 to 2**128 - 1');
}
const hex = bigInt.toString(16).padStart(32, '0');
const groups = [];
for (let i = 0; i < constants6.GROUPS; i++) {
groups.push(hex.slice(i * 4, (i + 1) * 4));
}
return new Address6(groups.join(':'));
}
/**
* Parse a URL (with optional bracketed host and port) into an address and
* port. Returns either `{ address, port }` on success or
* `{ error, address: null, port: null }` if the URL could not be parsed.
* Ports are returned as numbers (or `null` if absent or out of range).
* @example
* var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/');
* addressAndPort.address.correctForm(); // 'ffff::'
* addressAndPort.port; // 8080
*/
static fromURL(url: string) {
let host: string;
let port: string | number | null = null;
let result: RegExpExecArray | null;
let error: string;
// Remove the protocol prefix, if any
const stripped = url.replace(/^[a-z][a-z0-9+.-]*:\/\//i, '');
// If we have brackets parse them and find a port
if (stripped.indexOf('[') !== -1 && stripped.indexOf(']:') !== -1) {
error = 'failed to parse address with port';
result = constants6.RE_URL_WITH_PORT.exec(stripped);
if (result === null) {
return { error, address: null, port: null };
}
host = result[1];
port = result[2];
} else {
error = 'failed to parse address from URL';
result = constants6.RE_URL.exec(stripped);
if (result === null) {
return { error, address: null, port: null };
}
host = result[1] ?? result[2];
}
// If there's a port convert it to an integer
if (port) {
port = parseInt(port, 10);
// squelch out of range ports (valid ports are 0-65535)
if (port < 0 || port > 65535) {
port = null;
}
} else {
// Standardize `undefined` to `null`
port = null;
}
// The URL character class is a superset of valid IPv6, so a host the
// regex accepted (an IPv4 literal, bare punctuation, too many groups)
// can still be rejected by the parser
let address: Address6;
try {
address = new Address6(host);
} catch {
return { error, address: null, port: null };
}
return { address, port };
}
/**
* Construct an `Address6` from an address and a hex subnet mask given as
* separate strings (e.g. as returned by Node's `os.networkInterfaces()`).
* Throws `AddressError` if the mask is non-contiguous (e.g.
* `ffff::ffff`).
* @example
* var address = Address6.fromAddressAndMask('fe80::1', 'ffff:ffff:ffff:ffff::');
* address.subnetMask; // 64
*/
static fromAddressAndMask(address: string, mask: string): Address6 {
const bits = common.prefixLengthFromMask(new Address6(mask).bigInt(), constants6.BITS);
return new Address6(`${address}/${bits}`);
}
/**
* Construct an `Address6` from an address and a Cisco-style wildcard mask
* given as separate strings (e.g. `::ffff:ffff:ffff:ffff` for a `/64`).
* The wildcard mask is the bitwise inverse of the subnet mask. Throws
* `AddressError` if the mask is non-contiguous.
* @example
* var address = Address6.fromAddressAndWildcardMask('fe80::1', '::ffff:ffff:ffff:ffff');
* address.subnetMask; // 64
*/
static fromAddressAndWildcardMask(address: string, wildcardMask: string): Address6 {
const wildcard = new Address6(wildcardMask).bigInt();
const allOnes = (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1);
const mask = wildcard ^ allOnes;
const bits = common.prefixLengthFromMask(mask, constants6.BITS);
return new Address6(`${address}/${bits}`);
}
/**
* Construct an `Address6` from a wildcard pattern with trailing `*`
* groups. The number of trailing wildcards determines the prefix
* length: each `*` represents 16 bits. `::` is expanded to zero groups
* (not wildcards) before evaluating trailing wildcards.
*
* Only trailing whole-group wildcards are supported. Partial-group
* wildcards (e.g. `2001:db8::0*`) and interior wildcards (e.g.
* `*::1`) throw `AddressError`.
* @example
* Address6.fromWildcard('2001:db8:*:*:*:*:*:*').subnet; // '/32'
* Address6.fromWildcard('2001:db8::*').subnet; // '/112'
* Address6.fromWildcard('*:*:*:*:*:*:*:*').subnet; // '/0'
*/
static fromWildcard(input: string): Address6 {
if (input.includes('%') || input.includes('/')) {
throw new AddressError('Wildcard pattern must not include a zone or CIDR suffix');
}
const halves = input.split('::');
if (halves.length > 2) {
throw new AddressError("Wildcard pattern cannot contain more than one '::'");
}
let groups: string[];
if (halves.length === 2) {
const left = halves[0] === '' ? [] : halves[0].split(':');
const right = halves[1] === '' ? [] : halves[1].split(':');
const remaining = constants6.GROUPS - left.length - right.length;
if (remaining < 1) {
throw new AddressError("Wildcard pattern with '::' has too many groups");
}
groups = [...left, ...new Array(remaining).fill('0'), ...right];
} else {
groups = input.split(':');
}
if (groups.length !== constants6.GROUPS) {
throw new AddressError('Wildcard pattern must have 8 groups');
}
let firstWildcard = -1;
for (let i = 0; i < groups.length; i++) {
if (groups[i] === '*') {
if (firstWildcard === -1) {
firstWildcard = i;
}
} else if (firstWildcard !== -1) {
throw new AddressError(
'Wildcard `*` must only appear in trailing groups (e.g. `2001:db8:*:*:*:*:*:*`)',
);
}
}
const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
const replaced = groups.map((g) => (g === '*' ? '0' : g));
const subnetBits = constants6.BITS - trailing * 16;
return new Address6(`${replaced.join(':')}/${subnetBits}`);
}
/**
* Create an IPv6-mapped address given an IPv4 address
* @param {string} address - An IPv4 address string
* @returns {Address6}
* @example
* var address = Address6.fromAddress4('192.168.0.1');
* address.correctForm(); // '::ffff:c0a8:1'
* address.to4in6(); // '::ffff:192.168.0.1'
*/
static fromAddress4(address: string): Address6 {
const address4 = new Address4(address);
const mask6 = constants6.BITS - (constants4.BITS - address4.subnetMask);
return new Address6(`::ffff:${address4.correctForm()}/${mask6}`);
}
/**
* Return an address from ip6.arpa form. A full 32-nibble name gives a /128
* address; a shorter name, as used for a delegated reverse zone, gives the
* network it covers, with a subnet mask of four bits per nibble, so
* `fromArpa(x.reverseForm())` round-trips {@link reverseForm} for any prefix.
* @param {string} arpaFormAddress - an 'ip6.arpa' form address
* @returns {Adress6}
* @example
* var address = Address6.fromArpa(e.f.f.f.3.c.2.6.f.f.f.e.6.6.8.e.1.0.6.7.9.4.e.c.0.0.0.0.1.0.0.2.ip6.arpa.)
* address.correctForm(); // '2001:0:ce49:7601:e866:efff:62c3:fffe'
* Address6.fromArpa('8.b.d.0.1.0.0.2.ip6.arpa.').networkForm(); // '2001:db8::/32'
*/
static fromArpa(arpaFormAddress: string): Address6 {
// remove an ending ".ip6.arpa", in any case and with or without the root
// dot
const nibbles = arpaFormAddress.replace(/(\.ip6\.arpa)?\.?$/i, '');
if (!/^[0-9a-f](\.[0-9a-f]){0,31}$/i.test(nibbles)) {
throw new AddressError("Invalid 'ip6.arpa' form.");
}
const reversed = nibbles.split('.').reverse();
const subnetMask = reversed.length * 4;
const hex = reversed.join('').padEnd(32, '0');
const groups = [];
for (let i = 0; i < constants6.GROUPS; i++) {
groups.push(hex.slice(i * 4, (i + 1) * 4));
}
return new Address6(`${groups.join(':')}/${subnetMask}`);
}
/**
* Return the Microsoft UNC transcription of the address
* @returns {String} the Microsoft UNC transcription of the address
*/
microsoftTranscription(): string {
return `${this.correctForm().replace(/:/g, '-')}.ipv6-literal.net`;
}
/**
* Return the first n bits of the address, defaulting to the subnet mask
* @param {number} [mask=subnet] - the number of bits to mask
* @returns {String} the first n bits of the address as a string
*/
mask(mask: number = this.subnetMask): string {
return this.getBitsBase2(0, mask);
}
/**
* Return the number of possible subnets of a given size in the address
* @param {number} [subnetSize=128] - the subnet size
* @returns {String}
*/
// TODO: probably useful to have a numeric version of this too
possibleSubnets(subnetSize: number = 128): string {
const availableBits = constants6.BITS - this.subnetMask;
const subnetBits = Math.abs(subnetSize - constants6.BITS);
const subnetPowers = availableBits - subnetBits;
if (subnetPowers < 0) {
return '0';
}
return addCommas((BigInt('2') ** BigInt(subnetPowers)).toString(10));
}
/**
* Helper function getting start address.
* @returns {bigint}
*/
_startAddress(): bigint {
return BigInt(`0b${this.mask() + '0'.repeat(constants6.BITS - this.subnetMask)}`);
}
/**
* The first address in the range given by this address' subnet
* Often referred to as the Network Address.
* @returns {Address6}
*/
startAddress(): Address6 {
return Address6.fromBigInt(this._startAddress());
}
/**
* The first host address in the range given by this address's subnet ie
* the first address after the Network Address
* @returns {Address6}
*/
startAddressExclusive(): Address6 {
const adjust = BigInt('1');
return Address6.fromBigInt(this._startAddress() + adjust);
}
/**
* Helper function getting end address.
* @returns {bigint}
*/
_endAddress(): bigint {
return BigInt(`0b${this.mask() + '1'.repeat(constants6.BITS - this.subnetMask)}`);
}
/**
* The last address in the range given by this address's subnet. IPv6 has
* no broadcast address, so this is an ordinary assignable address (in a
* 64-bit-interface-identifier subnet it falls inside the reserved
* subnet-anycast block of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526)).
* @returns {Address6}
*/
endAddress(): Address6 {
return Address6.fromBigInt(this._endAddress());
}
/**
* The address one before {@link endAddress}. This is the IPv6 counterpart
* of the IPv4 method that skips the broadcast address; IPv6 has no broadcast,
* so it drops exactly one address and does not model the 128 reserved
* subnet-anycast identifiers of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526).
* @returns {Address6}
*/
endAddressExclusive(): Address6 {
const adjust = BigInt('1');
return Address6.fromBigInt(this._endAddress() - adjust);
}
/**
* Returns the address `n` addresses after this one (or before, when `n` is
* negative), keeping this address's subnet mask. Throws `AddressError` when
* the result would fall outside the IPv6 address space or `n` is not an
* integer.
* @param {number | bigint} n
* @returns {Address6}
* @example
* new Address6('2001:db8::/64').offset(1).correctForm(); // '2001:db8::1'
*/
offset(n: number | bigint): Address6 {
return Address6.fromBigInt(
common.offsetBigInt(this.bigInt(), n, constants6.BITS, 'IPv6'),
).withSubnetMask(this.subnetMask);
}
/**
* Returns the network that follows this address's network: the address after
* {@link endAddress}, with the same subnet mask. Throws `AddressError` when
* this network is the last one in the address space.
* @returns {Address6}
* @example
* new Address6('2001:db8::/64').nextNetwork().networkForm(); // '2001:db8:0:1::/64'
*/
nextNetwork(): Address6 {
return Address6.fromBigInt(
common.offsetBigInt(this._endAddress(), 1, constants6.BITS, 'IPv6'),
).withSubnetMask(this.subnetMask);
}
private withSubnetMask(subnetMask: number): Address6 {
return new Address6(`${this.correctForm()}/${subnetMask}`);
}
/**
* The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a
* `/64`. Returns an `Address6`; call `.correctForm()` for the string.
* @returns {Address6}
*/
subnetMaskAddress(): Address6 {
return Address6.fromBigInt(
BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants6.BITS - this.subnetMask)}`),
);
}
/**
* The Cisco-style wildcard mask, e.g. `::ffff:ffff:ffff:ffff` for a
* `/64`. This is the bitwise inverse of `subnetMaskAddress()`. Returns
* an `Address6`; call `.correctForm()` for the string.
* @returns {Address6}
*/
wildcardMask(): Address6 {
return Address6.fromBigInt(
BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants6.BITS - this.subnetMask)}`),
);
}
/**
* The network address in CIDR string form, e.g. `2001:db8::/32` for
* `2001:db8::1/32`. For an address with no explicit subnet the prefix
* is `/128`, e.g. `networkForm()` on `2001:db8::1` returns
* `2001:db8::1/128`.
* @returns {string}
*/
networkForm(): string {
return `${this.startAddress().correctForm()}/${this.subnetMask}`;
}
/**
* Return the scope of the address. The 4-bit scope field
* ([RFC 4291 §2.7](https://datatracker.ietf.org/doc/html/rfc4291#section-2.7))
* is only defined for multicast addresses; for unicast addresses the scope
* is derived from the address type per
* [RFC 4007 §6](https://datatracker.ietf.org/doc/html/rfc4007#section-6).
* @returns {String}
*/
getScope(): string {
const type = this.getType();
if (type === 'Multicast' || type.startsWith('Multicast ')) {
const scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
return scope || 'Unknown';
}
// RFC 4291 §2.5.3: the loopback address is treated as having Link-Local
// scope. (Multicast scope 1, "Interface-Local", is a different concept
// used only for loopback transmission of multicast.)
if (type === 'Link-local unicast' || type === 'Loopback') {
return 'Link local';
}
// RFC 4007 §6: the unspecified address has no scope.
if (type === 'Unspecified') {
return 'Unknown';
}
return 'Global';
}
/**
* Return the type of the address
* @returns {String}
*/
getType(): string {
for (let i = 0; i < TYPE_SUBNETS.length; i++) {
const entry = TYPE_SUBNETS[i];
if (this.isHostInSubnet(entry[0])) {
return entry[1];
}
}
return 'Global unicast';
}
/**
* Return the bits in the given range as a BigInt
* @returns {bigint}
*/
getBits(start: number, end: number): bigint {
return BigInt(`0b${this.getBitsBase2(start, end)}`);
}
/**
* Return the bits in the given range as a base-2 string
* @returns {String}
*/
getBitsBase2(start: number, end: number): string {
return this.binaryZeroPad().slice(start, end);
}
/**
* Return the bits in the given range as a base-16 string
* @returns {String}
*/
getBitsBase16(start: number, end: number): string {
const length = end - start;
if (length % 4 !== 0) {
throw new Error('Length of bits to retrieve must be divisible by four');
}
return this.getBits(start, end)
.toString(16)
.padStart(length / 4, '0');
}
/**
* Return the bits that are set past the subnet mask length
* @returns {String}
*/
getBitsPastSubnet(): string {
return this.getBitsBase2(this.subnetMask, constants6.BITS);
}
/**
* Return the reversed ip6.arpa form of the address
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
* @returns {String}
*/
reverseForm(options?: common.ReverseFormOptions): string {
if (!options) {
options = {};
}
const characters = Math.floor(this.subnetMask / 4);
const reversed = this.canonicalForm()
.replace(/:/g, '')
.split('')
.slice(0, characters)
.reverse()
.join('.');
if (characters > 0) {
if (options.omitSuffix) {
return reversed;
}
return `${reversed}.ip6.arpa.`;
}
if (options.omitSuffix) {
return '';
}
return 'ip6.arpa.';
}
/**
* Returns the address in correct form, per
* [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros
* stripped, the longest run of zero groups collapsed to `::`, and hex digits
* lowercased (e.g. `2001:db8::1`). This is the recommended form for display.
*/
correctForm(): string {
let i;
let groups = [];
let zeroCounter = 0;
const zeroes = [];
for (i = 0; i < this.parsedAddress.length; i++) {
const value = parseInt(this.parsedAddress[i], 16);
if (value === 0) {
zeroCounter++;
}
if (value !== 0 && zeroCounter > 0) {
if (zeroCounter > 1) {
zeroes.push([i - zeroCounter, i - 1]);
}
zeroCounter = 0;
}
}
// Do we end with a string of zeroes?
if (zeroCounter > 1) {
zeroes.push([this.parsedAddress.length - zeroCounter, this.parsedAddress.length - 1]);
}
const zeroLengths = zeroes.map((n) => n[1] - n[0] + 1);
if (zeroes.length > 0) {
const index = zeroLengths.indexOf(Math.max(...zeroLengths) as number);
groups = compact(this.parsedAddress, zeroes[index]);
} else {
groups = this.parsedAddress;
}
for (i = 0; i < groups.length; i++) {
if (groups[i] !== 'compact') {
groups[i] = parseInt(groups[i], 16).toString(16);
}
}
let correct = groups.join(':');
correct = correct.replace(/^compact$/, '::');
correct = correct.replace(/(^compact)|(compact$)/, ':');
correct = correct.replace(/compact/, '');
return correct;
}
/**
* Return a zero-padded base-2 string representation of the address
* @returns {String}
* @example
* var address = new Address6('2001:4860:4001:803::1011');
* address.binaryZeroPad();
* // '0010000000000001010010000110000001000000000000010000100000000011
* // 0000000000000000000000000000000000000000000000000001000000010001'
*/
binaryZeroPad(): string {
if (this._binaryZeroPad === undefined) {
this._binaryZeroPad = this.bigInt().toString(2).padStart(constants6.BITS, '0');
}
return this._binaryZeroPad;
}
/**
* Parses a v4-in-v6 string (e.g. `::ffff:192.168.0.1`) by extracting the
* trailing IPv4 address into `this.address4` / `this.parsedAddress4` and
* returning the address with the v4 portion converted to two v6 groups.
* Used internally by `parse()`.
*/
// TODO: Improve the semantics of this helper function
parse4in6(address: string): string {
if (address.indexOf('.') === -1) {
return address;
}
const groups = address.split(':');
const lastGroup = groups.slice(-1)[0];
// RE_ADDRESS rejects octets with a leading zero, so a dotted-quad tail is
// matched permissively first: that way this notation still gets its own
// message with the offending octet highlighted, rather than falling
// through as an unrecognized group.
const v4Octets = lastGroup.split('.');
if (
v4Octets.length === constants4.GROUPS &&
v4Octets.every((octet) => /^\d{1,3}$/.test(octet))
) {
if (v4Octets.some((octet) => /^0\d/.test(octet))) {
// The prefix groups haven't been through the bad-character check
// yet, so escape them before including in the error HTML.
const highlighted = v4Octets.map(spanLeadingZeroes4).join('.');
const prefix = groups.slice(0, -1).map(helpers.escapeHtml).join(':');
const separator = groups.length > 1 ? ':' : '';
throw new AddressError(
"IPv4 addresses can't have leading zeroes.",
`${prefix}${separator}${highlighted}`,
);
}
}
const address4 = lastGroup.match(constants4.RE_ADDRESS);
if (address4) {
this.parsedAddress4 = address4[0];
const v4Suffix = this.subnetMask >= 96 ? `/${this.subnetMask - 96}` : '';
this.address4 = new Address4(`${this.parsedAddress4}${v4Suffix}`);
this.v4 = true;
groups[groups.length - 1] = this.address4.toGroup6();
address = groups.join(':');
}
return address;
}
/**
* Parses an IPv6 address string into its 8 hexadecimal groups (expanding
* any `::` elision and any trailing v4-in-v6 portion) and stores the result
* on `this.parsedAddress`. Called automatically by the constructor; you
* typically don't need to call it directly. Throws `AddressError` if the
* input is malformed.
*/
// TODO: Make private?
parse(address: string): string[] {
address = this.parse4in6(address);
const badCharacters = address.match(constants6.RE_BAD_CHARACTERS);
if (badCharacters) {
throw new AddressError(
`Bad character${
badCharacters.length > 1 ? 's' : ''
} detected in address: ${badCharacters.join('')}`,
address.replace(
constants6.RE_BAD_CHARACTERS,
(character) => `${helpers.escapeHtml(character)}`,
),
);
}
const badAddress = address.match(constants6.RE_BAD_ADDRESS);
if (badAddress) {
throw new AddressError(
`Address failed regex: ${badAddress.join('')}`,
address.replace(constants6.RE_BAD_ADDRESS, '$1'),
);
}
let groups: string[] = [];
const halves = address.split('::');
if (halves.length === 2) {
let first = halves[0].split(':');
let last = halves[1].split(':');
if (first.length === 1 && first[0] === '') {
first = [];
}
if (last.length === 1 && last[0] === '') {
last = [];
}
const remaining = this.groups - (first.length + last.length);
if (!remaining) {
throw new AddressError('Error parsing groups');
}
this.elidedGroups = remaining;
this.elisionBegin = first.length;
this.elisionEnd = first.length + this.elidedGroups;
groups = groups.concat(first);
for (let i = 0; i < remaining; i++) {
groups.push('0');
}
groups = groups.concat(last);
} else if (halves.length === 1) {
groups = address.split(':');
this.elidedGroups = 0;
} else {
throw new AddressError('Too many :: groups found');
}
groups = groups.map((group: string) => parseInt(group, 16).toString(16));
if (groups.length !== this.groups) {
throw new AddressError('Incorrect number of groups found');
}
return groups;
}
/**
* Returns the canonical (fully expanded) form of the address: all 8 groups,
* each padded to 4 hex digits, with no `::` collapsing
* (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and
* byte-exact comparison.
*/
canonicalForm(): string {
return this.parsedAddress.map(paddedHex).join(':');
}
/**
* Return the decimal form of the address
* @returns {String}
*/
decimal(): string {
return this.parsedAddress.map((n) => parseInt(n, 16).toString(10).padStart(5, '0')).join(':');
}
/**
* Return the address as a BigInt
* @returns {bigint}
*/
bigInt(): bigint {
return BigInt(`0x${this.parsedAddress.map(paddedHex).join('')}`);
}
/**
* Return the last two groups of this address as an IPv4 address string.
* If this address carries a CIDR prefix that covers the trailing 32 bits
* (i.e. `subnetMask >= 96`), the resulting `Address4` inherits the
* corresponding v4 prefix (`subnetMask - 96`); otherwise it defaults to
* `/32`.
* @returns {Address4}
* @example
* var address = new Address6('2001:4860:4001::1825:bf11');
* address.to4().correctForm(); // '24.37.191.17'
*/
to4(): Address4 {
const binary = this.binaryZeroPad().split('');
const hex = BigInt(`0b${binary.slice(96, 128).join('')}`)
.toString(16)
.padStart(8, '0');
if (this.subnetMask >= 96) {
const v4Mask = this.subnetMask - 96;
const groups = [];
for (let i = 0; i < 8; i += 2) {
groups.push(parseInt(hex.slice(i, i + 2), 16));
}
return new Address4(`${groups.join('.')}/${v4Mask}`);
}
return Address4.fromHex(hex);
}
/**
* Return the v4-in-v6 form of the address
* @returns {String}
*/
to4in6(): string {
const address4 = this.to4();
const address6 = new Address6(this.parsedAddress.slice(0, 6).join(':'), 6);
const correct = address6.correctForm();
let infix = '';
if (!/:$/.test(correct)) {
infix = ':';
}
return correct + infix + address4.correctForm();
}
/**
* Decodes the Teredo tunneling fields embedded in this address. Returns the
* Teredo prefix, server IPv4, client IPv4, raw flag bits, cone-NAT flag,
* UDP port, and Microsoft-format flag breakdown (reserved, universal/local,
* group/individual, nonce). Only meaningful for addresses in `2001::/32`.
*/
inspectTeredo(): TeredoProperties {
/*
- Bits 0 to 31 are set to the Teredo prefix (normally 2001:0000::/32).
- Bits 32 to 63 embed the primary IPv4 address of the Teredo server that
is used.
- Bits 64 to 79 can be used to define some flags. Currently only the
higher order bit is used; it is set to 1 if the Teredo client is
located behind a cone NAT, 0 otherwise. For Microsoft's Windows Vista
and Windows Server 2008 implementations, more bits are used. In those
implementations, the format for these 16 bits is "CRAAAAUG AAAAAAAA",
where "C" remains the "Cone" flag. The "R" bit is reserved for future
use. The "U" bit is for the Universal/Local flag (set to 0). The "G" bit
is Individual/Group flag (set to 0). The A bits are set to a 12-bit
randomly generated number chosen by the Teredo client to introduce
additional protection for the Teredo node against IPv6-based scanning
attacks.
- Bits 80 to 95 contains the obfuscated UDP port number. This is the
port number that is mapped by the NAT to the Teredo client with all
bits inverted.
- Bits 96 to 127 contains the obfuscated IPv4 address. This is the
public IPv4 address of the NAT with all bits inverted.
*/
const prefix = this.getBitsBase16(0, 32);
const bitsForUdpPort: bigint = this.getBits(80, 96);
const udpPort = (bitsForUdpPort ^ BigInt('0xffff')).toString();
const server4 = Address4.fromHex(this.getBitsBase16(32, 64));
const bitsForClient4 = this.getBits(96, 128);
const client4 = Address4.fromHex(
(bitsForClient4 ^ BigInt('0xffffffff')).toString(16).padStart(8, '0'),
);
const flagsBase2 = this.getBitsBase2(64, 80);
const coneNat = testBit(flagsBase2, 15);
const reserved = testBit(flagsBase2, 14);
const groupIndividual = testBit(flagsBase2, 8);
const universalLocal = testBit(flagsBase2, 9);
const nonce = BigInt(`0b${flagsBase2.slice(2, 6) + flagsBase2.slice(8, 16)}`).toString(10);
return {
prefix: `${prefix.slice(0, 4)}:${prefix.slice(4, 8)}`,
server4: server4.address,
client4: client4.address,
flags: flagsBase2,
coneNat,
microsoft: {
reserved,
universalLocal,
groupIndividual,
nonce,
},
udpPort,
};
}
/**
* Decodes the 6to4 tunneling fields embedded in this address. Returns the
* 6to4 prefix and the embedded IPv4 gateway address. Only meaningful for
* addresses in `2002::/16`.
*/
inspect6to4(): SixToFourProperties {
/*
- Bits 0 to 15 are set to the 6to4 prefix (2002::/16).
- Bits 16 to 48 embed the IPv4 address of the 6to4 gateway that is used.
*/
const prefix = this.getBitsBase16(0, 16);
const gateway = Address4.fromHex(this.getBitsBase16(16, 48));
return {
prefix: prefix.slice(0, 4),
gateway: gateway.address,
};
}
/**
* Return a v6 6to4 address from a v6 v4inv6 address
* @returns {Address6}
*/
to6to4(): Address6 | null {
if (!this.is4()) {
return null;
}
const addr6to4 = [
'2002',
this.getBitsBase16(96, 112),
this.getBitsBase16(112, 128),
'',
'/16',
].join(':');
return new Address6(addr6to4);
}
/**
* Embed an IPv4 address into a NAT64 IPv6 address using the encoding
* defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
* The default prefix is the well-known prefix `64:ff9b::/96`. The prefix
* length must be one of 32, 40, 48, 56, 64, or 96; for prefixes shorter
* than /64 the IPv4 octets are split around the reserved bits 64–71.
* @example
* Address6.fromAddress4Nat64('192.0.2.33').correctForm(); // '64:ff9b::c000:221'
* Address6.fromAddress4Nat64('192.0.2.33', '2001:db8::/32').correctForm(); // '2001:db8:c000:221::'
*/
static fromAddress4Nat64(address: string, prefix: string = '64:ff9b::/96'): Address6 {
const v4 = new Address4(address);
const prefix6 = new Address6(prefix);
const pl = prefix6.subnetMask;
if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
throw new AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
}
const prefixBits = prefix6.binaryZeroPad();
const v4Bits = v4.binaryZeroPad();
let bits: string;
if (pl === 96) {
bits = prefixBits.slice(0, 96) + v4Bits;
} else {
const beforeU = 64 - pl;
bits = [
prefixBits.slice(0, pl),
v4Bits.slice(0, beforeU),
// Bits 64 to 71 are the reserved u octet and are always zero.
'00000000',
v4Bits.slice(beforeU),
'0'.repeat(128 - 72 - (32 - beforeU)),
].join('');
}
const hex = BigInt(`0b${bits}`).toString(16).padStart(32, '0');
const groups: string[] = [];
for (let i = 0; i < 8; i++) {
groups.push(hex.slice(i * 4, (i + 1) * 4));
}
return new Address6(groups.join(':'));
}
/**
* Extract the embedded IPv4 address from a NAT64 IPv6 address using the
* encoding defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
* The default prefix is the well-known prefix `64:ff9b::/96`. Returns
* `null` if this address is not contained within the given prefix.
* @example
* new Address6('64:ff9b::c000:221').toAddress4Nat64()!.correctForm(); // '192.0.2.33'
*/
toAddress4Nat64(prefix: string = '64:ff9b::/96'): Address4 | null {
const prefix6 = new Address6(prefix);
const pl = prefix6.subnetMask;
if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
throw new AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
}
if (!this.isHostInSubnet(prefix6)) {
return null;
}
const bits = this.binaryZeroPad();
let v4Bits: string;
if (pl === 96) {
v4Bits = bits.slice(96, 128);
} else {
const beforeU = 64 - pl;
v4Bits = bits.slice(pl, pl + beforeU) + bits.slice(72, 72 + (32 - beforeU));
}
const octets: string[] = [];
for (let i = 0; i < 4; i++) {
octets.push(parseInt(v4Bits.slice(i * 8, (i + 1) * 8), 2).toString());
}
return new Address4(octets.join('.'));
}
/**
* Return a byte array.
*
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`.
* @returns {Array}
*/
toByteArray(): number[] {
const value = this.bigInt()
.toString(16)
.padStart(constants6.BITS / 4, '0');
const bytes = [];
for (let i = 0, length = value.length; i < length; i += 2) {
bytes.push(parseInt(value.substring(i, i + 2), 16));
}
return bytes;
}
/**
* Return an unsigned byte array.
*
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`.
* @returns {Array}
*/
toUnsignedByteArray(): number[] {
// toByteArray() emits 0 to 255, so unsigning it is an identity mapping and
// the two methods return equal arrays. 11.0.0 keeps one of them and makes
// this a deprecated alias; test/common-test.ts fails at that version.
return this.toByteArray().map(unsignByte);
}
/**
* Convert a byte array to an Address6 object.
*
* Accepts unsigned bytes (0 to 255) or signed bytes (-128 to 127, as an
* `Int8Array` or a Java `byte[]` holds them), folding signed values to their
* unsigned equivalent. Throws `AddressError` unless given exactly 16
* integers from -128 to 255.
*
* To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`.
* @returns {Address6}
*/
static fromByteArray(bytes: Array): Address6 {
// Address4.fromByteArray takes unsigned bytes only. 11.0.0 aligns this
// method with it, at which point the -128 floor here, unsignByte, and the
// mapping below all go; test/common-test.ts fails at that version.
common.assertByteArray(bytes, 16, 'IPv6', -128);
return this.fromUnsignedByteArray(bytes.map(unsignByte));
}
/**
* Convert an unsigned byte array to an Address6 object.
*
* Throws `AddressError` unless given exactly 16 integers from 0 to 255.
*
* To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`.
* @returns {Address6}
*/
static fromUnsignedByteArray(bytes: Array): Address6 {
common.assertByteArray(bytes, 16, 'IPv6', 0);
const BYTE_MAX = BigInt('256');
let result = BigInt('0');
let multiplier = BigInt('1');
for (let i = bytes.length - 1; i >= 0; i--) {
result += multiplier * BigInt(bytes[i].toString(10));
multiplier *= BYTE_MAX;
}
return Address6.fromBigInt(result);
}
// #region Attributes
/**
* Returns true if the given address is in the subnet of the current address.
* An `Address4` is never in the subnet of an `Address6`; convert with
* `Address6.fromAddress4()` or `to4()` to compare across families.
* @returns {boolean}
*/
isInSubnet = common.isInSubnet;
/**
* Returns true if this address's host bits fall inside the given subnet,
* ignoring this address's own subnet mask. Prefer this over `isInSubnet`
* when classifying a single address, so the answer doesn't change with the
* CIDR suffix the caller happened to write — notably when the address came
* from untrusted input and the result backs a trust-boundary decision.
* An `Address4` is never in the subnet of an `Address6`; convert with
* `Address6.fromAddress4()` or `to4()` to compare across families.
* @returns {boolean}
*/
isHostInSubnet = common.isHostInSubnet;
/**
* Returns true if the address is correct, false otherwise
* @returns {boolean}
*/
isCorrect = isCorrect6;
/**
* Returns true if the address is in the canonical form, false otherwise
* @returns {boolean}
*/
isCanonical(): boolean {
return this.addressMinusSuffix === this.canonicalForm();
}
/**
* Returns true if the address is a link-local unicast address in `fe80::/10`
* ([RFC 4291 §2.4](https://datatracker.ietf.org/doc/html/rfc4291#section-2.4))
* or an IPv4-mapped / NAT64 address whose embedded IPv4 address is link-local
* (`169.254.0.0/16`, e.g. `::ffff:169.254.169.254`), false otherwise.
* @returns {boolean}
*/
isLinkLocal(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isLinkLocal();
}
return this.isHostInSubnet(LINK_LOCAL_SUBNET);
}
/**
* Returns true if the address is a multicast address, false otherwise
* @returns {boolean}
*/
isMulticast(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isMulticast();
}
const type = this.getType();
return type === 'Multicast' || type.startsWith('Multicast ');
}
/**
* Returns true if the address was written in v4-in-v6 dotted-quad notation
* (e.g. `::ffff:127.0.0.1`), false otherwise. This is a notation-level flag
* and does not reflect whether the address bits lie in the IPv4-mapped
* (`::ffff:0:0/96`) subnet — for that, see {@link isMapped4}.
* @returns {boolean}
*/
is4(): boolean {
return this.v4;
}
/**
* Returns true if the address is an IPv4-mapped IPv6 address in
* `::ffff:0:0/96` ([RFC 4291 §2.5.5.2](https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2)),
* false otherwise. Unlike {@link is4}, this checks the underlying address
* bits rather than the textual notation, so `::ffff:127.0.0.1` and
* `::ffff:7f00:1` both return true.
* @returns {boolean}
*/
isMapped4(): boolean {
return this.isHostInSubnet(IPV4_MAPPED_SUBNET);
}
/**
* If this address embeds a routable IPv4 address — i.e. it is IPv4-mapped
* (`::ffff:0:0/96`) or sits in the NAT64 well-known prefix (`64:ff9b::/96`,
* [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052)) — return that
* embedded address as an {@link Address4}; otherwise return null.
*
* The special-property checks (`isLoopback`, `isLinkLocal`, `isMulticast`,
* `isUnspecified`, `isPrivate`, `isCGNAT`, `isBroadcast`) call this first and
* delegate to the embedded {@link Address4} when present, so a literal such as
* `::ffff:127.0.0.1` is classified by what it actually reaches (loopback)
* rather than by its IPv6 wrapper (which `getType()` reports as IPv4-mapped).
* This matters wherever the checks back a trust-boundary decision (e.g. an
* SSRF allow/deny filter): without normalization, `::ffff:10.0.0.1`,
* `::ffff:169.254.169.254`, `64:ff9b::7f00:1`, etc. would all read as
* non-internal.
* @returns {Address4 | null}
*/
embeddedIPv4(): Address4 | null {
if (this.isMapped4() || this.isHostInSubnet(NAT64_WELL_KNOWN_SUBNET)) {
return this.to4();
}
return null;
}
/**
* Returns true if the address is a Teredo address, false otherwise
* @returns {boolean}
*/
isTeredo(): boolean {
return this.isHostInSubnet(TEREDO_SUBNET);
}
/**
* Returns true if the address is a 6to4 address, false otherwise
* @returns {boolean}
*/
is6to4(): boolean {
return this.isHostInSubnet(SIX_TO_FOUR_SUBNET);
}
/**
* Returns true if the address is a loopback address, false otherwise
* @returns {boolean}
*/
isLoopback(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isLoopback();
}
return this.getType() === 'Loopback';
}
/**
* Returns true if the address is a Unique Local Address in `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)). ULAs are the IPv6 equivalent of IPv4 [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private addresses.
* @returns {boolean}
*/
isULA(): boolean {
return this.isHostInSubnet(ULA_SUBNET);
}
/**
* Returns true if the address is private, i.e. a Unique Local Address in
* `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)), an
* address in the NAT64 local-use range `64:ff9b:1::/48`
* ([RFC 8215](https://datatracker.ietf.org/doc/html/rfc8215)), or an
* IPv4-mapped / NAT64 well-known address whose embedded IPv4 address is in
* one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918)
* private ranges (e.g. `::ffff:10.0.0.1`). This is the IPv6 counterpart to
* {@link Address4.isPrivate}; use it instead of {@link isULA} when you need to
* catch mapped RFC 1918 addresses as well as native ULAs.
*
* The local-use NAT64 range is reported private as a whole rather than by
* its embedded IPv4 address: an operator may carve a prefix of any RFC 6052
* length out of `64:ff9b:1::/48`, so the same bits decode to different IPv4
* addresses under different deployments and no single decoding is correct.
* Use {@link toAddress4Nat64} with the deployment's prefix to decode one.
* @returns {boolean}
*/
isPrivate(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isPrivate();
}
return this.isULA() || this.isHostInSubnet(NAT64_LOCAL_USE_SUBNET);
}
/**
* Returns true if the address is an IPv4-mapped / NAT64 address whose embedded
* IPv4 address is in the carrier-grade NAT range `100.64.0.0/10`
* ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)), false
* otherwise. There is no native IPv6 CGNAT range, so this only ever returns
* true for an embedded IPv4 address (e.g. `::ffff:100.64.0.1`).
* @returns {boolean}
*/
isCGNAT(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isCGNAT();
}
return false;
}
/**
* Returns true if the address is an IPv4-mapped / NAT64 address whose embedded
* IPv4 address is the limited broadcast address `255.255.255.255`
* ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)), false otherwise.
* There is no IPv6 broadcast, so this only ever returns true for an embedded
* IPv4 address (e.g. `::ffff:255.255.255.255`).
* @returns {boolean}
*/
isBroadcast(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isBroadcast();
}
return false;
}
/**
* Returns true if the address is the unspecified address `::`.
* @returns {boolean}
*/
isUnspecified(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isUnspecified();
}
return this.getType() === 'Unspecified';
}
/**
* Returns true if the address is in the documentation prefix `2001:db8::/32` ([RFC 3849](https://datatracker.ietf.org/doc/html/rfc3849)).
* @returns {boolean}
*/
isDocumentation(): boolean {
return DOCUMENTATION_SUBNETS.some((subnet) => this.isHostInSubnet(subnet));
}
/**
* Returns true if the address is in the benchmarking range `2001:2::/48`
* ([RFC 5180](https://datatracker.ietf.org/doc/html/rfc5180)) or is an
* IPv4-mapped / NAT64 address whose embedded IPv4 address is in
* `198.18.0.0/15`, false otherwise.
* @returns {boolean}
*/
isBenchmarking(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isBenchmarking();
}
return this.isHostInSubnet(BENCHMARKING_SUBNET);
}
/**
* Returns true if the address is globally reachable: inside the global
* unicast allocation `2000::/3` (the only range the [IANA IPv6 Address Space
* Registry](https://www.iana.org/assignments/ipv6-address-space/) assigns
* for global unicast; everything else is reserved, ULA, link-local, or
* multicast) and not in any block the [IANA IPv6 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv6-special-registry/)
* marks as not globally reachable. An IPv4-mapped or NAT64 well-known
* address answers for its embedded IPv4 address, so `::ffff:10.0.0.1` and
* `64:ff9b::7f00:1` are not global. Teredo (`2001::/32`) and 6to4
* (`2002::/16`) are not global either: the registry lists them as N/A and a
* packet to one needs a relay.
*
* This covers everything the individual classifiers name and the blocks they
* do not: the discard-only prefix `100::/64`, the IETF protocol assignments
* in `2001::/23`, the deprecated site-local `fec0::/10` and IPv4-compatible
* `::/96` ranges, and unallocated space such as `4000::/3`. It is the single
* predicate to use where a request must not reach an internal or
* special-purpose destination; see SECURITY.md.
* @returns {boolean}
*/
isGlobal(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isGlobal();
}
return (
this.isHostInSubnet(GLOBAL_UNICAST_SUBNET) &&
common.isGloballyReachable.call(this, SPECIAL_PURPOSE_V6)
);
}
// #endregion
// #region HTML
/**
* Returns the address as an HTTP URL with the host bracketed, e.g.
* `http://[2001:db8::1]/`. If `optionalPort` is provided it is appended,
* e.g. `http://[2001:db8::1]:8080/`.
*/
href(optionalPort?: number | string): string {
if (optionalPort === undefined) {
optionalPort = '';
} else {
optionalPort = `:${optionalPort}`;
}
return `http://[${this.correctForm()}]${optionalPort}/`;
}
/**
* Returns an HTML `` element whose `href` encodes the address in a URL
* hash fragment (default prefix `/#address=`). Useful for linking between
* pages of an address-inspector UI.
* @param options.className - CSS class for the rendered `` element
* @param options.prefix - hash prefix prepended to the address (default `/#address=`)
* @param options.v4 - when true, render the address in v4-in-v6 form
*/
link(options?: { className?: string; prefix?: string; v4?: boolean }): string {
if (!options) {
options = {};
}
if (options.className === undefined) {
options.className = '';
}
if (options.prefix === undefined) {
options.prefix = '/#address=';
}
if (options.v4 === undefined) {
options.v4 = false;
}
let formFunction = this.correctForm;
if (options.v4) {
formFunction = this.to4in6;
}
const form = formFunction.call(this);
const safeHref = helpers.escapeHtml(`${options.prefix}${form}`);
const safeForm = helpers.escapeHtml(form);
if (options.className) {
const safeClass = helpers.escapeHtml(options.className);
return `${safeForm}`;
}
return `${safeForm}`;
}
/**
* Groups an address.
*
* Returns an HTML fragment: each group is wrapped in a `` carrying
* the group classes an address-inspector UI hovers on. The address content
* is HTML-escaped; anything you concatenate around it is your
* responsibility.
* @returns {String}
*/
group(): string {
if (this.elidedGroups === 0) {
// The simple case
return helpers.simpleGroup(this.addressMinusSuffix).join(':');
}
assert(typeof this.elidedGroups === 'number');
assert(typeof this.elisionBegin === 'number');
// The elided case
const output = [];
const [left, right] = this.addressMinusSuffix.split('::');
if (left.length) {
output.push(...helpers.simpleGroup(left));
} else {
output.push('');
}
const classes = ['hover-group'];
for (let i = this.elisionBegin; i < this.elisionBegin + this.elidedGroups; i++) {
classes.push(`group-${i}`);
}
output.push(``);
if (right.length) {
output.push(...helpers.simpleGroup(right, this.elisionEnd));
} else {
output.push('');
}
if (this.is4()) {
assert(this.address4 instanceof Address4);
output.pop();
output.push(this.address4.groupForV6());
}
return output.join(':');
}
// #endregion
// #region Regular expressions
/**
* Generate a regular expression string that can be used to find or validate
* all variations of this address
* @param {boolean} substringSearch
* @returns {string}
*/
regularExpressionString(this: Address6, substringSearch: boolean = false): string {
let output: string[] = [];
// TODO: revisit why this is necessary
const address6 = new Address6(this.correctForm());
if (address6.elidedGroups === 0) {
// The simple case
output.push(simpleRegularExpression(address6.parsedAddress));
} else if (address6.elidedGroups === constants6.GROUPS) {
// A completely elided address
output.push(possibleElisions(constants6.GROUPS));
} else {
// A partially elided address
const halves = address6.address.split('::');
if (halves[0].length) {
output.push(simpleRegularExpression(halves[0].split(':')));
}
assert(typeof address6.elidedGroups === 'number');
output.push(
possibleElisions(address6.elidedGroups, halves[0].length !== 0, halves[1].length !== 0),
);
if (halves[1].length) {
output.push(simpleRegularExpression(halves[1].split(':')));
}
output = [output.join(':')];
}
if (!substringSearch) {
output = [
'(?=^|',
ADDRESS_BOUNDARY,
'|[^\\w\\:])(',
...output,
')(?=[^\\w\\:]|',
ADDRESS_BOUNDARY,
'|$)',
];
}
return output.join('');
}
/**
* Generate a regular expression that can be used to find or validate all
* variations of this address.
* @param {boolean} substringSearch
* @returns {RegExp}
*/
regularExpression(this: Address6, substringSearch: boolean = false): RegExp {
return new RegExp(this.regularExpressionString(substringSearch), 'i');
}
// #endregion
}
const TYPE_SUBNETS: Array<[Address6, string]> = Object.keys(constants6.TYPES).map((subnet) => [
new Address6(subnet),
constants6.TYPES[subnet] as string,
]);
const TEREDO_SUBNET = new Address6('2001::/32');
const SIX_TO_FOUR_SUBNET = new Address6('2002::/16');
const ULA_SUBNET = new Address6('fc00::/7');
const LINK_LOCAL_SUBNET = new Address6('fe80::/10');
const DOCUMENTATION_SUBNETS = [new Address6('2001:db8::/32'), new Address6('3fff::/20')];
const BENCHMARKING_SUBNET = new Address6('2001:2::/48');
const GLOBAL_UNICAST_SUBNET = new Address6('2000::/3');
const SPECIAL_PURPOSE_V6 = constants6.SPECIAL_PURPOSE.map(([cidr, , reachable]) => ({
subnet: new Address6(cidr),
reachable,
}));
const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96');
const NAT64_WELL_KNOWN_SUBNET = new Address6('64:ff9b::/96');
const NAT64_LOCAL_USE_SUBNET = new Address6('64:ff9b:1::/48');
beaugunderson-ip-address-438375e/src/v4/ 0000775 0000000 0000000 00000000000 15272410673 0020017 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/src/v4/constants.ts 0000664 0000000 0000000 00000005030 15272410673 0022401 0 ustar 00root root 0000000 0000000 export const BITS = 32;
export const GROUPS = 4;
// Each octet is 0-255 written without a leading zero. A leading zero is
// octal to the WHATWG URL parser, inet_aton, and getaddrinfo, but decimal to
// parseInt(part, 10), so accepting the notation would make this library
// disagree with the network stack about which host a string names.
export const RE_ADDRESS =
/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/g;
export const RE_SUBNET_STRING = /\/\d{1,2}$/;
/**
* The IANA IPv4 Special-Purpose Address Registry
* (https://www.iana.org/assignments/iana-ipv4-special-registry/), one entry
* per block: `[cidr, name, globallyReachable]`. A `null` reachability means
* the registry leaves the column blank and the block inherits the answer of
* the block containing it (or is global when nothing contains it).
*
* `Address4.isGlobal()` answers from the most specific entry containing the
* address. `test/data/iana-corpus.json` is generated from the registry's CSV
* and pins this table to it.
*/
export const SPECIAL_PURPOSE: ReadonlyArray = [
['0.0.0.0/8', 'This network', false],
['0.0.0.0/32', 'This host on this network', false],
['10.0.0.0/8', 'Private-Use', false],
['100.64.0.0/10', 'Shared Address Space', false],
['127.0.0.0/8', 'Loopback', false],
['169.254.0.0/16', 'Link Local', false],
['172.16.0.0/12', 'Private-Use', false],
['192.0.0.0/24', 'IETF Protocol Assignments', false],
['192.0.0.0/29', 'IPv4 Service Continuity Prefix', false],
['192.0.0.8/32', 'IPv4 dummy address', false],
['192.0.0.9/32', 'Port Control Protocol Anycast', true],
['192.0.0.10/32', 'Traversal Using Relays around NAT Anycast', true],
['192.0.0.170/32', 'NAT64/DNS64 Discovery', false],
['192.0.0.171/32', 'NAT64/DNS64 Discovery', false],
['192.0.2.0/24', 'Documentation (TEST-NET-1)', false],
['192.31.196.0/24', 'AS112-v4', true],
['192.52.193.0/24', 'AMT', true],
['192.88.99.0/24', 'Deprecated (6to4 Relay Anycast)', null],
['192.88.99.2/32', '6a44-relay anycast address', false],
['192.168.0.0/16', 'Private-Use', false],
['192.175.48.0/24', 'Direct Delegation AS112 Service', true],
['198.18.0.0/15', 'Benchmarking', false],
['198.51.100.0/24', 'Documentation (TEST-NET-2)', false],
['203.0.113.0/24', 'Documentation (TEST-NET-3)', false],
['240.0.0.0/4', 'Reserved', false],
['255.255.255.255/32', 'Limited Broadcast', false],
];
beaugunderson-ip-address-438375e/src/v6/ 0000775 0000000 0000000 00000000000 15272410673 0020021 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/src/v6/constants.ts 0000664 0000000 0000000 00000011744 15272410673 0022414 0 ustar 00root root 0000000 0000000 export const BITS = 128;
export const GROUPS = 8;
/**
* Represents IPv6 address scopes
* @memberof Address6
* @static
*/
export const SCOPES: { [key: number]: string | undefined } = {
0: 'Reserved',
1: 'Interface local',
2: 'Link local',
4: 'Admin local',
5: 'Site local',
8: 'Organization local',
14: 'Global',
15: 'Reserved',
} as const;
/**
* Represents IPv6 address types
* @memberof Address6
* @static
*/
export const TYPES: { [key: string]: string | undefined } = {
'ff01::1/128': 'Multicast (All nodes on this interface)',
'ff01::2/128': 'Multicast (All routers on this interface)',
'ff02::1/128': 'Multicast (All nodes on this link)',
'ff02::2/128': 'Multicast (All routers on this link)',
'ff05::2/128': 'Multicast (All routers in this site)',
'ff02::5/128': 'Multicast (OSPFv3 AllSPF routers)',
'ff02::6/128': 'Multicast (OSPFv3 AllDR routers)',
'ff02::9/128': 'Multicast (RIP routers)',
'ff02::a/128': 'Multicast (EIGRP routers)',
'ff02::d/128': 'Multicast (PIM routers)',
'ff02::16/128': 'Multicast (MLDv2 reports)',
'ff01::fb/128': 'Multicast (mDNSv6)',
'ff02::fb/128': 'Multicast (mDNSv6)',
'ff05::fb/128': 'Multicast (mDNSv6)',
'ff02::1:2/128': 'Multicast (All DHCP servers and relay agents on this link)',
'ff05::1:2/128': 'Multicast (All DHCP servers and relay agents in this site)',
'ff02::1:3/128': 'Multicast (All DHCP servers on this link)',
'ff05::1:3/128': 'Multicast (All DHCP servers in this site)',
'::/128': 'Unspecified',
'::1/128': 'Loopback',
'::ffff:0:0/96': 'IPv4-mapped',
'ff00::/8': 'Multicast',
'fe80::/10': 'Link-local unicast',
'fc00::/7': 'Unique local',
'2001::/32': 'Teredo',
'2001:2::/48': 'Benchmarking',
'2002::/16': '6to4',
'2001:db8::/32': 'Documentation',
'3fff::/20': 'Documentation',
'100::/64': 'Discard-only',
'fec0::/10': 'Site-local unicast (deprecated)',
'::/96': 'IPv4-compatible (deprecated)',
'64:ff9b::/96': 'NAT64 (well-known)',
'64:ff9b:1::/48': 'NAT64 (local-use)',
} as const;
/**
* A regular expression that matches bad characters in an IPv6 address
* @memberof Address6
* @static
*/
export const RE_BAD_CHARACTERS = /([^0-9a-f:/%])/gi;
/**
* A regular expression that matches an incorrect IPv6 address
* @memberof Address6
* @static
*/
export const RE_BAD_ADDRESS = /([0-9a-f]{5,}|:{3,}|[^:]:$|^:[^:]|\/$)/gi;
/**
* A regular expression that matches an IPv6 subnet
* @memberof Address6
* @static
*/
export const RE_SUBNET_STRING = /\/\d{1,3}(?=%|$)/;
/**
* A regular expression that matches an IPv6 zone
* @memberof Address6
* @static
* @deprecated Takes quadratic time on input holding many `%` characters
* followed by a line terminator. The library finds the zone by index, as
* `Address6`'s constructor shows, and 11.0.0 removes this export.
*/
export const RE_ZONE_STRING = /%.*$/;
export const RE_URL = /^(?:\[([0-9a-f:.]+)\]|([0-9a-f:.]+))(?:[/?#].*)?$/i;
export const RE_URL_WITH_PORT = /^\[([0-9a-f:.]+)\]:([0-9]{1,5})(?:[/?#].*)?$/i;
/**
* The IANA IPv6 Special-Purpose Address Registry
* (https://www.iana.org/assignments/iana-ipv6-special-registry/), one entry
* per block: `[cidr, name, globallyReachable]`. A `null` reachability means
* the registry says N/A or leaves the column blank; N/A blocks (Teredo, 6to4)
* are treated as not globally reachable, since a packet to one needs a relay,
* and blank blocks inherit the answer of the block containing them.
*
* `Address6.isGlobal()` answers from the most specific entry containing the
* address, after delegating IPv4-mapped and NAT64 well-known addresses to the
* embedded IPv4 address. `test/data/iana-corpus.json` is generated from the
* registry's CSV and pins this table to it.
*/
export const SPECIAL_PURPOSE: ReadonlyArray = [
['::1/128', 'Loopback Address', false],
['::/128', 'Unspecified Address', false],
['::ffff:0:0/96', 'IPv4-mapped Address', false],
['64:ff9b::/96', 'IPv4-IPv6 Translat.', true],
['64:ff9b:1::/48', 'IPv4-IPv6 Translat.', false],
['100::/64', 'Discard-Only Address Block', false],
['100:0:0:1::/64', 'Dummy IPv6 Prefix', false],
['2001::/23', 'IETF Protocol Assignments', false],
['2001::/32', 'TEREDO', false],
['2001:1::1/128', 'Port Control Protocol Anycast', true],
['2001:1::2/128', 'Traversal Using Relays around NAT Anycast', true],
['2001:1::3/128', 'DNS-SD Service Registration Protocol Anycast', true],
['2001:2::/48', 'Benchmarking', false],
['2001:3::/32', 'AMT', true],
['2001:4:112::/48', 'AS112-v6', true],
['2001:10::/28', 'Deprecated (previously ORCHID)', null],
['2001:20::/28', 'ORCHIDv2', true],
['2001:30::/28', 'Drone Remote ID Protocol Entity Tags (DETs) Prefix', true],
['2001:db8::/32', 'Documentation', false],
['2002::/16', '6to4', false],
['2620:4f:8000::/48', 'Direct Delegation AS112 Service', true],
['3fff::/20', 'Documentation', false],
['5f00::/16', 'Segment Routing (SRv6) SIDs', false],
['fc00::/7', 'Unique-Local', false],
['fe80::/10', 'Link-Local Unicast', false],
];
beaugunderson-ip-address-438375e/src/v6/helpers.ts 0000664 0000000 0000000 00000002772 15272410673 0022043 0 ustar 00root root 0000000 0000000 export function escapeHtml(s: string): string {
return s
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
/**
* @returns {String} the string with all zeroes contained in a
*/
export function spanAllZeroes(s: string): string {
return escapeHtml(s).replace(/(0+)/g, '$1');
}
/**
* @returns {String} the string with each character contained in a
*/
export function spanAll(s: string, offset: number = 0): string {
const letters = s.split('');
return letters
.map(
(n, i) =>
`${spanAllZeroes(n)}`,
)
.join('');
}
function spanLeadingZeroesSimple(group: string): string {
return escapeHtml(group).replace(/^(0+)/, '$1');
}
/**
* @returns {String} the string with leading zeroes contained in a
*/
export function spanLeadingZeroes(address: string): string {
const groups = address.split(':');
return groups.map((g) => spanLeadingZeroesSimple(g)).join(':');
}
/**
* Groups an address
* @returns {String} a grouped address
*/
export function simpleGroup(addressString: string, offset: number = 0): string[] {
const groups = addressString.split(':');
return groups.map((g, i) => {
if (/group-v4/.test(g)) {
return g;
}
return `${spanLeadingZeroesSimple(g)}`;
});
}
beaugunderson-ip-address-438375e/src/v6/regular-expressions.ts 0000664 0000000 0000000 00000004526 15272410673 0024421 0 ustar 00root root 0000000 0000000 import * as v6 from './constants';
export function groupPossibilities(possibilities: string[]): string {
return `(${possibilities.join('|')})`;
}
export function padGroup(group: string): string {
if (group.length < 4) {
return `0{0,${4 - group.length}}${group}`;
}
return group;
}
export const ADDRESS_BOUNDARY = '[^A-Fa-f0-9:]';
export function simpleRegularExpression(groups: string[]) {
const zeroIndexes: number[] = [];
groups.forEach((group, i) => {
const groupInteger = parseInt(group, 16);
if (groupInteger === 0) {
zeroIndexes.push(i);
}
});
// You can technically elide a single 0, this creates the regular expressions
// to match that eventuality
const possibilities = zeroIndexes.map((zeroIndex) =>
groups
.map((group, i) => {
if (i === zeroIndex) {
const elision = i === 0 || i === v6.GROUPS - 1 ? ':' : '';
return groupPossibilities([padGroup(group), elision]);
}
return padGroup(group);
})
.join(':'),
);
// The simplest case
possibilities.push(groups.map(padGroup).join(':'));
return groupPossibilities(possibilities);
}
export function possibleElisions(
elidedGroups: number,
moreLeft?: boolean,
moreRight?: boolean,
): string {
const left = moreLeft ? '' : ':';
const right = moreRight ? '' : ':';
const possibilities = [];
// 1. elision of everything (::)
if (!moreLeft && !moreRight) {
possibilities.push('::');
}
// 2. complete elision of the middle
if (moreLeft && moreRight) {
possibilities.push('');
}
if ((moreRight && !moreLeft) || (!moreRight && moreLeft)) {
// 3. complete elision of one side
possibilities.push(':');
}
// 4. elision from the left side
possibilities.push(`${left}(:0{1,4}){1,${elidedGroups - 1}}`);
// 5. elision from the right side
possibilities.push(`(0{1,4}:){1,${elidedGroups - 1}}${right}`);
// 6. no elision
possibilities.push(`(0{1,4}:){${elidedGroups - 1}}0{1,4}`);
// 7. elision (including sloppy elision) from the middle
for (let groups = 1; groups < elidedGroups - 1; groups++) {
for (let position = 1; position < elidedGroups - groups; position++) {
possibilities.push(
`(0{1,4}:){${position}}:(0{1,4}:){${elidedGroups - position - groups - 1}}0{1,4}`,
);
}
}
return groupPossibilities(possibilities);
}
beaugunderson-ip-address-438375e/test/ 0000775 0000000 0000000 00000000000 15272410673 0017656 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/test/.eslintrc 0000664 0000000 0000000 00000000067 15272410673 0021505 0 ustar 00root root 0000000 0000000 {
"env": {
"node": true,
"mocha": true
}
}
beaugunderson-ip-address-438375e/test/address-test.ts 0000664 0000000 0000000 00000015552 15272410673 0022640 0 ustar 00root root 0000000 0000000 /* eslint-disable import/extensions */
/* eslint-disable no-param-reassign */
import * as chai from 'chai';
import { Address4, Address6 } from '../src/ip-address';
import intermapperInvalid6 from './data/intermapper-invalid-ipv6-addresses.json';
import intermapperValid6 from './data/intermapper-valid-ipv6-addresses.json';
import invalid4 from './data/invalid-ipv4-addresses.json';
import invalid6 from './data/invalid-ipv6-addresses.json';
import valid4 from './data/valid-ipv4-addresses.json';
import valid6 from './data/valid-ipv6-addresses.json';
const should = chai.should();
function addressIs(addressString: string, descriptors: string[]) {
describe(addressString, () => {
descriptors.forEach((descriptor) => {
if (descriptor === 'valid-ipv4') {
const address4 = new Address4(addressString);
it('is valid', () => {
address4.should.be.an('object');
address4.parsedAddress.should.be.an.instanceOf(Array);
address4.parsedAddress.length.should.equal(4);
address4.subnetMask.should.be.a('number');
address4.subnetMask.should.be.at.least(0);
address4.subnetMask.should.be.at.most(128);
});
it('converts to arpa format and back', () => {
const arpa = address4.reverseForm();
arpa.length.should.be.at.most(29);
const arpaWithoutSuffix = address4.reverseForm({ omitSuffix: true });
arpaWithoutSuffix.length.should.be.at.most(15);
const converted = Address4.fromArpa(arpa);
address4.correctForm().should.equal(converted.correctForm());
});
}
if (descriptor === 'valid-ipv6') {
const address6 = new Address6(addressString);
it('is valid', () => {
address6.should.be.an('object');
address6.zone.should.be.a('string');
address6.subnet.should.be.a('string');
address6.subnetMask.should.be.a('number');
address6.subnetMask.should.be.at.least(0);
address6.subnetMask.should.be.at.most(128);
address6.parsedAddress.should.be.an.instanceOf(Array);
address6.parsedAddress.length.should.equal(8);
});
const re = address6.regularExpression();
const reSubstring = address6.regularExpression(true);
it('matches the correct form via regex', () => {
re.test(address6.correctForm()).should.equal(true);
reSubstring.test(`abc ${address6.correctForm()} def`).should.equal(true);
});
it('matches the canonical form via regex', () => {
re.test(address6.canonicalForm()).should.equal(true);
reSubstring.test(`abc ${address6.canonicalForm()} def`).should.equal(true);
});
it('matches the given form via regex', () => {
// We can't match addresses like ::192.168.0.1 yet
if (address6.is4()) {
return;
}
re.test(addressString).should.equal(true);
reSubstring.test(`abc ${addressString} def`).should.equal(true);
});
it('converts to a byte array and back', () => {
const byteArray = address6.toByteArray();
byteArray.length.should.equal(16);
const converted = Address6.fromByteArray(byteArray);
address6.correctForm().should.equal(converted.correctForm());
});
it('converts to an unsigned byte array and back', () => {
const byteArray = address6.toUnsignedByteArray();
byteArray.length.should.equal(16);
const converted = Address6.fromUnsignedByteArray(byteArray);
address6.correctForm().should.equal(converted.correctForm());
});
}
if (descriptor === 'invalid-ipv4') {
it('is invalid as parsed by v4', () => {
should.Throw(() => new Address4(addressString));
});
}
if (descriptor === 'invalid-ipv6') {
it('is invalid as parsed by v6', () => {
should.Throw(() => new Address6(addressString));
});
}
if (descriptor === 'canonical') {
const address6 = new Address6(addressString);
it('is canonical', () => {
address6.isCanonical().should.equal(true);
should.equal(address6.addressMinusSuffix.length, 39);
});
}
if (descriptor === 'correct') {
const address6 = new Address6(addressString);
it('is correct', () => {
address6.isCorrect().should.equal(true);
});
}
if (descriptor === 'correct-ipv4') {
const address4 = new Address4(addressString);
it('is correct', () => {
address4.isCorrect().should.equal(true);
});
}
if (descriptor === 'incorrect') {
const address6 = new Address6(addressString);
it('is incorrect', () => {
address6.isCorrect().should.equal(false);
});
}
if (descriptor === 'incorrect-ipv4') {
const address4 = new Address4(addressString);
it('is incorrect', () => {
address4.isCorrect().should.equal(false);
});
}
if (descriptor === 'has-subnet') {
const address6 = new Address6(addressString);
it('parses the subnet', () => {
address6.subnet.should.match(/^\/\d{1,3}/);
});
}
if (descriptor === 'v4-in-v6') {
const address6 = new Address6(addressString);
it('is an ipv4-in-ipv6 address', () => {
address6.is4().should.equal(true);
});
}
});
});
}
interface AddressEntry {
address: string;
conditions?: string[];
}
function loadJsonBatch(addresses: AddressEntry[], classes: string[], noMerge?: boolean) {
addresses.forEach((address) => {
if (address.conditions === undefined || !address.conditions.length || noMerge) {
address.conditions = classes;
} else {
address.conditions = address.conditions.concat(classes);
}
addressIs(address.address, address.conditions);
});
}
describe('Valid IPv4 addresses', () => {
loadJsonBatch(valid4, ['valid-ipv4']);
loadJsonBatch(valid4, ['invalid-ipv6'], true);
});
describe('Valid IPv6 addresses', () => {
loadJsonBatch(valid6, ['valid-ipv6']);
loadJsonBatch(valid6, ['invalid-ipv4'], true);
});
describe('Invalid IPv4 addresses', () => {
loadJsonBatch(invalid4, ['invalid-ipv4']);
});
describe('Invalid IPv6 addresses', () => {
loadJsonBatch(invalid6, ['invalid-ipv6']);
});
// Test corpus from richb-intermapper/IPv6-Regex (Dartware/Intermapper, ~2010).
// Three cases were reclassified to match ip-address's actual behavior:
// leading/trailing whitespace addresses are rejected (intermapper's regex
// trims), and `2001:db8::%1` is accepted because we support zone IDs.
describe('Intermapper IPv6 corpus — valid', () => {
loadJsonBatch(intermapperValid6, ['valid-ipv6']);
});
describe('Intermapper IPv6 corpus — invalid', () => {
loadJsonBatch(intermapperInvalid6, ['invalid-ipv6']);
});
beaugunderson-ip-address-438375e/test/common-test.ts 0000664 0000000 0000000 00000003700 15272410673 0022473 0 ustar 00root root 0000000 0000000 import * as chai from 'chai';
import { testBit } from '../src/common';
// eslint-disable-next-line import/extensions
import pkg from '../package.json';
const should = chai.should();
describe('the byte array API', () => {
it('keeps its signed and unsigned split only until 11.0.0', () => {
// Address6.fromByteArray accepts signed bytes and folds them to unsigned,
// Address4.fromByteArray rejects them, and toUnsignedByteArray returns what
// toByteArray already returns. A major version is where those differences
// can be settled, so this fails there rather than relying on anyone
// remembering to look.
const major = Number(pkg.version.split('.')[0]);
major.should.be.below(
11,
'ip-address is at 11.x, so collapse the byte array API: make Address6.fromByteArray ' +
'reject anything outside 0-255 as Address4.fromByteArray does, delete unsignByte and ' +
'the -128 floor from src/ipv6.ts, and reduce fromUnsignedByteArray and ' +
'toUnsignedByteArray to deprecated aliases. Then delete this test.',
);
});
});
describe('the deprecated RE_ZONE_STRING export', () => {
it('lasts only until 11.0.0', () => {
const major = Number(pkg.version.split('.')[0]);
major.should.be.below(
11,
'ip-address is at 11.x, so delete RE_ZONE_STRING from src/v6/constants.ts: nothing in ' +
'the library uses it and it takes quadratic time on hostile input. Then delete this test.',
);
});
});
describe('testBit', () => {
it('should return value per specific bit', () => {
should.equal(testBit('0', 0), false);
should.equal(testBit('1', 0), true);
should.equal(testBit('1010', 0), false);
should.equal(testBit('1010', 1), true);
should.equal(testBit('1010', 2), false);
should.equal(testBit('1010', 3), true);
should.equal(testBit('1010', 4), false);
// Length bigger than the size of string
should.equal(testBit('1010', 5), false);
});
});
beaugunderson-ip-address-438375e/test/data/ 0000775 0000000 0000000 00000000000 15272410673 0020567 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-438375e/test/data/iana-corpus.json 0000664 0000000 0000000 00000611306 15272410673 0023712 0 ustar 00root root 0000000 0000000 [
{
"address": "0.0.0.0",
"family": 4,
"block": "\"This host on this network\"",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": true,
"global": false
}
},
{
"address": "0.0.0.1",
"family": 4,
"block": "\"This network\"",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "0.127.255.255",
"family": 4,
"block": "\"This network\"",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "0.255.255.254",
"family": 4,
"block": "\"This network\"",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "0.255.255.255",
"family": 4,
"block": "\"This network\"",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "1.0.0.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "0.0.0.0",
"family": 4,
"block": "\"This host on this network\"",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": true,
"global": false
}
},
{
"address": "0.0.0.1",
"family": 4,
"block": "\"This network\"",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "9.255.255.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "10.0.0.0",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "10.0.0.1",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "10.127.255.255",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "10.255.255.254",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "10.255.255.255",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "11.0.0.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "100.63.255.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "100.64.0.0",
"family": 4,
"block": "Shared Address Space",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "100.64.0.1",
"family": 4,
"block": "Shared Address Space",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "100.95.255.255",
"family": 4,
"block": "Shared Address Space",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "100.127.255.254",
"family": 4,
"block": "Shared Address Space",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "100.127.255.255",
"family": 4,
"block": "Shared Address Space",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "100.128.0.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "126.255.255.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "127.0.0.0",
"family": 4,
"block": "Loopback",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "127.0.0.1",
"family": 4,
"block": "Loopback",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "127.127.255.255",
"family": 4,
"block": "Loopback",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "127.255.255.254",
"family": 4,
"block": "Loopback",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "127.255.255.255",
"family": 4,
"block": "Loopback",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "128.0.0.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "169.253.255.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "169.254.0.0",
"family": 4,
"block": "Link Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "169.254.0.1",
"family": 4,
"block": "Link Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "169.254.127.255",
"family": 4,
"block": "Link Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "169.254.255.254",
"family": 4,
"block": "Link Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "169.254.255.255",
"family": 4,
"block": "Link Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "169.255.0.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "172.15.255.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "172.16.0.0",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "172.16.0.1",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "172.23.255.255",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "172.31.255.254",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "172.31.255.255",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "172.32.0.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "191.255.255.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.0.0.0",
"family": 4,
"block": "IPv4 Service Continuity Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.1",
"family": 4,
"block": "IPv4 Service Continuity Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.127",
"family": 4,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.254",
"family": 4,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.255",
"family": 4,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.1.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "191.255.255.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.0.0.0",
"family": 4,
"block": "IPv4 Service Continuity Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.1",
"family": 4,
"block": "IPv4 Service Continuity Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.3",
"family": 4,
"block": "IPv4 Service Continuity Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.6",
"family": 4,
"block": "IPv4 Service Continuity Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.7",
"family": 4,
"block": "IPv4 Service Continuity Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.8",
"family": 4,
"block": "IPv4 dummy address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.7",
"family": 4,
"block": "IPv4 Service Continuity Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.8",
"family": 4,
"block": "IPv4 dummy address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.9",
"family": 4,
"block": "Port Control Protocol Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.0.0.8",
"family": 4,
"block": "IPv4 dummy address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.9",
"family": 4,
"block": "Port Control Protocol Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.0.0.10",
"family": 4,
"block": "Traversal Using Relays around NAT Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.0.0.9",
"family": 4,
"block": "Port Control Protocol Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.0.0.10",
"family": 4,
"block": "Traversal Using Relays around NAT Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.0.0.11",
"family": 4,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.169",
"family": 4,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.170",
"family": 4,
"block": "NAT64/DNS64 Discovery",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.171",
"family": 4,
"block": "NAT64/DNS64 Discovery",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.170",
"family": 4,
"block": "NAT64/DNS64 Discovery",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.171",
"family": 4,
"block": "NAT64/DNS64 Discovery",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.0.172",
"family": 4,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.1.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.0.2.0",
"family": 4,
"block": "Documentation (TEST-NET-1)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.2.1",
"family": 4,
"block": "Documentation (TEST-NET-1)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.2.127",
"family": 4,
"block": "Documentation (TEST-NET-1)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.2.254",
"family": 4,
"block": "Documentation (TEST-NET-1)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.2.255",
"family": 4,
"block": "Documentation (TEST-NET-1)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.0.3.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.31.195.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.31.196.0",
"family": 4,
"block": "AS112-v4",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.31.196.1",
"family": 4,
"block": "AS112-v4",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.31.196.127",
"family": 4,
"block": "AS112-v4",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.31.196.254",
"family": 4,
"block": "AS112-v4",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.31.196.255",
"family": 4,
"block": "AS112-v4",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.31.197.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.52.192.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.52.193.0",
"family": 4,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.52.193.1",
"family": 4,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.52.193.127",
"family": 4,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.52.193.254",
"family": 4,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.52.193.255",
"family": 4,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.52.194.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.98.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.99.0",
"family": 4,
"block": "Deprecated (6to4 Relay Anycast)",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.99.1",
"family": 4,
"block": "Deprecated (6to4 Relay Anycast)",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.99.127",
"family": 4,
"block": "Deprecated (6to4 Relay Anycast)",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.99.254",
"family": 4,
"block": "Deprecated (6to4 Relay Anycast)",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.99.255",
"family": 4,
"block": "Deprecated (6to4 Relay Anycast)",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.100.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.99.1",
"family": 4,
"block": "Deprecated (6to4 Relay Anycast)",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.99.2",
"family": 4,
"block": "6a44-relay anycast address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.88.99.3",
"family": 4,
"block": "Deprecated (6to4 Relay Anycast)",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.167.255.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.168.0.0",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.168.0.1",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.168.127.255",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.168.255.254",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.168.255.255",
"family": 4,
"block": "Private-Use",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "192.169.0.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.175.47.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.175.48.0",
"family": 4,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.175.48.1",
"family": 4,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.175.48.127",
"family": 4,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.175.48.254",
"family": 4,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.175.48.255",
"family": 4,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "192.175.49.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "198.17.255.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "198.18.0.0",
"family": 4,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.18.0.1",
"family": 4,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.18.255.255",
"family": 4,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.19.255.254",
"family": 4,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.19.255.255",
"family": 4,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.20.0.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "198.51.99.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "198.51.100.0",
"family": 4,
"block": "Documentation (TEST-NET-2)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.51.100.1",
"family": 4,
"block": "Documentation (TEST-NET-2)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.51.100.127",
"family": 4,
"block": "Documentation (TEST-NET-2)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.51.100.254",
"family": 4,
"block": "Documentation (TEST-NET-2)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.51.100.255",
"family": 4,
"block": "Documentation (TEST-NET-2)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "198.51.101.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "203.0.112.255",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "203.0.113.0",
"family": 4,
"block": "Documentation (TEST-NET-3)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "203.0.113.1",
"family": 4,
"block": "Documentation (TEST-NET-3)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "203.0.113.127",
"family": 4,
"block": "Documentation (TEST-NET-3)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "203.0.113.254",
"family": 4,
"block": "Documentation (TEST-NET-3)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "203.0.113.255",
"family": 4,
"block": "Documentation (TEST-NET-3)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "203.0.114.0",
"family": 4,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "239.255.255.255",
"family": 4,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": true,
"unspecified": false,
"global": true
}
},
{
"address": "240.0.0.0",
"family": 4,
"block": "Reserved",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "240.0.0.1",
"family": 4,
"block": "Reserved",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "247.255.255.255",
"family": 4,
"block": "Reserved",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "255.255.255.254",
"family": 4,
"block": "Reserved",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "255.255.255.255",
"family": 4,
"block": "Limited Broadcast",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "255.255.255.254",
"family": 4,
"block": "Reserved",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "255.255.255.255",
"family": 4,
"block": "Limited Broadcast",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "::",
"family": 6,
"block": "Unspecified Address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": true,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "::1",
"family": 6,
"block": "Loopback Address",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "::2",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "::",
"family": 6,
"block": "Unspecified Address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": true,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "::1",
"family": 6,
"block": "Loopback Address",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "::fffe:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "::ffff:0.0.0.0",
"family": 6,
"block": "IPv4-mapped Address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": true,
"global": false
},
"allocation": "Reserved by IETF",
"embedded": "0.0.0.0"
},
{
"address": "::ffff:0.0.0.1",
"family": 6,
"block": "IPv4-mapped Address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF",
"embedded": "0.0.0.1"
},
{
"address": "::ffff:127.255.255.255",
"family": 6,
"block": "IPv4-mapped Address",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF",
"embedded": "127.255.255.255"
},
{
"address": "::ffff:255.255.255.254",
"family": 6,
"block": "IPv4-mapped Address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF",
"embedded": "255.255.255.254"
},
{
"address": "::ffff:255.255.255.255",
"family": 6,
"block": "IPv4-mapped Address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF",
"embedded": "255.255.255.255"
},
{
"address": "::1:0:0:0",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "64:ff9a:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "64:ff9b::",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF",
"embedded": "0.0.0.0"
},
{
"address": "64:ff9b::1",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF",
"embedded": "0.0.0.1"
},
{
"address": "64:ff9b::7fff:ffff",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF",
"embedded": "127.255.255.255"
},
{
"address": "64:ff9b::ffff:fffe",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF",
"embedded": "255.255.255.254"
},
{
"address": "64:ff9b::ffff:ffff",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF",
"embedded": "255.255.255.255"
},
{
"address": "64:ff9b::1:0:0",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "64:ff9b:0:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "64:ff9b:1::",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "64:ff9b:1::1",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "64:ff9b:1:7fff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "64:ff9b:1:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "64:ff9b:1:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "IPv4-IPv6 Translat.",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "64:ff9b:2::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "100::",
"family": 6,
"block": "Discard-Only Address Block",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "100::1",
"family": 6,
"block": "Discard-Only Address Block",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "100::7fff:ffff:ffff:ffff",
"family": 6,
"block": "Discard-Only Address Block",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "100::ffff:ffff:ffff:fffe",
"family": 6,
"block": "Discard-Only Address Block",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "100::ffff:ffff:ffff:ffff",
"family": 6,
"block": "Discard-Only Address Block",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "100:0:0:1::",
"family": 6,
"block": "Dummy IPv6 Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "100::ffff:ffff:ffff:ffff",
"family": 6,
"block": "Discard-Only Address Block",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "100:0:0:1::",
"family": 6,
"block": "Dummy IPv6 Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "100:0:0:1::1",
"family": 6,
"block": "Dummy IPv6 Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "100::1:7fff:ffff:ffff:ffff",
"family": 6,
"block": "Dummy IPv6 Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "100::1:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Dummy IPv6 Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "100::1:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Dummy IPv6 Prefix",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "100:0:0:2::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001::",
"family": 6,
"block": "TEREDO",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001::1",
"family": 6,
"block": "TEREDO",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:ff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1ff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:200::",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001::",
"family": 6,
"block": "TEREDO",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001::1",
"family": 6,
"block": "TEREDO",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:0:7fff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "TEREDO",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:0:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "TEREDO",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:0:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "TEREDO",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::1",
"family": 6,
"block": "Port Control Protocol Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::2",
"family": 6,
"block": "Traversal Using Relays around NAT Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::1",
"family": 6,
"block": "Port Control Protocol Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::2",
"family": 6,
"block": "Traversal Using Relays around NAT Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::3",
"family": 6,
"block": "DNS-SD Service Registration Protocol Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::2",
"family": 6,
"block": "Traversal Using Relays around NAT Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::3",
"family": 6,
"block": "DNS-SD Service Registration Protocol Anycast",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1::4",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:2::",
"family": 6,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:2::1",
"family": 6,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:2:0:7fff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:2:0:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:2:0:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Benchmarking",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:2:1::",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:2:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:3::",
"family": 6,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:3::1",
"family": 6,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:3:7fff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:3:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:3:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "AMT",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:4::",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:4:111:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:4:112::",
"family": 6,
"block": "AS112-v6",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:4:112::1",
"family": 6,
"block": "AS112-v6",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:4:112:7fff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "AS112-v6",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:4:112:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "AS112-v6",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:4:112:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "AS112-v6",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:4:113::",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:f:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:10::",
"family": 6,
"block": "Deprecated (previously ORCHID)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:10::1",
"family": 6,
"block": "Deprecated (previously ORCHID)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:17:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Deprecated (previously ORCHID)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1f:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Deprecated (previously ORCHID)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:1f:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Deprecated (previously ORCHID)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:20::",
"family": 6,
"block": "ORCHIDv2",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:1f:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Deprecated (previously ORCHID)",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:20::",
"family": 6,
"block": "ORCHIDv2",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:20::1",
"family": 6,
"block": "ORCHIDv2",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:27:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "ORCHIDv2",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:2f:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "ORCHIDv2",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:2f:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "ORCHIDv2",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:30::",
"family": 6,
"block": "Drone Remote ID Protocol Entity Tags (DETs) Prefix",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:2f:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "ORCHIDv2",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:30::",
"family": 6,
"block": "Drone Remote ID Protocol Entity Tags (DETs) Prefix",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:30::1",
"family": 6,
"block": "Drone Remote ID Protocol Entity Tags (DETs) Prefix",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:37:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Drone Remote ID Protocol Entity Tags (DETs) Prefix",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:3f:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Drone Remote ID Protocol Entity Tags (DETs) Prefix",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:3f:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Drone Remote ID Protocol Entity Tags (DETs) Prefix",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:40::",
"family": 6,
"block": "IETF Protocol Assignments",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:db7:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:db8::",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:db8::1",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:db8:7fff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:db8:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2001:db9::",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2002::",
"family": 6,
"block": "6to4",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2002::1",
"family": 6,
"block": "6to4",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2002:7fff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "6to4",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2002:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "6to4",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "6to4",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "2003::",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2620:4f:7fff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2620:4f:8000::",
"family": 6,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2620:4f:8000::1",
"family": 6,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2620:4f:8000:7fff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2620:4f:8000:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2620:4f:8000:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Direct Delegation AS112 Service",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2620:4f:8001::",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "3ffe:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "3fff::",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "3fff::1",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "3fff:7ff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "3fff:fff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Documentation",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Global Unicast"
},
{
"address": "3fff:1000::",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "5eff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5f00::",
"family": 6,
"block": "Segment Routing (SRv6) SIDs",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5f00::1",
"family": 6,
"block": "Segment Routing (SRv6) SIDs",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5f00:7fff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Segment Routing (SRv6) SIDs",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5f00:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Segment Routing (SRv6) SIDs",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5f00:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Segment Routing (SRv6) SIDs",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5f01::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fc00::",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fc00::1",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fcff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fdff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fe00::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fe80::",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "fe80::1",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "fe9f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "febf:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "fec0::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "::",
"family": 6,
"block": "Unspecified Address",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": true,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "::1",
"family": 6,
"block": "Loopback Address",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "ff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "100::",
"family": 6,
"block": "Discard-Only Address Block",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "100::",
"family": 6,
"block": "Discard-Only Address Block",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "100::1",
"family": 6,
"block": "Discard-Only Address Block",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Reserved by IETF"
},
{
"address": "17f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "1ff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "1ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "200::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "1ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "200::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "200::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "2ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "3ff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "3ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "400::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "3ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "400::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "400::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "7ff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "800::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "800::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "800::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "bff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "1000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "1000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "1000::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "17ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "1fff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "1fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "2000::",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "1fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "2000::",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2000::1",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "2fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "3fff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "4000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Global Unicast"
},
{
"address": "4000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "4000::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "4fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5fff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "6000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "5fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "6000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "6000::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "6fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "7fff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "8000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "8000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "8000::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "8fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "9fff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "9fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "a000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "9fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "a000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "a000::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "afff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "bfff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "bfff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "c000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "bfff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "c000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "c000::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "cfff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "dfff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "dfff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "e000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "dfff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "e000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "e000::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "e7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "efff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "efff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "efff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f000::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f000::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f3ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f7ff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f800::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f800::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f800::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "f9ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fbff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fc00::",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fc00::",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fc00::1",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fcff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fdff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fe00::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Unique-Local",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Unique Local Unicast"
},
{
"address": "fe00::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fe00::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fe3f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fe7f:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fe80::",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fe80::",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "fe80::1",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "fe9f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "febf:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "fec0::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": "Link-Local Unicast",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
},
"allocation": "Link-Scoped Unicast"
},
{
"address": "fec0::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fec0::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "fedf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "feff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "ff00::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": true,
"unspecified": false,
"global": true
},
"allocation": "Multicast"
},
{
"address": "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
},
"allocation": "Reserved by IETF"
},
{
"address": "ff00::",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": true,
"unspecified": false,
"global": true
},
"allocation": "Multicast"
},
{
"address": "ff00::1",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": true,
"unspecified": false,
"global": true
},
"allocation": "Multicast"
},
{
"address": "ff7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": true,
"unspecified": false,
"global": true
},
"allocation": "Multicast"
},
{
"address": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": true,
"unspecified": false,
"global": true
},
"allocation": "Multicast"
},
{
"address": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"family": 6,
"block": null,
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": true,
"unspecified": false,
"global": true
},
"allocation": "Multicast"
},
{
"address": "::ffff:0.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 0.0.0.0 (\"This host on this network\")",
"embedded": "0.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": true,
"global": false
}
},
{
"address": "64:ff9b::",
"family": 6,
"block": "NAT64 well-known form of 0.0.0.0 (\"This host on this network\")",
"embedded": "0.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:0.0.0.1",
"family": 6,
"block": "IPv4-mapped form of 0.0.0.1 (\"This network\")",
"embedded": "0.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::1",
"family": 6,
"block": "NAT64 well-known form of 0.0.0.1 (\"This network\")",
"embedded": "0.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:0.127.255.255",
"family": 6,
"block": "IPv4-mapped form of 0.127.255.255 (\"This network\")",
"embedded": "0.127.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::7f:ffff",
"family": 6,
"block": "NAT64 well-known form of 0.127.255.255 (\"This network\")",
"embedded": "0.127.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:0.255.255.254",
"family": 6,
"block": "IPv4-mapped form of 0.255.255.254 (\"This network\")",
"embedded": "0.255.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ff:fffe",
"family": 6,
"block": "NAT64 well-known form of 0.255.255.254 (\"This network\")",
"embedded": "0.255.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:0.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 0.255.255.255 (\"This network\")",
"embedded": "0.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ff:ffff",
"family": 6,
"block": "NAT64 well-known form of 0.255.255.255 (\"This network\")",
"embedded": "0.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:1.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 1.0.0.0 (None)",
"embedded": "1.0.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::100:0",
"family": 6,
"block": "NAT64 well-known form of 1.0.0.0 (None)",
"embedded": "1.0.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:0.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 0.0.0.0 (\"This host on this network\")",
"embedded": "0.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": true,
"global": false
}
},
{
"address": "64:ff9b::",
"family": 6,
"block": "NAT64 well-known form of 0.0.0.0 (\"This host on this network\")",
"embedded": "0.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:0.0.0.1",
"family": 6,
"block": "IPv4-mapped form of 0.0.0.1 (\"This network\")",
"embedded": "0.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::1",
"family": 6,
"block": "NAT64 well-known form of 0.0.0.1 (\"This network\")",
"embedded": "0.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:9.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 9.255.255.255 (None)",
"embedded": "9.255.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::9ff:ffff",
"family": 6,
"block": "NAT64 well-known form of 9.255.255.255 (None)",
"embedded": "9.255.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:10.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 10.0.0.0 (Private-Use)",
"embedded": "10.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::a00:0",
"family": 6,
"block": "NAT64 well-known form of 10.0.0.0 (Private-Use)",
"embedded": "10.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:10.0.0.1",
"family": 6,
"block": "IPv4-mapped form of 10.0.0.1 (Private-Use)",
"embedded": "10.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::a00:1",
"family": 6,
"block": "NAT64 well-known form of 10.0.0.1 (Private-Use)",
"embedded": "10.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:10.127.255.255",
"family": 6,
"block": "IPv4-mapped form of 10.127.255.255 (Private-Use)",
"embedded": "10.127.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::a7f:ffff",
"family": 6,
"block": "NAT64 well-known form of 10.127.255.255 (Private-Use)",
"embedded": "10.127.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:10.255.255.254",
"family": 6,
"block": "IPv4-mapped form of 10.255.255.254 (Private-Use)",
"embedded": "10.255.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::aff:fffe",
"family": 6,
"block": "NAT64 well-known form of 10.255.255.254 (Private-Use)",
"embedded": "10.255.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:10.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 10.255.255.255 (Private-Use)",
"embedded": "10.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::aff:ffff",
"family": 6,
"block": "NAT64 well-known form of 10.255.255.255 (Private-Use)",
"embedded": "10.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:11.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 11.0.0.0 (None)",
"embedded": "11.0.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::b00:0",
"family": 6,
"block": "NAT64 well-known form of 11.0.0.0 (None)",
"embedded": "11.0.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:100.63.255.255",
"family": 6,
"block": "IPv4-mapped form of 100.63.255.255 (None)",
"embedded": "100.63.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::643f:ffff",
"family": 6,
"block": "NAT64 well-known form of 100.63.255.255 (None)",
"embedded": "100.63.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:100.64.0.0",
"family": 6,
"block": "IPv4-mapped form of 100.64.0.0 (Shared Address Space)",
"embedded": "100.64.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::6440:0",
"family": 6,
"block": "NAT64 well-known form of 100.64.0.0 (Shared Address Space)",
"embedded": "100.64.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:100.64.0.1",
"family": 6,
"block": "IPv4-mapped form of 100.64.0.1 (Shared Address Space)",
"embedded": "100.64.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::6440:1",
"family": 6,
"block": "NAT64 well-known form of 100.64.0.1 (Shared Address Space)",
"embedded": "100.64.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:100.95.255.255",
"family": 6,
"block": "IPv4-mapped form of 100.95.255.255 (Shared Address Space)",
"embedded": "100.95.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::645f:ffff",
"family": 6,
"block": "NAT64 well-known form of 100.95.255.255 (Shared Address Space)",
"embedded": "100.95.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:100.127.255.254",
"family": 6,
"block": "IPv4-mapped form of 100.127.255.254 (Shared Address Space)",
"embedded": "100.127.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::647f:fffe",
"family": 6,
"block": "NAT64 well-known form of 100.127.255.254 (Shared Address Space)",
"embedded": "100.127.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:100.127.255.255",
"family": 6,
"block": "IPv4-mapped form of 100.127.255.255 (Shared Address Space)",
"embedded": "100.127.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::647f:ffff",
"family": 6,
"block": "NAT64 well-known form of 100.127.255.255 (Shared Address Space)",
"embedded": "100.127.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:100.128.0.0",
"family": 6,
"block": "IPv4-mapped form of 100.128.0.0 (None)",
"embedded": "100.128.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::6480:0",
"family": 6,
"block": "NAT64 well-known form of 100.128.0.0 (None)",
"embedded": "100.128.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:126.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 126.255.255.255 (None)",
"embedded": "126.255.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::7eff:ffff",
"family": 6,
"block": "NAT64 well-known form of 126.255.255.255 (None)",
"embedded": "126.255.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:127.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 127.0.0.0 (Loopback)",
"embedded": "127.0.0.0",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::7f00:0",
"family": 6,
"block": "NAT64 well-known form of 127.0.0.0 (Loopback)",
"embedded": "127.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:127.0.0.1",
"family": 6,
"block": "IPv4-mapped form of 127.0.0.1 (Loopback)",
"embedded": "127.0.0.1",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::7f00:1",
"family": 6,
"block": "NAT64 well-known form of 127.0.0.1 (Loopback)",
"embedded": "127.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:127.127.255.255",
"family": 6,
"block": "IPv4-mapped form of 127.127.255.255 (Loopback)",
"embedded": "127.127.255.255",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::7f7f:ffff",
"family": 6,
"block": "NAT64 well-known form of 127.127.255.255 (Loopback)",
"embedded": "127.127.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:127.255.255.254",
"family": 6,
"block": "IPv4-mapped form of 127.255.255.254 (Loopback)",
"embedded": "127.255.255.254",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::7fff:fffe",
"family": 6,
"block": "NAT64 well-known form of 127.255.255.254 (Loopback)",
"embedded": "127.255.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:127.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 127.255.255.255 (Loopback)",
"embedded": "127.255.255.255",
"global": false,
"python": {
"loopback": true,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::7fff:ffff",
"family": 6,
"block": "NAT64 well-known form of 127.255.255.255 (Loopback)",
"embedded": "127.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:128.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 128.0.0.0 (None)",
"embedded": "128.0.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::8000:0",
"family": 6,
"block": "NAT64 well-known form of 128.0.0.0 (None)",
"embedded": "128.0.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:169.253.255.255",
"family": 6,
"block": "IPv4-mapped form of 169.253.255.255 (None)",
"embedded": "169.253.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::a9fd:ffff",
"family": 6,
"block": "NAT64 well-known form of 169.253.255.255 (None)",
"embedded": "169.253.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:169.254.0.0",
"family": 6,
"block": "IPv4-mapped form of 169.254.0.0 (Link Local)",
"embedded": "169.254.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::a9fe:0",
"family": 6,
"block": "NAT64 well-known form of 169.254.0.0 (Link Local)",
"embedded": "169.254.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:169.254.0.1",
"family": 6,
"block": "IPv4-mapped form of 169.254.0.1 (Link Local)",
"embedded": "169.254.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::a9fe:1",
"family": 6,
"block": "NAT64 well-known form of 169.254.0.1 (Link Local)",
"embedded": "169.254.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:169.254.127.255",
"family": 6,
"block": "IPv4-mapped form of 169.254.127.255 (Link Local)",
"embedded": "169.254.127.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::a9fe:7fff",
"family": 6,
"block": "NAT64 well-known form of 169.254.127.255 (Link Local)",
"embedded": "169.254.127.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:169.254.255.254",
"family": 6,
"block": "IPv4-mapped form of 169.254.255.254 (Link Local)",
"embedded": "169.254.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::a9fe:fffe",
"family": 6,
"block": "NAT64 well-known form of 169.254.255.254 (Link Local)",
"embedded": "169.254.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:169.254.255.255",
"family": 6,
"block": "IPv4-mapped form of 169.254.255.255 (Link Local)",
"embedded": "169.254.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": true,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::a9fe:ffff",
"family": 6,
"block": "NAT64 well-known form of 169.254.255.255 (Link Local)",
"embedded": "169.254.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:169.255.0.0",
"family": 6,
"block": "IPv4-mapped form of 169.255.0.0 (None)",
"embedded": "169.255.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::a9ff:0",
"family": 6,
"block": "NAT64 well-known form of 169.255.0.0 (None)",
"embedded": "169.255.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:172.15.255.255",
"family": 6,
"block": "IPv4-mapped form of 172.15.255.255 (None)",
"embedded": "172.15.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::ac0f:ffff",
"family": 6,
"block": "NAT64 well-known form of 172.15.255.255 (None)",
"embedded": "172.15.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:172.16.0.0",
"family": 6,
"block": "IPv4-mapped form of 172.16.0.0 (Private-Use)",
"embedded": "172.16.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ac10:0",
"family": 6,
"block": "NAT64 well-known form of 172.16.0.0 (Private-Use)",
"embedded": "172.16.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:172.16.0.1",
"family": 6,
"block": "IPv4-mapped form of 172.16.0.1 (Private-Use)",
"embedded": "172.16.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ac10:1",
"family": 6,
"block": "NAT64 well-known form of 172.16.0.1 (Private-Use)",
"embedded": "172.16.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:172.23.255.255",
"family": 6,
"block": "IPv4-mapped form of 172.23.255.255 (Private-Use)",
"embedded": "172.23.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ac17:ffff",
"family": 6,
"block": "NAT64 well-known form of 172.23.255.255 (Private-Use)",
"embedded": "172.23.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:172.31.255.254",
"family": 6,
"block": "IPv4-mapped form of 172.31.255.254 (Private-Use)",
"embedded": "172.31.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ac1f:fffe",
"family": 6,
"block": "NAT64 well-known form of 172.31.255.254 (Private-Use)",
"embedded": "172.31.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:172.31.255.255",
"family": 6,
"block": "IPv4-mapped form of 172.31.255.255 (Private-Use)",
"embedded": "172.31.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ac1f:ffff",
"family": 6,
"block": "NAT64 well-known form of 172.31.255.255 (Private-Use)",
"embedded": "172.31.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:172.32.0.0",
"family": 6,
"block": "IPv4-mapped form of 172.32.0.0 (None)",
"embedded": "172.32.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::ac20:0",
"family": 6,
"block": "NAT64 well-known form of 172.32.0.0 (None)",
"embedded": "172.32.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:191.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 191.255.255.255 (None)",
"embedded": "191.255.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::bfff:ffff",
"family": 6,
"block": "NAT64 well-known form of 191.255.255.255 (None)",
"embedded": "191.255.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.0 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:0",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.0 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.1",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.1 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:1",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.1 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.127",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.127 (IETF Protocol Assignments)",
"embedded": "192.0.0.127",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:7f",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.127 (IETF Protocol Assignments)",
"embedded": "192.0.0.127",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.254",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.254 (IETF Protocol Assignments)",
"embedded": "192.0.0.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:fe",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.254 (IETF Protocol Assignments)",
"embedded": "192.0.0.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.255",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.255 (IETF Protocol Assignments)",
"embedded": "192.0.0.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:ff",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.255 (IETF Protocol Assignments)",
"embedded": "192.0.0.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.1.0",
"family": 6,
"block": "IPv4-mapped form of 192.0.1.0 (None)",
"embedded": "192.0.1.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c000:100",
"family": 6,
"block": "NAT64 well-known form of 192.0.1.0 (None)",
"embedded": "192.0.1.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:191.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 191.255.255.255 (None)",
"embedded": "191.255.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::bfff:ffff",
"family": 6,
"block": "NAT64 well-known form of 191.255.255.255 (None)",
"embedded": "191.255.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.0 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:0",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.0 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.1",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.1 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:1",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.1 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.3",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.3 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.3",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:3",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.3 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.3",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.6",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.6 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.6",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:6",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.6 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.6",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.7",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.7 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.7",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:7",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.7 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.7",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.8",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.8 (IPv4 dummy address)",
"embedded": "192.0.0.8",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:8",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.8 (IPv4 dummy address)",
"embedded": "192.0.0.8",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.7",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.7 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.7",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:7",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.7 (IPv4 Service Continuity Prefix)",
"embedded": "192.0.0.7",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.8",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.8 (IPv4 dummy address)",
"embedded": "192.0.0.8",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:8",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.8 (IPv4 dummy address)",
"embedded": "192.0.0.8",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.9",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.9 (Port Control Protocol Anycast)",
"embedded": "192.0.0.9",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c000:9",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.9 (Port Control Protocol Anycast)",
"embedded": "192.0.0.9",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.8",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.8 (IPv4 dummy address)",
"embedded": "192.0.0.8",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:8",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.8 (IPv4 dummy address)",
"embedded": "192.0.0.8",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.9",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.9 (Port Control Protocol Anycast)",
"embedded": "192.0.0.9",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c000:9",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.9 (Port Control Protocol Anycast)",
"embedded": "192.0.0.9",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.10",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.10 (Traversal Using Relays around NAT Anycast)",
"embedded": "192.0.0.10",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c000:a",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.10 (Traversal Using Relays around NAT Anycast)",
"embedded": "192.0.0.10",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.9",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.9 (Port Control Protocol Anycast)",
"embedded": "192.0.0.9",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c000:9",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.9 (Port Control Protocol Anycast)",
"embedded": "192.0.0.9",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.10",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.10 (Traversal Using Relays around NAT Anycast)",
"embedded": "192.0.0.10",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c000:a",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.10 (Traversal Using Relays around NAT Anycast)",
"embedded": "192.0.0.10",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.11",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.11 (IETF Protocol Assignments)",
"embedded": "192.0.0.11",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:b",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.11 (IETF Protocol Assignments)",
"embedded": "192.0.0.11",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.169",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.169 (IETF Protocol Assignments)",
"embedded": "192.0.0.169",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:a9",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.169 (IETF Protocol Assignments)",
"embedded": "192.0.0.169",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.170",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.170 (NAT64/DNS64 Discovery)",
"embedded": "192.0.0.170",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:aa",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.170 (NAT64/DNS64 Discovery)",
"embedded": "192.0.0.170",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.171",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.171 (NAT64/DNS64 Discovery)",
"embedded": "192.0.0.171",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:ab",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.171 (NAT64/DNS64 Discovery)",
"embedded": "192.0.0.171",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.170",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.170 (NAT64/DNS64 Discovery)",
"embedded": "192.0.0.170",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:aa",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.170 (NAT64/DNS64 Discovery)",
"embedded": "192.0.0.170",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.171",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.171 (NAT64/DNS64 Discovery)",
"embedded": "192.0.0.171",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:ab",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.171 (NAT64/DNS64 Discovery)",
"embedded": "192.0.0.171",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.0.172",
"family": 6,
"block": "IPv4-mapped form of 192.0.0.172 (IETF Protocol Assignments)",
"embedded": "192.0.0.172",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:ac",
"family": 6,
"block": "NAT64 well-known form of 192.0.0.172 (IETF Protocol Assignments)",
"embedded": "192.0.0.172",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.1.255",
"family": 6,
"block": "IPv4-mapped form of 192.0.1.255 (None)",
"embedded": "192.0.1.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c000:1ff",
"family": 6,
"block": "NAT64 well-known form of 192.0.1.255 (None)",
"embedded": "192.0.1.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.2.0",
"family": 6,
"block": "IPv4-mapped form of 192.0.2.0 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:200",
"family": 6,
"block": "NAT64 well-known form of 192.0.2.0 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.2.1",
"family": 6,
"block": "IPv4-mapped form of 192.0.2.1 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:201",
"family": 6,
"block": "NAT64 well-known form of 192.0.2.1 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.2.127",
"family": 6,
"block": "IPv4-mapped form of 192.0.2.127 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.127",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:27f",
"family": 6,
"block": "NAT64 well-known form of 192.0.2.127 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.127",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.2.254",
"family": 6,
"block": "IPv4-mapped form of 192.0.2.254 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:2fe",
"family": 6,
"block": "NAT64 well-known form of 192.0.2.254 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.2.255",
"family": 6,
"block": "IPv4-mapped form of 192.0.2.255 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c000:2ff",
"family": 6,
"block": "NAT64 well-known form of 192.0.2.255 (Documentation (TEST-NET-1))",
"embedded": "192.0.2.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.0.3.0",
"family": 6,
"block": "IPv4-mapped form of 192.0.3.0 (None)",
"embedded": "192.0.3.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c000:300",
"family": 6,
"block": "NAT64 well-known form of 192.0.3.0 (None)",
"embedded": "192.0.3.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.31.195.255",
"family": 6,
"block": "IPv4-mapped form of 192.31.195.255 (None)",
"embedded": "192.31.195.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c01f:c3ff",
"family": 6,
"block": "NAT64 well-known form of 192.31.195.255 (None)",
"embedded": "192.31.195.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.31.196.0",
"family": 6,
"block": "IPv4-mapped form of 192.31.196.0 (AS112-v4)",
"embedded": "192.31.196.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c01f:c400",
"family": 6,
"block": "NAT64 well-known form of 192.31.196.0 (AS112-v4)",
"embedded": "192.31.196.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.31.196.1",
"family": 6,
"block": "IPv4-mapped form of 192.31.196.1 (AS112-v4)",
"embedded": "192.31.196.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c01f:c401",
"family": 6,
"block": "NAT64 well-known form of 192.31.196.1 (AS112-v4)",
"embedded": "192.31.196.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.31.196.127",
"family": 6,
"block": "IPv4-mapped form of 192.31.196.127 (AS112-v4)",
"embedded": "192.31.196.127",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c01f:c47f",
"family": 6,
"block": "NAT64 well-known form of 192.31.196.127 (AS112-v4)",
"embedded": "192.31.196.127",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.31.196.254",
"family": 6,
"block": "IPv4-mapped form of 192.31.196.254 (AS112-v4)",
"embedded": "192.31.196.254",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c01f:c4fe",
"family": 6,
"block": "NAT64 well-known form of 192.31.196.254 (AS112-v4)",
"embedded": "192.31.196.254",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.31.196.255",
"family": 6,
"block": "IPv4-mapped form of 192.31.196.255 (AS112-v4)",
"embedded": "192.31.196.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c01f:c4ff",
"family": 6,
"block": "NAT64 well-known form of 192.31.196.255 (AS112-v4)",
"embedded": "192.31.196.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.31.197.0",
"family": 6,
"block": "IPv4-mapped form of 192.31.197.0 (None)",
"embedded": "192.31.197.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c01f:c500",
"family": 6,
"block": "NAT64 well-known form of 192.31.197.0 (None)",
"embedded": "192.31.197.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.52.192.255",
"family": 6,
"block": "IPv4-mapped form of 192.52.192.255 (None)",
"embedded": "192.52.192.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c034:c0ff",
"family": 6,
"block": "NAT64 well-known form of 192.52.192.255 (None)",
"embedded": "192.52.192.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.52.193.0",
"family": 6,
"block": "IPv4-mapped form of 192.52.193.0 (AMT)",
"embedded": "192.52.193.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c034:c100",
"family": 6,
"block": "NAT64 well-known form of 192.52.193.0 (AMT)",
"embedded": "192.52.193.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.52.193.1",
"family": 6,
"block": "IPv4-mapped form of 192.52.193.1 (AMT)",
"embedded": "192.52.193.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c034:c101",
"family": 6,
"block": "NAT64 well-known form of 192.52.193.1 (AMT)",
"embedded": "192.52.193.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.52.193.127",
"family": 6,
"block": "IPv4-mapped form of 192.52.193.127 (AMT)",
"embedded": "192.52.193.127",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c034:c17f",
"family": 6,
"block": "NAT64 well-known form of 192.52.193.127 (AMT)",
"embedded": "192.52.193.127",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.52.193.254",
"family": 6,
"block": "IPv4-mapped form of 192.52.193.254 (AMT)",
"embedded": "192.52.193.254",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c034:c1fe",
"family": 6,
"block": "NAT64 well-known form of 192.52.193.254 (AMT)",
"embedded": "192.52.193.254",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.52.193.255",
"family": 6,
"block": "IPv4-mapped form of 192.52.193.255 (AMT)",
"embedded": "192.52.193.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c034:c1ff",
"family": 6,
"block": "NAT64 well-known form of 192.52.193.255 (AMT)",
"embedded": "192.52.193.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.52.194.0",
"family": 6,
"block": "IPv4-mapped form of 192.52.194.0 (None)",
"embedded": "192.52.194.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c034:c200",
"family": 6,
"block": "NAT64 well-known form of 192.52.194.0 (None)",
"embedded": "192.52.194.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.98.255",
"family": 6,
"block": "IPv4-mapped form of 192.88.98.255 (None)",
"embedded": "192.88.98.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:62ff",
"family": 6,
"block": "NAT64 well-known form of 192.88.98.255 (None)",
"embedded": "192.88.98.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.99.0",
"family": 6,
"block": "IPv4-mapped form of 192.88.99.0 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:6300",
"family": 6,
"block": "NAT64 well-known form of 192.88.99.0 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.99.1",
"family": 6,
"block": "IPv4-mapped form of 192.88.99.1 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:6301",
"family": 6,
"block": "NAT64 well-known form of 192.88.99.1 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.99.127",
"family": 6,
"block": "IPv4-mapped form of 192.88.99.127 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.127",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:637f",
"family": 6,
"block": "NAT64 well-known form of 192.88.99.127 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.127",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.99.254",
"family": 6,
"block": "IPv4-mapped form of 192.88.99.254 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.254",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:63fe",
"family": 6,
"block": "NAT64 well-known form of 192.88.99.254 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.254",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.99.255",
"family": 6,
"block": "IPv4-mapped form of 192.88.99.255 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:63ff",
"family": 6,
"block": "NAT64 well-known form of 192.88.99.255 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.100.0",
"family": 6,
"block": "IPv4-mapped form of 192.88.100.0 (None)",
"embedded": "192.88.100.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:6400",
"family": 6,
"block": "NAT64 well-known form of 192.88.100.0 (None)",
"embedded": "192.88.100.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.99.1",
"family": 6,
"block": "IPv4-mapped form of 192.88.99.1 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:6301",
"family": 6,
"block": "NAT64 well-known form of 192.88.99.1 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.99.2",
"family": 6,
"block": "IPv4-mapped form of 192.88.99.2 (6a44-relay anycast address)",
"embedded": "192.88.99.2",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:6302",
"family": 6,
"block": "NAT64 well-known form of 192.88.99.2 (6a44-relay anycast address)",
"embedded": "192.88.99.2",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.88.99.3",
"family": 6,
"block": "IPv4-mapped form of 192.88.99.3 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.3",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c058:6303",
"family": 6,
"block": "NAT64 well-known form of 192.88.99.3 (Deprecated (6to4 Relay Anycast))",
"embedded": "192.88.99.3",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.167.255.255",
"family": 6,
"block": "IPv4-mapped form of 192.167.255.255 (None)",
"embedded": "192.167.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c0a7:ffff",
"family": 6,
"block": "NAT64 well-known form of 192.167.255.255 (None)",
"embedded": "192.167.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.168.0.0",
"family": 6,
"block": "IPv4-mapped form of 192.168.0.0 (Private-Use)",
"embedded": "192.168.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c0a8:0",
"family": 6,
"block": "NAT64 well-known form of 192.168.0.0 (Private-Use)",
"embedded": "192.168.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.168.0.1",
"family": 6,
"block": "IPv4-mapped form of 192.168.0.1 (Private-Use)",
"embedded": "192.168.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c0a8:1",
"family": 6,
"block": "NAT64 well-known form of 192.168.0.1 (Private-Use)",
"embedded": "192.168.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.168.127.255",
"family": 6,
"block": "IPv4-mapped form of 192.168.127.255 (Private-Use)",
"embedded": "192.168.127.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c0a8:7fff",
"family": 6,
"block": "NAT64 well-known form of 192.168.127.255 (Private-Use)",
"embedded": "192.168.127.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.168.255.254",
"family": 6,
"block": "IPv4-mapped form of 192.168.255.254 (Private-Use)",
"embedded": "192.168.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c0a8:fffe",
"family": 6,
"block": "NAT64 well-known form of 192.168.255.254 (Private-Use)",
"embedded": "192.168.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.168.255.255",
"family": 6,
"block": "IPv4-mapped form of 192.168.255.255 (Private-Use)",
"embedded": "192.168.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c0a8:ffff",
"family": 6,
"block": "NAT64 well-known form of 192.168.255.255 (Private-Use)",
"embedded": "192.168.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.169.0.0",
"family": 6,
"block": "IPv4-mapped form of 192.169.0.0 (None)",
"embedded": "192.169.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c0a9:0",
"family": 6,
"block": "NAT64 well-known form of 192.169.0.0 (None)",
"embedded": "192.169.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.175.47.255",
"family": 6,
"block": "IPv4-mapped form of 192.175.47.255 (None)",
"embedded": "192.175.47.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c0af:2fff",
"family": 6,
"block": "NAT64 well-known form of 192.175.47.255 (None)",
"embedded": "192.175.47.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.175.48.0",
"family": 6,
"block": "IPv4-mapped form of 192.175.48.0 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c0af:3000",
"family": 6,
"block": "NAT64 well-known form of 192.175.48.0 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.175.48.1",
"family": 6,
"block": "IPv4-mapped form of 192.175.48.1 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c0af:3001",
"family": 6,
"block": "NAT64 well-known form of 192.175.48.1 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.1",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.175.48.127",
"family": 6,
"block": "IPv4-mapped form of 192.175.48.127 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.127",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c0af:307f",
"family": 6,
"block": "NAT64 well-known form of 192.175.48.127 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.127",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.175.48.254",
"family": 6,
"block": "IPv4-mapped form of 192.175.48.254 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.254",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c0af:30fe",
"family": 6,
"block": "NAT64 well-known form of 192.175.48.254 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.254",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.175.48.255",
"family": 6,
"block": "IPv4-mapped form of 192.175.48.255 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c0af:30ff",
"family": 6,
"block": "NAT64 well-known form of 192.175.48.255 (Direct Delegation AS112 Service)",
"embedded": "192.175.48.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:192.175.49.0",
"family": 6,
"block": "IPv4-mapped form of 192.175.49.0 (None)",
"embedded": "192.175.49.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c0af:3100",
"family": 6,
"block": "NAT64 well-known form of 192.175.49.0 (None)",
"embedded": "192.175.49.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.17.255.255",
"family": 6,
"block": "IPv4-mapped form of 198.17.255.255 (None)",
"embedded": "198.17.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c611:ffff",
"family": 6,
"block": "NAT64 well-known form of 198.17.255.255 (None)",
"embedded": "198.17.255.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.18.0.0",
"family": 6,
"block": "IPv4-mapped form of 198.18.0.0 (Benchmarking)",
"embedded": "198.18.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c612:0",
"family": 6,
"block": "NAT64 well-known form of 198.18.0.0 (Benchmarking)",
"embedded": "198.18.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.18.0.1",
"family": 6,
"block": "IPv4-mapped form of 198.18.0.1 (Benchmarking)",
"embedded": "198.18.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c612:1",
"family": 6,
"block": "NAT64 well-known form of 198.18.0.1 (Benchmarking)",
"embedded": "198.18.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.18.255.255",
"family": 6,
"block": "IPv4-mapped form of 198.18.255.255 (Benchmarking)",
"embedded": "198.18.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c612:ffff",
"family": 6,
"block": "NAT64 well-known form of 198.18.255.255 (Benchmarking)",
"embedded": "198.18.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.19.255.254",
"family": 6,
"block": "IPv4-mapped form of 198.19.255.254 (Benchmarking)",
"embedded": "198.19.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c613:fffe",
"family": 6,
"block": "NAT64 well-known form of 198.19.255.254 (Benchmarking)",
"embedded": "198.19.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.19.255.255",
"family": 6,
"block": "IPv4-mapped form of 198.19.255.255 (Benchmarking)",
"embedded": "198.19.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c613:ffff",
"family": 6,
"block": "NAT64 well-known form of 198.19.255.255 (Benchmarking)",
"embedded": "198.19.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.20.0.0",
"family": 6,
"block": "IPv4-mapped form of 198.20.0.0 (None)",
"embedded": "198.20.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c614:0",
"family": 6,
"block": "NAT64 well-known form of 198.20.0.0 (None)",
"embedded": "198.20.0.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.51.99.255",
"family": 6,
"block": "IPv4-mapped form of 198.51.99.255 (None)",
"embedded": "198.51.99.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c633:63ff",
"family": 6,
"block": "NAT64 well-known form of 198.51.99.255 (None)",
"embedded": "198.51.99.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.51.100.0",
"family": 6,
"block": "IPv4-mapped form of 198.51.100.0 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c633:6400",
"family": 6,
"block": "NAT64 well-known form of 198.51.100.0 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.51.100.1",
"family": 6,
"block": "IPv4-mapped form of 198.51.100.1 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c633:6401",
"family": 6,
"block": "NAT64 well-known form of 198.51.100.1 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.51.100.127",
"family": 6,
"block": "IPv4-mapped form of 198.51.100.127 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.127",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c633:647f",
"family": 6,
"block": "NAT64 well-known form of 198.51.100.127 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.127",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.51.100.254",
"family": 6,
"block": "IPv4-mapped form of 198.51.100.254 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c633:64fe",
"family": 6,
"block": "NAT64 well-known form of 198.51.100.254 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.51.100.255",
"family": 6,
"block": "IPv4-mapped form of 198.51.100.255 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::c633:64ff",
"family": 6,
"block": "NAT64 well-known form of 198.51.100.255 (Documentation (TEST-NET-2))",
"embedded": "198.51.100.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:198.51.101.0",
"family": 6,
"block": "IPv4-mapped form of 198.51.101.0 (None)",
"embedded": "198.51.101.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::c633:6500",
"family": 6,
"block": "NAT64 well-known form of 198.51.101.0 (None)",
"embedded": "198.51.101.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:203.0.112.255",
"family": 6,
"block": "IPv4-mapped form of 203.0.112.255 (None)",
"embedded": "203.0.112.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::cb00:70ff",
"family": 6,
"block": "NAT64 well-known form of 203.0.112.255 (None)",
"embedded": "203.0.112.255",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:203.0.113.0",
"family": 6,
"block": "IPv4-mapped form of 203.0.113.0 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::cb00:7100",
"family": 6,
"block": "NAT64 well-known form of 203.0.113.0 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:203.0.113.1",
"family": 6,
"block": "IPv4-mapped form of 203.0.113.1 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::cb00:7101",
"family": 6,
"block": "NAT64 well-known form of 203.0.113.1 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:203.0.113.127",
"family": 6,
"block": "IPv4-mapped form of 203.0.113.127 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.127",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::cb00:717f",
"family": 6,
"block": "NAT64 well-known form of 203.0.113.127 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.127",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:203.0.113.254",
"family": 6,
"block": "IPv4-mapped form of 203.0.113.254 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::cb00:71fe",
"family": 6,
"block": "NAT64 well-known form of 203.0.113.254 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:203.0.113.255",
"family": 6,
"block": "IPv4-mapped form of 203.0.113.255 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::cb00:71ff",
"family": 6,
"block": "NAT64 well-known form of 203.0.113.255 (Documentation (TEST-NET-3))",
"embedded": "203.0.113.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:203.0.114.0",
"family": 6,
"block": "IPv4-mapped form of 203.0.114.0 (None)",
"embedded": "203.0.114.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::cb00:7200",
"family": 6,
"block": "NAT64 well-known form of 203.0.114.0 (None)",
"embedded": "203.0.114.0",
"global": true,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:239.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 239.255.255.255 (None)",
"embedded": "239.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": true,
"unspecified": false,
"global": true
}
},
{
"address": "64:ff9b::efff:ffff",
"family": 6,
"block": "NAT64 well-known form of 239.255.255.255 (None)",
"embedded": "239.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:240.0.0.0",
"family": 6,
"block": "IPv4-mapped form of 240.0.0.0 (Reserved)",
"embedded": "240.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::f000:0",
"family": 6,
"block": "NAT64 well-known form of 240.0.0.0 (Reserved)",
"embedded": "240.0.0.0",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:240.0.0.1",
"family": 6,
"block": "IPv4-mapped form of 240.0.0.1 (Reserved)",
"embedded": "240.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::f000:1",
"family": 6,
"block": "NAT64 well-known form of 240.0.0.1 (Reserved)",
"embedded": "240.0.0.1",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:247.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 247.255.255.255 (Reserved)",
"embedded": "247.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::f7ff:ffff",
"family": 6,
"block": "NAT64 well-known form of 247.255.255.255 (Reserved)",
"embedded": "247.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:255.255.255.254",
"family": 6,
"block": "IPv4-mapped form of 255.255.255.254 (Reserved)",
"embedded": "255.255.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ffff:fffe",
"family": 6,
"block": "NAT64 well-known form of 255.255.255.254 (Reserved)",
"embedded": "255.255.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:255.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 255.255.255.255 (Limited Broadcast)",
"embedded": "255.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ffff:ffff",
"family": 6,
"block": "NAT64 well-known form of 255.255.255.255 (Limited Broadcast)",
"embedded": "255.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:255.255.255.254",
"family": 6,
"block": "IPv4-mapped form of 255.255.255.254 (Reserved)",
"embedded": "255.255.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ffff:fffe",
"family": 6,
"block": "NAT64 well-known form of 255.255.255.254 (Reserved)",
"embedded": "255.255.255.254",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
},
{
"address": "::ffff:255.255.255.255",
"family": 6,
"block": "IPv4-mapped form of 255.255.255.255 (Limited Broadcast)",
"embedded": "255.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": false
}
},
{
"address": "64:ff9b::ffff:ffff",
"family": 6,
"block": "NAT64 well-known form of 255.255.255.255 (Limited Broadcast)",
"embedded": "255.255.255.255",
"global": false,
"python": {
"loopback": false,
"linkLocal": false,
"multicast": false,
"unspecified": false,
"global": true
}
}
]
beaugunderson-ip-address-438375e/test/data/iana-ipv4-special-registry.csv 0000664 0000000 0000000 00000004567 15272410673 0026374 0 ustar 00root root 0000000 0000000 Address Block,Name,RFC,Allocation Date,Termination Date,Source,Destination,Forwardable,Globally Reachable,Reserved-by-Protocol
0.0.0.0/8,"""This network""","[RFC791], Section 3.2",1981-09,N/A,True,False,False,False,True
0.0.0.0/32,"""This host on this network""","[RFC1122], Section 3.2.1.3",1981-09,N/A,True,False,False,False,True
10.0.0.0/8,Private-Use,[RFC1918],1996-02,N/A,True,True,True,False,False
100.64.0.0/10,Shared Address Space,[RFC6598],2012-04,N/A,True,True,True,False,False
127.0.0.0/8,Loopback,"[RFC1122], Section 3.2.1.3",1981-09,N/A,False [1],False [1],False [1],False [1],True
169.254.0.0/16,Link Local,[RFC3927],2005-05,N/A,True,True,False,False,True
172.16.0.0/12,Private-Use,[RFC1918],1996-02,N/A,True,True,True,False,False
192.0.0.0/24 [2],IETF Protocol Assignments,"[RFC6890], Section 2.1",2010-01,N/A,False,False,False,False,False
192.0.0.0/29,IPv4 Service Continuity Prefix,[RFC7335],2011-06,N/A,True,True,True,False,False
192.0.0.8/32,IPv4 dummy address,[RFC7600],2015-03,N/A,True,False,False,False,False
192.0.0.9/32,Port Control Protocol Anycast,[RFC7723],2015-10,N/A,True,True,True,True,False
192.0.0.10/32,Traversal Using Relays around NAT Anycast,[RFC8155],2017-02,N/A,True,True,True,True,False
"192.0.0.170/32, 192.0.0.171/32",NAT64/DNS64 Discovery,"[RFC8880][RFC7050], Section 2.2",2013-02,N/A,False,False,False,False,True
192.0.2.0/24,Documentation (TEST-NET-1),[RFC5737],2010-01,N/A,False,False,False,False,False
192.31.196.0/24,AS112-v4,[RFC7535],2014-12,N/A,True,True,True,True,False
192.52.193.0/24,AMT,[RFC7450],2014-12,N/A,True,True,True,True,False
192.88.99.0/24,Deprecated (6to4 Relay Anycast),[RFC7526],2001-06,2015-03,,,,,
192.88.99.2/32,6a44-relay anycast address,[RFC6751],2012-10,N/A,True,True,True,False,False
192.168.0.0/16,Private-Use,[RFC1918],1996-02,N/A,True,True,True,False,False
192.175.48.0/24,Direct Delegation AS112 Service,[RFC7534],1996-01,N/A,True,True,True,True,False
198.18.0.0/15,Benchmarking,[RFC2544],1999-03,N/A,True,True,True,False,False
198.51.100.0/24,Documentation (TEST-NET-2),[RFC5737],2010-01,N/A,False,False,False,False,False
203.0.113.0/24,Documentation (TEST-NET-3),[RFC5737],2010-01,N/A,False,False,False,False,False
240.0.0.0/4,Reserved,"[RFC1112], Section 4",1989-08,N/A,False,False,False,False,True
255.255.255.255/32,Limited Broadcast,"[RFC8190]
[RFC919], Section 7",1984-10,N/A,False,True,False,False,True
beaugunderson-ip-address-438375e/test/data/iana-ipv6-address-space.csv 0000664 0000000 0000000 00000004055 15272410673 0025616 0 ustar 00root root 0000000 0000000 IPv6 Prefix,Allocation,Reference,Notes
::/8,Reserved by IETF,[RFC3513][RFC4291],"This range has been partially allocated. See [IPv6 Special-Purpose Address Space] for details. ::/96, formerly defined as the ""IPv4-compatible IPv6 address"" prefix, was deprecated by [RFC4291]."
100::/8,Reserved by IETF,[RFC3513][RFC4291],This range has been partially allocated. See [IPv6 Special-Purpose Address Space] for details.
200::/7,Reserved by IETF,[RFC4048],Deprecated as of December 2004 [RFC4048]. Formerly an OSI NSAP-mapped prefix set [RFC4548].
400::/6,Reserved by IETF,[RFC3513][RFC4291],
800::/5,Reserved by IETF,[RFC3513][RFC4291],
1000::/4,Reserved by IETF,[RFC3513][RFC4291],
2000::/3,Global Unicast,[RFC3513][RFC4291],"The IPv6 Unicast space encompasses the entire IPv6 address range
with the exception of ff00::/8, per [RFC4291]. IANA unicast address
assignments are currently limited to the IPv6 unicast address
range of 2000::/3. IANA assignments from this block are registered
in [IPv6 Global Unicast Address Space]."
4000::/3,Reserved by IETF,[RFC3513][RFC4291],"This range has been partially allocated. See [IPv6 Special-Purpose Address Space] for details. 5f00::/8 (with 3ffe::/16, as noted at [IPv6 Global Unicast Address Space]) was used for the 6bone, but returned [RFC5156]."
6000::/3,Reserved by IETF,[RFC3513][RFC4291],
8000::/3,Reserved by IETF,[RFC3513][RFC4291],
a000::/3,Reserved by IETF,[RFC3513][RFC4291],
c000::/3,Reserved by IETF,[RFC3513][RFC4291],
e000::/4,Reserved by IETF,[RFC3513][RFC4291],
f000::/5,Reserved by IETF,[RFC3513][RFC4291],
f800::/6,Reserved by IETF,[RFC3513][RFC4291],
fc00::/7,Unique Local Unicast,[RFC4193],See [IPv6 Special-Purpose Address Space] for details.
fe00::/9,Reserved by IETF,[RFC3513][RFC4291],
fe80::/10,Link-Scoped Unicast,[RFC3513][RFC4291],See [IPv6 Special-Purpose Address Space] for details.
fec0::/10,Reserved by IETF,[RFC3879],Deprecated by [RFC3879] in September 2004. Formerly a Site-Local scoped address prefix.
ff00::/8,Multicast,[RFC3513][RFC4291],See [IPv6 Multicast Address Space] for details.
beaugunderson-ip-address-438375e/test/data/iana-ipv6-special-registry.csv 0000664 0000000 0000000 00000004361 15272410673 0026366 0 ustar 00root root 0000000 0000000 Address Block,Name,RFC,Allocation Date,Termination Date,Source,Destination,Forwardable,Globally Reachable,Reserved-by-Protocol
::1/128,Loopback Address,[RFC4291],2006-02,N/A,False,False,False,False,True
::/128,Unspecified Address,[RFC4291],2006-02,N/A,True,False,False,False,True
::ffff:0:0/96,IPv4-mapped Address,[RFC4291],2006-02,N/A,False,False,False,False,True
64:ff9b::/96,IPv4-IPv6 Translat.,[RFC6052],2010-10,N/A,True,True,True,True,False
64:ff9b:1::/48,IPv4-IPv6 Translat.,[RFC8215],2017-06,N/A,True,True,True,False,False
100::/64,Discard-Only Address Block,[RFC6666],2012-06,N/A,True,True,True,False,False
100:0:0:1::/64,Dummy IPv6 Prefix,[RFC9780],2025-04,N/A,True,False,False,False,False
2001::/23,IETF Protocol Assignments,[RFC2928],2000-09,N/A,False [1],False [1],False [1],False [1],False
2001::/32,TEREDO,"[RFC4380]
[RFC8190]",2006-01,N/A,True,True,True,N/A [2],False
2001:1::1/128,Port Control Protocol Anycast,[RFC7723],2015-10,N/A,True,True,True,True,False
2001:1::2/128,Traversal Using Relays around NAT Anycast,[RFC8155],2017-02,N/A,True,True,True,True,False
2001:1::3/128,DNS-SD Service Registration Protocol Anycast,[RFC9665],2024-04,N/A,True,True,True,True,False
2001:2::/48,Benchmarking,[RFC5180][RFC Errata 1752],2008-04,N/A,True,True,True,False,False
2001:3::/32,AMT,[RFC7450],2014-12,N/A,True,True,True,True,False
2001:4:112::/48,AS112-v6,[RFC7535],2014-12,N/A,True,True,True,True,False
2001:10::/28,Deprecated (previously ORCHID),[RFC4843],2007-03,2014-03,,,,,
2001:20::/28,ORCHIDv2,[RFC7343],2014-07,N/A,True,True,True,True,False
2001:30::/28,Drone Remote ID Protocol Entity Tags (DETs) Prefix,[RFC9374],2022-12,N/A,True,True,True,True,False
2001:db8::/32,Documentation,[RFC3849],2004-07,N/A,False,False,False,False,False
2002::/16 [3],6to4,[RFC3056],2001-02,N/A,True,True,True,N/A [3],False
2620:4f:8000::/48,Direct Delegation AS112 Service,[RFC7534],2011-05,N/A,True,True,True,True,False
3fff::/20,Documentation,[RFC9637],2024-07,N/A,False,False,False,False,False
5f00::/16,Segment Routing (SRv6) SIDs,[RFC9602],2024-04,N/A,True,True,True,False,False
fc00::/7,Unique-Local,"[RFC4193]
[RFC8190]",2005-10,N/A,True,True,True,False [4],False
fe80::/10,Link-Local Unicast,[RFC4291],2006-02,N/A,True,True,False,False,True
beaugunderson-ip-address-438375e/test/data/intermapper-invalid-ipv6-addresses.json 0000664 0000000 0000000 00000057041 15272410673 0030300 0 ustar 00root root 0000000 0000000 [
{
"address": "",
"conditions": []
},
{
"address": " 2001:0000:1234:0000:0000:C1C0:ABCD:0876",
"conditions": []
},
{
"address": " 2001:0000:1234:0000:0000:C1C0:ABCD:0876 ",
"conditions": []
},
{
"address": ":",
"conditions": []
},
{
"address": ":::",
"conditions": []
},
{
"address": ":::1.2.3.4",
"conditions": []
},
{
"address": ":::2222:3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":::2222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":::3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":::5555",
"conditions": []
},
{
"address": ":::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":::5555:6666:7777:8888",
"conditions": []
},
{
"address": ":::6666:1.2.3.4",
"conditions": []
},
{
"address": ":::6666:7777:8888",
"conditions": []
},
{
"address": ":::7777:8888",
"conditions": []
},
{
"address": ":::8888",
"conditions": []
},
{
"address": "::.",
"conditions": []
},
{
"address": "::..",
"conditions": []
},
{
"address": "::...",
"conditions": []
},
{
"address": "::...4",
"conditions": []
},
{
"address": "::..3.",
"conditions": []
},
{
"address": "::..3.4",
"conditions": []
},
{
"address": "::.2..",
"conditions": []
},
{
"address": "::.2.3.",
"conditions": []
},
{
"address": "::.2.3.4",
"conditions": []
},
{
"address": "::1...",
"conditions": []
},
{
"address": "::1.2..",
"conditions": []
},
{
"address": "::1.2.256.4",
"conditions": []
},
{
"address": "::1.2.3.",
"conditions": []
},
{
"address": "::1.2.3.256",
"conditions": []
},
{
"address": "::1.2.3.300",
"conditions": []
},
{
"address": "::1.2.3.900",
"conditions": []
},
{
"address": "::1.2.300.4",
"conditions": []
},
{
"address": "::1.2.900.4",
"conditions": []
},
{
"address": "::1.256.3.4",
"conditions": []
},
{
"address": "::1.300.3.4",
"conditions": []
},
{
"address": "::1.900.3.4",
"conditions": []
},
{
"address": "::1111:2222:3333:4444:5555:6666::",
"conditions": []
},
{
"address": "::2222::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "::2222::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "::2222:3333::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "::2222:3333::5555:6666:7777:8888",
"conditions": []
},
{
"address": "::2222:3333:4444::6666:1.2.3.4",
"conditions": []
},
{
"address": "::2222:3333:4444::6666:7777:8888",
"conditions": []
},
{
"address": "::2222:3333:4444:5555::1.2.3.4",
"conditions": []
},
{
"address": "::2222:3333:4444:5555::7777:8888",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:6666:7777:1.2.3.4",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:6666:7777:8888:9999",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:7777::8888",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:7777:8888::",
"conditions": []
},
{
"address": "::256.2.3.4",
"conditions": []
},
{
"address": "::260.2.3.4",
"conditions": []
},
{
"address": "::300.2.3.4",
"conditions": []
},
{
"address": "::300.300.300.300",
"conditions": []
},
{
"address": "::3000.30.30.30",
"conditions": []
},
{
"address": "::3333:4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "::400.2.3.4",
"conditions": []
},
{
"address": "::4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "::5555:",
"conditions": []
},
{
"address": "::5555:6666:7777:8888:",
"conditions": []
},
{
"address": "::6666:7777:8888:",
"conditions": []
},
{
"address": "::7777:8888:",
"conditions": []
},
{
"address": "::8888:",
"conditions": []
},
{
"address": "::900.2.3.4",
"conditions": []
},
{
"address": "::ffff:192x168.1.26",
"conditions": []
},
{
"address": "::ffff:2.3.4",
"conditions": []
},
{
"address": "::ffff:257.1.2.3",
"conditions": []
},
{
"address": ":1.2.3.4",
"conditions": []
},
{
"address": ":1111::",
"conditions": []
},
{
"address": ":1111::1.2.3.4",
"conditions": []
},
{
"address": ":1111::3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111::3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111::5555",
"conditions": []
},
{
"address": ":1111::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111::5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111::6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111::6666:7777:8888",
"conditions": []
},
{
"address": ":1111::7777:8888",
"conditions": []
},
{
"address": ":1111::8888",
"conditions": []
},
{
"address": ":1111:2222::",
"conditions": []
},
{
"address": ":1111:2222::1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222::5555",
"conditions": []
},
{
"address": ":1111:2222::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222::5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222::6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222::6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222::7777:8888",
"conditions": []
},
{
"address": ":1111:2222::8888",
"conditions": []
},
{
"address": ":1111:2222:3333::",
"conditions": []
},
{
"address": ":1111:2222:3333::1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333::5555",
"conditions": []
},
{
"address": ":1111:2222:3333::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333::5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333::6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333::6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333::7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333::8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::5555",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555::",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555::1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555::7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555::8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666::",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666::8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666:7777::",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":2222:3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":2222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":5555:6666:7777:8888",
"conditions": []
},
{
"address": ":6666:1.2.3.4",
"conditions": []
},
{
"address": ":6666:7777:8888",
"conditions": []
},
{
"address": ":7777:8888",
"conditions": []
},
{
"address": ":8888",
"conditions": []
},
{
"address": "':10.0.0.1",
"conditions": []
},
{
"address": "02001:0000:1234:0000:0000:C1C0:ABCD:0876",
"conditions": []
},
{
"address": "1:::3:4:5",
"conditions": []
},
{
"address": "1::1.2.256.4",
"conditions": []
},
{
"address": "1::1.2.3.256",
"conditions": []
},
{
"address": "1::1.2.3.300",
"conditions": []
},
{
"address": "1::1.2.3.900",
"conditions": []
},
{
"address": "1::1.2.300.4",
"conditions": []
},
{
"address": "1::1.2.900.4",
"conditions": []
},
{
"address": "1::1.256.3.4",
"conditions": []
},
{
"address": "1::1.300.3.4",
"conditions": []
},
{
"address": "1::1.900.3.4",
"conditions": []
},
{
"address": "1::2::3",
"conditions": []
},
{
"address": "1::256.2.3.4",
"conditions": []
},
{
"address": "1::260.2.3.4",
"conditions": []
},
{
"address": "1::300.2.3.4",
"conditions": []
},
{
"address": "1::300.300.300.300",
"conditions": []
},
{
"address": "1::3000.30.30.30",
"conditions": []
},
{
"address": "1::400.2.3.4",
"conditions": []
},
{
"address": "1::5:1.2.256.4",
"conditions": []
},
{
"address": "1::5:1.2.3.256",
"conditions": []
},
{
"address": "1::5:1.2.3.300",
"conditions": []
},
{
"address": "1::5:1.2.3.900",
"conditions": []
},
{
"address": "1::5:1.2.300.4",
"conditions": []
},
{
"address": "1::5:1.2.900.4",
"conditions": []
},
{
"address": "1::5:1.256.3.4",
"conditions": []
},
{
"address": "1::5:1.300.3.4",
"conditions": []
},
{
"address": "1::5:1.900.3.4",
"conditions": []
},
{
"address": "1::5:256.2.3.4",
"conditions": []
},
{
"address": "1::5:260.2.3.4",
"conditions": []
},
{
"address": "1::5:300.2.3.4",
"conditions": []
},
{
"address": "1::5:300.300.300.300",
"conditions": []
},
{
"address": "1::5:3000.30.30.30",
"conditions": []
},
{
"address": "1::5:400.2.3.4",
"conditions": []
},
{
"address": "1::5:900.2.3.4",
"conditions": []
},
{
"address": "1::900.2.3.4",
"conditions": []
},
{
"address": "1:2:3::4:5::7:8",
"conditions": []
},
{
"address": "1:2:3::4:5:6:7:8:9",
"conditions": []
},
{
"address": "1:2:3:4:5:6:7:8:9",
"conditions": []
},
{
"address": "1.2.3.4",
"conditions": []
},
{
"address": "1.2.3.4::",
"conditions": []
},
{
"address": "1.2.3.4::5555",
"conditions": []
},
{
"address": "1.2.3.4:1111::5555",
"conditions": []
},
{
"address": "1.2.3.4:1111:2222::5555",
"conditions": []
},
{
"address": "1.2.3.4:1111:2222:3333::5555",
"conditions": []
},
{
"address": "1.2.3.4:1111:2222:3333:4444::5555",
"conditions": []
},
{
"address": "1111",
"conditions": []
},
{
"address": "1111:",
"conditions": []
},
{
"address": "1111:::",
"conditions": []
},
{
"address": "1111:::3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:::3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111::3333::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111::3333::5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111::3333:4444::6666:1.2.3.4",
"conditions": []
},
{
"address": "1111::3333:4444::6666:7777:8888",
"conditions": []
},
{
"address": "1111::3333:4444:5555::1.2.3.4",
"conditions": []
},
{
"address": "1111::3333:4444:5555::7777:8888",
"conditions": []
},
{
"address": "1111::3333:4444:5555:6666::8888",
"conditions": []
},
{
"address": "1111::3333:4444:5555:6666:7777::",
"conditions": []
},
{
"address": "1111::3333:4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111::4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111::5555:",
"conditions": []
},
{
"address": "1111::5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111::6666:7777:8888:",
"conditions": []
},
{
"address": "1111::7777:8888:",
"conditions": []
},
{
"address": "1111::8888:",
"conditions": []
},
{
"address": "1111:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222",
"conditions": []
},
{
"address": "1111:2222:",
"conditions": []
},
{
"address": "1111:2222:::",
"conditions": []
},
{
"address": "1111:2222:::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222::4444::6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222::4444::6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222::4444:5555::1.2.3.4",
"conditions": []
},
{
"address": "1111:2222::4444:5555::7777:8888",
"conditions": []
},
{
"address": "1111:2222::4444:5555:6666::8888",
"conditions": []
},
{
"address": "1111:2222::4444:5555:6666:7777::",
"conditions": []
},
{
"address": "1111:2222::4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222::5555:",
"conditions": []
},
{
"address": "1111:2222::5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222::6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222::7777:8888:",
"conditions": []
},
{
"address": "1111:2222::8888:",
"conditions": []
},
{
"address": "1111:2222:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333",
"conditions": []
},
{
"address": "1111:2222:3333:",
"conditions": []
},
{
"address": "1111:2222:3333:::",
"conditions": []
},
{
"address": "1111:2222:3333:::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:::5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333::5555:",
"conditions": []
},
{
"address": "1111:2222:3333::5555::1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333::5555::7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333::5555:6666::8888",
"conditions": []
},
{
"address": "1111:2222:3333::5555:6666:7777::",
"conditions": []
},
{
"address": "1111:2222:3333::5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333::6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333::7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333::8888:",
"conditions": []
},
{
"address": "1111:2222:3333:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444",
"conditions": []
},
{
"address": "1111:2222:3333:4444:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:::6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:::6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444::5555:",
"conditions": []
},
{
"address": "1111:2222:3333:4444::6666::8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444::6666:7777::",
"conditions": []
},
{
"address": "1111:2222:3333:4444::6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444::7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444::8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:::1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:::7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::7777::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:::8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666::1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666::8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:00.00.00.00",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:000.000.000.000",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:1.2.3.4.5",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:255.255.255255",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:255.255255.255",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:255255.255.255",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:256.256.256.256",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888:9999",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:77778888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:66661.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:66667777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:55556666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:55556666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:44445555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:44445555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:33334444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:33334444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:22223333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:22223333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "11112222:3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "11112222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "123",
"conditions": []
},
{
"address": "12345::6:7:8",
"conditions": []
},
{
"address": "124.15.6.89/60",
"conditions": []
},
{
"address": "2001::FFD3::57ab",
"conditions": []
},
{
"address": "2001:0000:1234: 0000:0000:C1C0:ABCD:0876",
"conditions": []
},
{
"address": "2001:0000:1234:0000:0000:C1C0:ABCD:0876 0",
"conditions": []
},
{
"address": "2001:0000:1234:0000:00001:C1C0:ABCD:0876",
"conditions": []
},
{
"address": "2001:1:1:1:1:1:255Z255X255Y255",
"conditions": []
},
{
"address": "2001:DB8:0:0:8:800:200C:417A:221",
"conditions": []
},
{
"address": "2001:db8:85a3::8a2e:37023:7334",
"conditions": []
},
{
"address": "2001:db8:85a3::8a2e:370k:7334",
"conditions": []
},
{
"address": "3ffe:0b00:0000:0001:0000:0000:000a",
"conditions": []
},
{
"address": "3ffe:b00::1::a",
"conditions": []
},
{
"address": "fe80:0000:0000:0000:0204:61ff:254.157.241.086",
"conditions": []
},
{
"address": "FF01::101::2",
"conditions": []
},
{
"address": "FF02:0000:0000:0000:0000:0000:0000:0000:0001",
"conditions": []
},
{
"address": "ldkfj",
"conditions": []
},
{
"address": "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4",
"conditions": []
},
{
"address": "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX",
"conditions": []
}
]
beaugunderson-ip-address-438375e/test/data/intermapper-valid-ipv6-addresses.json 0000664 0000000 0000000 00000031575 15272410673 0027755 0 ustar 00root root 0000000 0000000 [
{
"address": "::",
"conditions": []
},
{
"address": "::/128",
"conditions": []
},
{
"address": "::0",
"conditions": []
},
{
"address": "::0:0",
"conditions": []
},
{
"address": "::0:0:0",
"conditions": []
},
{
"address": "::0:0:0:0",
"conditions": []
},
{
"address": "::0:0:0:0:0",
"conditions": []
},
{
"address": "::0:0:0:0:0:0",
"conditions": []
},
{
"address": "::0:0:0:0:0:0:0",
"conditions": []
},
{
"address": "::0:a:b:c:d:e:f",
"conditions": []
},
{
"address": "::1",
"conditions": []
},
{
"address": "::1/128",
"conditions": []
},
{
"address": "::10.0.0.1",
"conditions": []
},
{
"address": "::123.123.123.123",
"conditions": []
},
{
"address": "::13.1.68.3",
"conditions": []
},
{
"address": "::2:3",
"conditions": []
},
{
"address": "::2:3:4",
"conditions": []
},
{
"address": "::2:3:4:5",
"conditions": []
},
{
"address": "::2:3:4:5:6",
"conditions": []
},
{
"address": "::2:3:4:5:6:7",
"conditions": []
},
{
"address": "::2:3:4:5:6:7:8",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "::3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "::4444:5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "::5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "::5555:6666:7777:8888",
"conditions": []
},
{
"address": "::6666:123.123.123.123",
"conditions": []
},
{
"address": "::6666:7777:8888",
"conditions": []
},
{
"address": "::7777:8888",
"conditions": []
},
{
"address": "::8",
"conditions": []
},
{
"address": "::8888",
"conditions": []
},
{
"address": "::ffff:0:0",
"conditions": []
},
{
"address": "::ffff:0c22:384e",
"conditions": []
},
{
"address": "::FFFF:10.0.0.1",
"conditions": []
},
{
"address": "::ffff:12.34.56.78",
"conditions": []
},
{
"address": "::FFFF:129.144.52.38",
"conditions": []
},
{
"address": "::ffff:192.0.2.128",
"conditions": []
},
{
"address": "::ffff:192.168.1.1",
"conditions": []
},
{
"address": "::ffff:192.168.1.26",
"conditions": []
},
{
"address": "::ffff:c000:280",
"conditions": []
},
{
"address": "0::",
"conditions": []
},
{
"address": "0:0::",
"conditions": []
},
{
"address": "0:0:0::",
"conditions": []
},
{
"address": "0:0:0:0::",
"conditions": []
},
{
"address": "0:0:0:0:0::",
"conditions": []
},
{
"address": "0:0:0:0:0:0::",
"conditions": []
},
{
"address": "0:0:0:0:0:0:0::",
"conditions": []
},
{
"address": "0:0:0:0:0:0:0:0",
"conditions": []
},
{
"address": "0:0:0:0:0:0:0:1",
"conditions": []
},
{
"address": "0:0:0:0:0:0:13.1.68.3",
"conditions": []
},
{
"address": "0:0:0:0:0:FFFF:129.144.52.38",
"conditions": []
},
{
"address": "0:a:b:c:d:e:f::",
"conditions": []
},
{
"address": "0000:0000:0000:0000:0000:0000:0000:0000",
"conditions": []
},
{
"address": "0000:0000:0000:0000:0000:0000:0000:0001",
"conditions": []
},
{
"address": "1::",
"conditions": []
},
{
"address": "1::1.2.3.4",
"conditions": []
},
{
"address": "1::2:3",
"conditions": []
},
{
"address": "1::2:3:4",
"conditions": []
},
{
"address": "1::2:3:4:5",
"conditions": []
},
{
"address": "1::2:3:4:5:6",
"conditions": []
},
{
"address": "1::2:3:4:5:6:7",
"conditions": []
},
{
"address": "1::5:1.2.3.4",
"conditions": []
},
{
"address": "1::5:11.22.33.44",
"conditions": []
},
{
"address": "1::7:8",
"conditions": []
},
{
"address": "1::8",
"conditions": []
},
{
"address": "1:2::",
"conditions": []
},
{
"address": "1:2::1.2.3.4",
"conditions": []
},
{
"address": "1:2::5:1.2.3.4",
"conditions": []
},
{
"address": "1:2::7:8",
"conditions": []
},
{
"address": "1:2::8",
"conditions": []
},
{
"address": "1:2:3::",
"conditions": []
},
{
"address": "1:2:3::1.2.3.4",
"conditions": []
},
{
"address": "1:2:3::5:1.2.3.4",
"conditions": []
},
{
"address": "1:2:3::7:8",
"conditions": []
},
{
"address": "1:2:3::8",
"conditions": []
},
{
"address": "1:2:3:4::",
"conditions": []
},
{
"address": "1:2:3:4::1.2.3.4",
"conditions": []
},
{
"address": "1:2:3:4::5:1.2.3.4",
"conditions": []
},
{
"address": "1:2:3:4::7:8",
"conditions": []
},
{
"address": "1:2:3:4::8",
"conditions": []
},
{
"address": "1:2:3:4:5::",
"conditions": []
},
{
"address": "1:2:3:4:5::1.2.3.4",
"conditions": []
},
{
"address": "1:2:3:4:5::7:8",
"conditions": []
},
{
"address": "1:2:3:4:5::8",
"conditions": []
},
{
"address": "1:2:3:4:5:6::",
"conditions": []
},
{
"address": "1:2:3:4:5:6::8",
"conditions": []
},
{
"address": "1:2:3:4:5:6:1.2.3.4",
"conditions": []
},
{
"address": "1:2:3:4:5:6:7:8",
"conditions": []
},
{
"address": "1111::",
"conditions": []
},
{
"address": "1111::123.123.123.123",
"conditions": []
},
{
"address": "1111::3333:4444:5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "1111::3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111::4444:5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "1111::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111::5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "1111::5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111::6666:123.123.123.123",
"conditions": []
},
{
"address": "1111::6666:7777:8888",
"conditions": []
},
{
"address": "1111::7777:8888",
"conditions": []
},
{
"address": "1111::8888",
"conditions": []
},
{
"address": "1111:2222::",
"conditions": []
},
{
"address": "1111:2222::123.123.123.123",
"conditions": []
},
{
"address": "1111:2222::4444:5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "1111:2222::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222::5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "1111:2222::5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222::6666:123.123.123.123",
"conditions": []
},
{
"address": "1111:2222::6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222::7777:8888",
"conditions": []
},
{
"address": "1111:2222::8888",
"conditions": []
},
{
"address": "1111:2222:3333::",
"conditions": []
},
{
"address": "1111:2222:3333::123.123.123.123",
"conditions": []
},
{
"address": "1111:2222:3333::5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "1111:2222:3333::5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333::6666:123.123.123.123",
"conditions": []
},
{
"address": "1111:2222:3333::6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333::7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333::8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444::",
"conditions": []
},
{
"address": "1111:2222:3333:4444::123.123.123.123",
"conditions": []
},
{
"address": "1111:2222:3333:4444::6666:123.123.123.123",
"conditions": []
},
{
"address": "1111:2222:3333:4444::6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444::7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444::8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::123.123.123.123",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666::8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:123.123.123.123",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "2::10",
"conditions": []
},
{
"address": "2001:0000:1234:0000:0000:C1C0:ABCD:0876",
"conditions": []
},
{
"address": "2001:0db8::1428:57ab",
"conditions": []
},
{
"address": "2001:0DB8::CD30:0:0:0:0/60",
"conditions": []
},
{
"address": "2001:0db8:0:0::1428:57ab",
"conditions": []
},
{
"address": "2001:0db8:0:0:0:0:1428:57ab",
"conditions": []
},
{
"address": "2001:0DB8:0:CD30::/60",
"conditions": []
},
{
"address": "2001:0db8:0000:0000:0000::1428:57ab",
"conditions": []
},
{
"address": "2001:0db8:0000:0000:0000:0000:1428:57ab",
"conditions": []
},
{
"address": "2001:0DB8:0000:CD30:0000:0000:0000:0000/60",
"conditions": []
},
{
"address": "2001:0db8:1234::",
"conditions": []
},
{
"address": "2001:0db8:1234:0000:0000:0000:0000:0000",
"conditions": []
},
{
"address": "2001:0db8:1234:ffff:ffff:ffff:ffff:ffff",
"conditions": []
},
{
"address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"conditions": []
},
{
"address": "2001:db8::",
"conditions": []
},
{
"address": "2001:db8::%1",
"conditions": []
},
{
"address": "2001:db8::1428:57ab",
"conditions": []
},
{
"address": "2001:DB8::8:800:200C:417A",
"conditions": []
},
{
"address": "2001:DB8:0:0:8:800:200C:417A",
"conditions": []
},
{
"address": "2001:db8:85a3::8a2e:370:7334",
"conditions": []
},
{
"address": "2001:db8:85a3:0:0:8a2e:370:7334",
"conditions": []
},
{
"address": "2001:db8:a::123",
"conditions": []
},
{
"address": "2002::",
"conditions": []
},
{
"address": "3ffe:0b00:0000:0000:0001:0000:0000:000a",
"conditions": []
},
{
"address": "a:b:c:d:e:f:0::",
"conditions": []
},
{
"address": "fe80::",
"conditions": []
},
{
"address": "FE80::/10",
"conditions": []
},
{
"address": "fe80::1",
"conditions": []
},
{
"address": "fe80::204:61ff:254.157.241.86",
"conditions": []
},
{
"address": "fe80::204:61ff:fe9d:f156",
"conditions": []
},
{
"address": "fe80::217:f2ff:254.7.237.98",
"conditions": []
},
{
"address": "fe80::217:f2ff:fe07:ed62",
"conditions": []
},
{
"address": "fe80:0:0:0:204:61ff:254.157.241.86",
"conditions": []
},
{
"address": "fe80:0:0:0:204:61ff:fe9d:f156",
"conditions": []
},
{
"address": "fe80:0000:0000:0000:0204:61ff:fe9d:f156",
"conditions": []
},
{
"address": "FEC0::/10",
"conditions": []
},
{
"address": "FF00::/8",
"conditions": []
},
{
"address": "FF01::101",
"conditions": []
},
{
"address": "FF01:0:0:0:0:0:0:101",
"conditions": []
},
{
"address": "ff02::1",
"conditions": []
},
{
"address": "FF02:0000:0000:0000:0000:0000:0000:0001",
"conditions": []
}
]
beaugunderson-ip-address-438375e/test/data/invalid-ipv4-addresses.json 0000664 0000000 0000000 00000001455 15272410673 0025750 0 ustar 00root root 0000000 0000000 [
{
"address": " 127.0.0.1",
"conditions": []
},
{
"address": "127.0.0.1 ",
"conditions": []
},
{
"address": "127.0.0.1 127.0.0.1",
"conditions": []
},
{
"address": "127.0.0.256",
"conditions": []
},
{
"address": "127.0.0.1//1",
"conditions": []
},
{
"address": "127.0.0.1/0x1",
"conditions": []
},
{
"address": "127.0.0.1/-1",
"conditions": []
},
{
"address": "127.0.0.1/ab",
"conditions": []
},
{
"address": "127.0.0.1/",
"conditions": []
},
{
"address": "127.0.0.256/32",
"conditions": []
},
{
"address": "127.0.0.1/33",
"conditions": []
},
{
"address": "001.002.003.004",
"conditions": []
}
]
beaugunderson-ip-address-438375e/test/data/invalid-ipv6-addresses.json 0000664 0000000 0000000 00000060563 15272410673 0025757 0 ustar 00root root 0000000 0000000 [
{
"address": "':10.0.0.1",
"conditions": []
},
{
"address": "-1",
"conditions": []
},
{
"address": "::1 ::1",
"conditions": []
},
{
"address": "02001:0000:1234:0000:0000:C1C0:ABCD:0876",
"conditions": []
},
{
"address": "1.2.3.4",
"conditions": []
},
{
"address": "1.2.3.4:1111:2222:3333:4444::5555",
"conditions": []
},
{
"address": "1.2.3.4:1111:2222:3333::5555",
"conditions": []
},
{
"address": "1.2.3.4:1111:2222::5555",
"conditions": []
},
{
"address": "1.2.3.4:1111::5555",
"conditions": []
},
{
"address": "1.2.3.4::",
"conditions": []
},
{
"address": "1.2.3.4::5555",
"conditions": []
},
{
"address": "1111",
"conditions": []
},
{
"address": "11112222:3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "11112222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "::1//64",
"conditions": []
},
{
"address": "::1/0001",
"conditions": []
},
{
"address": "1111:",
"conditions": []
},
{
"address": "1111:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222",
"conditions": []
},
{
"address": "1111:22223333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:22223333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:",
"conditions": []
},
{
"address": "1111:2222:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333",
"conditions": []
},
{
"address": "1111:2222:33334444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:33334444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:",
"conditions": []
},
{
"address": "1111:2222:3333:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444",
"conditions": []
},
{
"address": "1111:2222:3333:44445555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:44445555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555",
"conditions": []
},
{
"address": "1111:2222:3333:4444:55556666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:55556666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:66661.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:66667777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:00.00.00.00",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:000.000.000.000",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:1.2.3.4.5",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:255.255.255255",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:255.255255.255",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:255255.255.255",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:256.256.256.256",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:77778888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888:9999",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666::1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666::8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:6666:::8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::7777::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555::8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:::1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:5555:::7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444::5555:",
"conditions": []
},
{
"address": "1111:2222:3333:4444::6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444::6666:7777::",
"conditions": []
},
{
"address": "1111:2222:3333:4444::6666::8888",
"conditions": []
},
{
"address": "1111:2222:3333:4444::7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444::8888:",
"conditions": []
},
{
"address": "1111:2222:3333:4444:::",
"conditions": []
},
{
"address": "1111:2222:3333:4444:::6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:4444:::6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333::5555:",
"conditions": []
},
{
"address": "1111:2222:3333::5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333::5555:6666:7777::",
"conditions": []
},
{
"address": "1111:2222:3333::5555:6666::8888",
"conditions": []
},
{
"address": "1111:2222:3333::5555::1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333::5555::7777:8888",
"conditions": []
},
{
"address": "1111:2222:3333::6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333::7777:8888:",
"conditions": []
},
{
"address": "1111:2222:3333::8888:",
"conditions": []
},
{
"address": "1111:2222:3333:::",
"conditions": []
},
{
"address": "1111:2222:3333:::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:3333:::5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222::4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222::4444:5555:6666:7777::",
"conditions": []
},
{
"address": "1111:2222::4444:5555:6666::8888",
"conditions": []
},
{
"address": "1111:2222::4444:5555::1.2.3.4",
"conditions": []
},
{
"address": "1111:2222::4444:5555::7777:8888",
"conditions": []
},
{
"address": "1111:2222::4444::6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222::4444::6666:7777:8888",
"conditions": []
},
{
"address": "1111:2222::5555:",
"conditions": []
},
{
"address": "1111:2222::5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222::6666:7777:8888:",
"conditions": []
},
{
"address": "1111:2222::7777:8888:",
"conditions": []
},
{
"address": "1111:2222::8888:",
"conditions": []
},
{
"address": "1111:2222:::",
"conditions": []
},
{
"address": "1111:2222:::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:2222:::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111::3333:4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111::3333:4444:5555:6666:7777::",
"conditions": []
},
{
"address": "1111::3333:4444:5555:6666::8888",
"conditions": []
},
{
"address": "1111::3333:4444:5555::1.2.3.4",
"conditions": []
},
{
"address": "1111::3333:4444:5555::7777:8888",
"conditions": []
},
{
"address": "1111::3333:4444::6666:1.2.3.4",
"conditions": []
},
{
"address": "1111::3333:4444::6666:7777:8888",
"conditions": []
},
{
"address": "1111::3333::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111::3333::5555:6666:7777:8888",
"conditions": []
},
{
"address": "1111::4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111::5555:",
"conditions": []
},
{
"address": "1111::5555:6666:7777:8888:",
"conditions": []
},
{
"address": "1111::6666:7777:8888:",
"conditions": []
},
{
"address": "1111::7777:8888:",
"conditions": []
},
{
"address": "1111::8888:",
"conditions": []
},
{
"address": "1111:::",
"conditions": []
},
{
"address": "1111:::3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "1111:::3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "123",
"conditions": []
},
{
"address": "12345::6:7:8",
"conditions": []
},
{
"address": "124.15.6.89/60",
"conditions": []
},
{
"address": "1:2:3:4:5:6:7:8:9",
"conditions": []
},
{
"address": "1:2:3::4:5:6:7:8:9",
"conditions": []
},
{
"address": "1:2:3::4:5::7:8",
"conditions": []
},
{
"address": "1::1.2.256.4",
"conditions": []
},
{
"address": "1::1.2.3.256",
"conditions": []
},
{
"address": "1::1.2.3.300",
"conditions": []
},
{
"address": "1::1.2.3.900",
"conditions": []
},
{
"address": "1::1.2.300.4",
"conditions": []
},
{
"address": "1::1.2.900.4",
"conditions": []
},
{
"address": "1::1.256.3.4",
"conditions": []
},
{
"address": "1::1.300.3.4",
"conditions": []
},
{
"address": "1::1.900.3.4",
"conditions": []
},
{
"address": "1::256.2.3.4",
"conditions": []
},
{
"address": "1::260.2.3.4",
"conditions": []
},
{
"address": "1::2::3",
"conditions": []
},
{
"address": "1::300.2.3.4",
"conditions": []
},
{
"address": "1::300.300.300.300",
"conditions": []
},
{
"address": "1::3000.30.30.30",
"conditions": []
},
{
"address": "1::400.2.3.4",
"conditions": []
},
{
"address": "1::5:1.2.256.4",
"conditions": []
},
{
"address": "1::5:1.2.3.256",
"conditions": []
},
{
"address": "1::5:1.2.3.300",
"conditions": []
},
{
"address": "1::5:1.2.3.900",
"conditions": []
},
{
"address": "1::5:1.2.300.4",
"conditions": []
},
{
"address": "1::5:1.2.900.4",
"conditions": []
},
{
"address": "1::5:1.256.3.4",
"conditions": []
},
{
"address": "1::5:1.300.3.4",
"conditions": []
},
{
"address": "1::5:1.900.3.4",
"conditions": []
},
{
"address": "1::5:256.2.3.4",
"conditions": []
},
{
"address": "1::5:260.2.3.4",
"conditions": []
},
{
"address": "1::5:300.2.3.4",
"conditions": []
},
{
"address": "1::5:300.300.300.300",
"conditions": []
},
{
"address": "1::5:3000.30.30.30",
"conditions": []
},
{
"address": "1::5:400.2.3.4",
"conditions": []
},
{
"address": "1::5:900.2.3.4",
"conditions": []
},
{
"address": "1::900.2.3.4",
"conditions": []
},
{
"address": "1:::3:4:5",
"conditions": []
},
{
"address": "2001:0000:1234: 0000:0000:C1C0:ABCD:0876",
"conditions": []
},
{
"address": "2001:0000:1234:0000:00001:C1C0:ABCD:0876",
"conditions": []
},
{
"address": "2001:0000:1234:0000:0000:C1C0:ABCD:0876 0",
"conditions": []
},
{
"address": "2001:1:1:1:1:1:255Z255X255Y255",
"conditions": []
},
{
"address": "2001::FFD3::57ab",
"conditions": []
},
{
"address": "2001:DB8:0:0:8:800:200C:417A:221",
"conditions": []
},
{
"address": "2001:db8:85a3::8a2e:37023:7334",
"conditions": []
},
{
"address": "2001:db8:85a3::8a2e:370k:7334",
"conditions": []
},
{
"address": "3ffe:0b00:0000:0001:0000:0000:000a",
"conditions": []
},
{
"address": "3ffe:b00::1::a",
"conditions": []
},
{
"address": ":",
"conditions": []
},
{
"address": ":1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666:7777::",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666::",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555:6666::8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555::",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555::1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555::7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444:5555::8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::5555",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333:4444::8888",
"conditions": []
},
{
"address": ":1111:2222:3333::",
"conditions": []
},
{
"address": ":1111:2222:3333::1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333::5555",
"conditions": []
},
{
"address": ":1111:2222:3333::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333::5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333::6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222:3333::6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333::7777:8888",
"conditions": []
},
{
"address": ":1111:2222:3333::8888",
"conditions": []
},
{
"address": ":1111:2222::",
"conditions": []
},
{
"address": ":1111:2222::1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222::5555",
"conditions": []
},
{
"address": ":1111:2222::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222::5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222::6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111:2222::6666:7777:8888",
"conditions": []
},
{
"address": ":1111:2222::7777:8888",
"conditions": []
},
{
"address": ":1111:2222::8888",
"conditions": []
},
{
"address": ":1111::",
"conditions": []
},
{
"address": ":1111::1.2.3.4",
"conditions": []
},
{
"address": ":1111::3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111::3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111::5555",
"conditions": []
},
{
"address": ":1111::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111::5555:6666:7777:8888",
"conditions": []
},
{
"address": ":1111::6666:1.2.3.4",
"conditions": []
},
{
"address": ":1111::6666:7777:8888",
"conditions": []
},
{
"address": ":1111::7777:8888",
"conditions": []
},
{
"address": ":1111::8888",
"conditions": []
},
{
"address": ":2222:3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":2222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":5555:6666:7777:8888",
"conditions": []
},
{
"address": ":6666:1.2.3.4",
"conditions": []
},
{
"address": ":6666:7777:8888",
"conditions": []
},
{
"address": ":7777:8888",
"conditions": []
},
{
"address": ":8888",
"conditions": []
},
{
"address": "::-1",
"conditions": []
},
{
"address": "::.",
"conditions": []
},
{
"address": "::..",
"conditions": []
},
{
"address": "::...",
"conditions": []
},
{
"address": "::...4",
"conditions": []
},
{
"address": "::..3.",
"conditions": []
},
{
"address": "::..3.4",
"conditions": []
},
{
"address": "::.2..",
"conditions": []
},
{
"address": "::.2.3.",
"conditions": []
},
{
"address": "::.2.3.4",
"conditions": []
},
{
"address": "::1...",
"conditions": []
},
{
"address": "::1.2..",
"conditions": []
},
{
"address": "::1.2.256.4",
"conditions": []
},
{
"address": "::1.2.3.",
"conditions": []
},
{
"address": "::1.2.3.256",
"conditions": []
},
{
"address": "::1.2.3.300",
"conditions": []
},
{
"address": "::1.2.3.900",
"conditions": []
},
{
"address": "::1.2.300.4",
"conditions": []
},
{
"address": "::1.2.900.4",
"conditions": []
},
{
"address": "::1.256.3.4",
"conditions": []
},
{
"address": "::1.300.3.4",
"conditions": []
},
{
"address": "::1.900.3.4",
"conditions": []
},
{
"address": "::1111:2222:3333:4444:5555:6666::",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:6666:7777:1.2.3.4",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:6666:7777:8888:9999",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:7777:8888::",
"conditions": []
},
{
"address": "::2222:3333:4444:5555:7777::8888",
"conditions": []
},
{
"address": "::2222:3333:4444:5555::1.2.3.4",
"conditions": []
},
{
"address": "::2222:3333:4444:5555::7777:8888",
"conditions": []
},
{
"address": "::2222:3333:4444::6666:1.2.3.4",
"conditions": []
},
{
"address": "::2222:3333:4444::6666:7777:8888",
"conditions": []
},
{
"address": "::2222:3333::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "::2222:3333::5555:6666:7777:8888",
"conditions": []
},
{
"address": "::2222::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": "::2222::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "::256.2.3.4",
"conditions": []
},
{
"address": "::260.2.3.4",
"conditions": []
},
{
"address": "::300.2.3.4",
"conditions": []
},
{
"address": "::300.300.300.300",
"conditions": []
},
{
"address": "::3000.30.30.30",
"conditions": []
},
{
"address": "::3333:4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "::400.2.3.4",
"conditions": []
},
{
"address": "::4444:5555:6666:7777:8888:",
"conditions": []
},
{
"address": "::5555:",
"conditions": []
},
{
"address": "::5555:6666:7777:8888:",
"conditions": []
},
{
"address": "::6666:7777:8888:",
"conditions": []
},
{
"address": "::7777:8888:",
"conditions": []
},
{
"address": "::8888:",
"conditions": []
},
{
"address": "::900.2.3.4",
"conditions": []
},
{
"address": ":::",
"conditions": []
},
{
"address": ":::1.2.3.4",
"conditions": []
},
{
"address": ":::2222:3333:4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":::2222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":::3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":::4444:5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": ":::5555",
"conditions": []
},
{
"address": ":::5555:6666:1.2.3.4",
"conditions": []
},
{
"address": ":::5555:6666:7777:8888",
"conditions": []
},
{
"address": ":::6666:1.2.3.4",
"conditions": []
},
{
"address": ":::6666:7777:8888",
"conditions": []
},
{
"address": ":::7777:8888",
"conditions": []
},
{
"address": ":::8888",
"conditions": []
},
{
"address": "::ffff:192x168.1.26",
"conditions": []
},
{
"address": "::ffff:2.3.4",
"conditions": []
},
{
"address": "::ffff:257.1.2.3",
"conditions": []
},
{
"address": "FF01::101::2",
"conditions": []
},
{
"address": "FF02:0000:0000:0000:0000:0000:0000:0000:0001",
"conditions": []
},
{
"address": "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4",
"conditions": []
},
{
"address": "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX",
"conditions": []
},
{
"address": "a::b::c",
"conditions": []
},
{
"address": "a::g",
"conditions": []
},
{
"address": "a:a:a:a:a:a:a:a:a",
"conditions": []
},
{
"address": "a:aaaaa::",
"conditions": []
},
{
"address": "a:b",
"conditions": []
},
{
"address": "a:b:c:d:e:f:g:0",
"conditions": []
},
{
"address": "fe80:0000:0000:0000:0204:61ff:254.157.241.086",
"conditions": []
},
{
"address": "ffff:",
"conditions": []
},
{
"address": "ffff::ffff::ffff",
"conditions": []
},
{
"address": "ffgg:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"conditions": []
},
{
"address": "ldkfj",
"conditions": []
},
{
"address": "::/129",
"conditions": []
},
{
"address": "1000:://32",
"conditions": []
},
{
"address": "::/",
"conditions": []
}
]
beaugunderson-ip-address-438375e/test/data/valid-ipv4-addresses.json 0000664 0000000 0000000 00000000514 15272410673 0025414 0 ustar 00root root 0000000 0000000 [
{
"address": "127.0.0.1",
"conditions": ["correct-ipv4"]
},
{
"address": "127.0.0.1/02",
"conditions": ["incorrect-ipv4"]
},
{
"address": "127.0.0.1/32",
"conditions": ["correct-ipv4"]
},
{
"address": "255.255.255.255/32",
"conditions": ["correct-ipv4"]
}
]
beaugunderson-ip-address-438375e/test/data/valid-ipv6-addresses.json 0000664 0000000 0000000 00000040455 15272410673 0025426 0 ustar 00root root 0000000 0000000 [
{
"address": "0000:0000:0000:0000:0000:0000:0000:0000/128",
"conditions": ["incorrect", "canonical", "has-subnet"]
},
{
"address": "0000:0000:0000:0000:0000:0000:0000:0000",
"conditions": ["incorrect", "canonical"]
},
{
"address": "0000:0000:0000:0000:0000:0000:0000:0001",
"conditions": ["incorrect", "canonical"]
},
{
"address": "0:0:0:0:0:0:0:0",
"conditions": ["incorrect"]
},
{
"address": "0:0:0:0:0:0:0:1",
"conditions": ["incorrect"]
},
{
"address": "0:0:0:0:0:0:0::",
"conditions": ["incorrect"]
},
{
"address": "0:0:0:0:0:0:13.1.68.3",
"conditions": ["incorrect", "v4-in-v6"]
},
{
"address": "0:0:0:0:0:0::",
"conditions": ["incorrect"]
},
{
"address": "0:0:0:0:0::",
"conditions": ["incorrect"]
},
{
"address": "0:0:0:0:0:FFFF:129.144.52.38",
"conditions": ["incorrect", "v4-in-v6"]
},
{
"address": "0:0:0:0:1:0:0:0",
"conditions": ["incorrect"]
},
{
"address": "0:0:0:0::",
"conditions": ["incorrect"]
},
{
"address": "0:0:0::",
"conditions": ["incorrect"]
},
{
"address": "0:0::",
"conditions": ["incorrect"]
},
{
"address": "0:1:2:3:4:5:6:7/001",
"conditions": ["incorrect", "has-subnet"]
},
{
"address": "0:1:2:3:4:5:6:7/128",
"conditions": ["correct", "has-subnet"]
},
{
"address": "0:1:2:3:4:5:6:7",
"conditions": ["correct"]
},
{
"address": "0::",
"conditions": ["incorrect"]
},
{
"address": "0:a:b:c:d:e:f::",
"conditions": ["incorrect"]
},
{
"address": "1080:0:0:0:8:800:200c:417a",
"conditions": ["incorrect"]
},
{
"address": "1080::8:800:200c:417a",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333:4444:5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222:3333:4444:5555:6666:7777:8888",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333:4444:5555:6666:7777::",
"conditions": ["incorrect"]
},
{
"address": "1111:2222:3333:4444:5555:6666::",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333:4444:5555:6666::8888",
"conditions": ["incorrect"]
},
{
"address": "1111:2222:3333:4444:5555::",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333:4444:5555::123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222:3333:4444:5555::7777:8888",
"conditions": ["incorrect"]
},
{
"address": "1111:2222:3333:4444:5555::8888",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333:4444::",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333:4444::123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222:3333:4444::6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222:3333:4444::6666:7777:8888",
"conditions": ["incorrect"]
},
{
"address": "1111:2222:3333:4444::7777:8888",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333:4444::8888",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333::",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333::123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222:3333::5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222:3333::5555:6666:7777:8888",
"conditions": ["incorrect"]
},
{
"address": "1111:2222:3333::6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222:3333::6666:7777:8888",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333::7777:8888",
"conditions": ["correct"]
},
{
"address": "1111:2222:3333::8888",
"conditions": ["correct"]
},
{
"address": "1111:2222::",
"conditions": ["correct"]
},
{
"address": "1111:2222::123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222::4444:5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222::4444:5555:6666:7777:8888",
"conditions": ["incorrect"]
},
{
"address": "1111:2222::5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222::5555:6666:7777:8888",
"conditions": ["correct"]
},
{
"address": "1111:2222::6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111:2222::6666:7777:8888",
"conditions": ["correct"]
},
{
"address": "1111:2222::7777:8888",
"conditions": ["correct"]
},
{
"address": "1111:2222::8888",
"conditions": ["correct"]
},
{
"address": "1111::",
"conditions": ["correct"]
},
{
"address": "1111::123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111::3333:4444:5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111::3333:4444:5555:6666:7777:8888",
"conditions": ["incorrect"]
},
{
"address": "1111::4444:5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111::4444:5555:6666:7777:8888",
"conditions": ["correct"]
},
{
"address": "1111::5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111::5555:6666:7777:8888",
"conditions": ["correct"]
},
{
"address": "1111::6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "1111::6666:7777:8888",
"conditions": ["correct"]
},
{
"address": "1111::7777:8888",
"conditions": ["correct"]
},
{
"address": "1111::8888",
"conditions": ["correct"]
},
{
"address": "1:2:3:4:5:6:1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1:2:3:4:5:6:7:8",
"conditions": ["correct"]
},
{
"address": "1:2:3:4:5:6::",
"conditions": ["correct"]
},
{
"address": "1:2:3:4:5:6::8",
"conditions": ["incorrect"]
},
{
"address": "1:2:3:4:5::",
"conditions": ["correct"]
},
{
"address": "1:2:3:4:5::1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1:2:3:4:5::7:8",
"conditions": ["incorrect"]
},
{
"address": "1:2:3:4:5::8",
"conditions": ["correct"]
},
{
"address": "1:2:3:4::",
"conditions": ["correct"]
},
{
"address": "1:2:3:4::1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1:2:3:4::5:1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1:2:3:4::7:8",
"conditions": ["correct"]
},
{
"address": "1:2:3:4::8",
"conditions": ["correct"]
},
{
"address": "1:2:3::",
"conditions": ["correct"]
},
{
"address": "1:2:3::1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1:2:3::5:1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1:2:3::7:8",
"conditions": ["correct"]
},
{
"address": "1:2:3::8",
"conditions": ["correct"]
},
{
"address": "1:2::",
"conditions": ["correct"]
},
{
"address": "1:2::1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1:2::5:1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1:2::7:8",
"conditions": ["correct"]
},
{
"address": "1:2::8",
"conditions": ["correct"]
},
{
"address": "1::",
"conditions": ["correct"]
},
{
"address": "1::1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1::2:3",
"conditions": ["correct"]
},
{
"address": "1::2:3:4",
"conditions": ["correct"]
},
{
"address": "1::2:3:4:5",
"conditions": ["correct"]
},
{
"address": "1::2:3:4:5:6",
"conditions": ["correct"]
},
{
"address": "1::2:3:4:5:6:7",
"conditions": ["incorrect"]
},
{
"address": "1::5:1.2.3.4",
"conditions": ["v4-in-v6"]
},
{
"address": "1::5:11.22.33.44",
"conditions": ["v4-in-v6"]
},
{
"address": "1::7:8",
"conditions": ["correct"]
},
{
"address": "1::8",
"conditions": ["correct"]
},
{
"address": "2001:0000:1234:0000:0000:C1C0:ABCD:0876",
"conditions": ["incorrect"]
},
{
"address": "2001:0000:4136:e378:8000:63bf:3fff:fdd2",
"conditions": ["canonical"]
},
{
"address": "2001:0DB8:0000:CD30:0000:0000:0000:0000/60",
"conditions": ["incorrect", "has-subnet"]
},
{
"address": "2001:0DB8:0:CD30::/60",
"conditions": ["incorrect", "has-subnet"]
},
{
"address": "2001:0DB8::CD30:0:0:0:0/60",
"conditions": ["incorrect", "has-subnet"]
},
{
"address": "2001:0db8:0000:0000:0000:0000:1428:57ab",
"conditions": []
},
{
"address": "2001:0db8:0000:0000:0000::1428:57ab",
"conditions": []
},
{
"address": "2001:0db8:0:0:0:0:1428:57ab",
"conditions": []
},
{
"address": "2001:0db8:0:0::1428:57ab",
"conditions": []
},
{
"address": "2001:0db8:1234:0000:0000:0000:0000:0000",
"conditions": []
},
{
"address": "2001:0db8:1234::",
"conditions": []
},
{
"address": "2001:0db8:1234:ffff:ffff:ffff:ffff:ffff",
"conditions": []
},
{
"address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"conditions": []
},
{
"address": "2001:0db8::1428:57ab",
"conditions": []
},
{
"address": "2001::CE49:7601:2CAD:DFFF:7C94:FFFE",
"conditions": ["incorrect"]
},
{
"address": "2001::CE49:7601:E866:EFFF:62C3:FFFE",
"conditions": ["incorrect"]
},
{
"address": "2001:DB8:0:0:8:800:200C:417A",
"conditions": ["incorrect"]
},
{
"address": "2001:DB8::8:800:200C:417A",
"conditions": ["incorrect"]
},
{
"address": "2001:db8:85a3:0:0:8a2e:370:7334",
"conditions": ["incorrect"]
},
{
"address": "2001:db8:85a3::8a2e:370:7334",
"conditions": ["correct"]
},
{
"address": "2001:db8::",
"conditions": ["correct"]
},
{
"address": "2001:db8::1428:57ab",
"conditions": ["correct"]
},
{
"address": "2001:db8:a::123",
"conditions": ["correct"]
},
{
"address": "2002::",
"conditions": ["correct"]
},
{
"address": "2608::3:5",
"conditions": ["correct"]
},
{
"address": "2608:af09:30:0:0:0:0:134",
"conditions": []
},
{
"address": "2608:af09:30::102a:7b91:c239:baff",
"conditions": []
},
{
"address": "2::10",
"conditions": ["correct"]
},
{
"address": "3ffe:0b00:0000:0000:0001:0000:0000:000a",
"conditions": ["canonical"]
},
{
"address": "7:6:5:4:3:2:1:0",
"conditions": ["correct"]
},
{
"address": "::",
"conditions": ["correct"]
},
{
"address": "::/128",
"conditions": ["correct", "has-subnet"]
},
{
"address": "::0",
"conditions": []
},
{
"address": "::0:0",
"conditions": []
},
{
"address": "::0:0:0",
"conditions": []
},
{
"address": "::0:0:0:0",
"conditions": []
},
{
"address": "::0:0:0:0:0",
"conditions": []
},
{
"address": "::0:0:0:0:0:0",
"conditions": []
},
{
"address": "::0:0:0:0:0:0:0",
"conditions": []
},
{
"address": "::0:a:b:c:d:e:f",
"conditions": []
},
{
"address": "::1",
"conditions": []
},
{
"address": "::1/128",
"conditions": ["correct", "has-subnet"]
},
{
"address": "::123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "::13.1.68.3",
"conditions": ["v4-in-v6"]
},
{
"address": "::2222:3333:4444:5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "::2222:3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "::2:3",
"conditions": []
},
{
"address": "::2:3:4",
"conditions": []
},
{
"address": "::2:3:4:5",
"conditions": []
},
{
"address": "::2:3:4:5:6",
"conditions": []
},
{
"address": "::2:3:4:5:6:7",
"conditions": []
},
{
"address": "::2:3:4:5:6:7:8",
"conditions": []
},
{
"address": "::3333:4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "::4444:5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "::4444:5555:6666:7777:8888",
"conditions": []
},
{
"address": "::5555:6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "::5555:6666:7777:8888",
"conditions": []
},
{
"address": "::6666:123.123.123.123",
"conditions": ["v4-in-v6"]
},
{
"address": "::6666:7777:8888",
"conditions": []
},
{
"address": "::7777:8888",
"conditions": []
},
{
"address": "::8",
"conditions": []
},
{
"address": "::8888",
"conditions": []
},
{
"address": "::FFFF:129.144.52.38",
"conditions": ["v4-in-v6"]
},
{
"address": "::ffff:0:0",
"conditions": []
},
{
"address": "::ffff:0c22:384e",
"conditions": []
},
{
"address": "::ffff:12.34.56.78",
"conditions": ["v4-in-v6"]
},
{
"address": "::ffff:192.0.2.128",
"conditions": ["v4-in-v6"]
},
{
"address": "::ffff:192.168.1.1",
"conditions": ["v4-in-v6"]
},
{
"address": "::ffff:192.168.1.26",
"conditions": ["v4-in-v6"]
},
{
"address": "::ffff:c000:280",
"conditions": []
},
{
"address": "FE80::/10",
"conditions": ["incorrect", "has-subnet"]
},
{
"address": "FEC0::/10",
"conditions": ["incorrect", "has-subnet"]
},
{
"address": "FF00::/8",
"conditions": ["incorrect", "has-subnet"]
},
{
"address": "FF01:0:0:0:0:0:0:101",
"conditions": ["incorrect"]
},
{
"address": "FF01::101",
"conditions": ["incorrect"]
},
{
"address": "FF02:0000:0000:0000:0000:0000:0000:0001",
"conditions": ["incorrect"]
},
{
"address": "a:b:c:d:e:f:0::",
"conditions": ["incorrect"]
},
{
"address": "fe80:0000:0000:0000:0204:61ff:fe9d:f156",
"conditions": ["canonical"]
},
{
"address": "fe80:0:0:0:204:61ff:254.157.241.86",
"conditions": ["v4-in-v6"]
},
{
"address": "fe80:0:0:0:204:61ff:fe9d:f156",
"conditions": ["incorrect"]
},
{
"address": "fe80::",
"conditions": ["correct"]
},
{
"address": "fe80::1",
"conditions": ["correct"]
},
{
"address": "fe80::204:61ff:254.157.241.86",
"conditions": ["v4-in-v6"]
},
{
"address": "fe80::204:61ff:fe9d:f156",
"conditions": []
},
{
"address": "fe80::217:f2ff:254.7.237.98",
"conditions": ["v4-in-v6"]
},
{
"address": "fe80::217:f2ff:fe07:ed62",
"conditions": ["correct"]
},
{
"address": "fedc:ba98:7654:3210:fedc:ba98:7654:3210",
"conditions": ["correct", "canonical"]
},
{
"address": "ff02::1",
"conditions": ["correct"]
},
{
"address": "ffff::",
"conditions": ["correct"]
},
{
"address": "ffff::3:5",
"conditions": ["correct"]
},
{
"address": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"conditions": ["correct", "canonical"]
},
{
"address": "a:0::0:b",
"conditions": ["incorrect"]
},
{
"address": "a:0:0::0:b",
"conditions": ["incorrect"]
},
{
"address": "a:0::0:0:b",
"conditions": ["incorrect"]
},
{
"address": "a::0:0:b",
"conditions": ["incorrect"]
},
{
"address": "a::0:b",
"conditions": ["incorrect"]
},
{
"address": "a:0::b",
"conditions": ["incorrect"]
},
{
"address": "a:0:0::b",
"conditions": ["incorrect"]
}
]
beaugunderson-ip-address-438375e/test/docs-check-test.ts 0000664 0000000 0000000 00000006003 15272410673 0023205 0 ustar 00root root 0000000 0000000 import * as chai from 'chai';
import * as childProcess from 'node:child_process';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
const { expect } = chai;
const ROOT = path.join(__dirname, '..');
// Only disposable fixtures are modified; no test stages or regenerates the real README.
describe('the docs check and commit gate', function docsChecks() {
this.timeout(30000);
let fixture: string;
beforeEach(() => {
fixture = fs.mkdtempSync(path.join(os.tmpdir(), 'ip-address-docs-'));
['src', 'scripts', 'README.md', 'tsconfig.json', 'package.json', 'hooks'].forEach((name) => {
fs.cpSync(path.join(ROOT, name), path.join(fixture, name), { recursive: true });
});
fs.symlinkSync(path.join(ROOT, 'node_modules'), path.join(fixture, 'node_modules'));
});
afterEach(() => {
fs.rmSync(fixture, { recursive: true });
});
function docs(check: boolean) {
return childProcess.spawnSync(
path.join(ROOT, 'node_modules/.bin/tsx'),
['scripts/build-readme.ts', ...(check ? ['--check'] : [])],
{ cwd: fixture, encoding: 'utf8' },
);
}
it('rejects stale docs without rewriting them and accepts regenerated docs', () => {
const readme = path.join(fixture, 'README.md');
fs.appendFileSync(readme, '\nStale fixture\n');
const before = fs.readFileSync(readme, 'utf8');
expect(docs(true).status).to.equal(1);
expect(fs.readFileSync(readme, 'utf8')).to.equal(before);
expect(docs(false).status).to.equal(0);
const generated = fs.readFileSync(readme, 'utf8');
expect(docs(true).status).to.equal(0);
expect(fs.readFileSync(readme, 'utf8')).to.equal(generated);
});
it('runs the docs gate and refuses partially staged inputs without changing the index', () => {
function git(args: string[]) {
return childProcess.execFileSync('git', args, { cwd: fixture, encoding: 'utf8' });
}
git(['init', '-q']);
git(['add', 'src', 'scripts', 'README.md', 'tsconfig.json', 'package.json']);
const bin = path.join(fixture, 'bin');
fs.mkdirSync(bin);
fs.writeFileSync(
path.join(bin, 'npm'),
'#!/bin/sh\nprintf "%s\\n" "$*" >> "$CALLS"\ncase "$*" in *docs:check*) exit 1;; esac\n',
{ mode: 0o755 },
);
const calls = path.join(fixture, 'calls');
const runHook = () =>
childProcess.spawnSync('sh', ['hooks/pre-commit'], {
cwd: fixture,
encoding: 'utf8',
env: { ...process.env, PATH: `${bin}:${process.env.PATH}`, CALLS: calls },
});
expect(runHook().status).to.equal(1);
expect(fs.readFileSync(calls, 'utf8')).to.include('docs:check');
const index = git(['write-tree']);
fs.appendFileSync(path.join(fixture, 'README.md'), '\nUnstaged edit\n');
const result = runHook();
expect(result.status).to.equal(1);
expect(result.stdout + result.stderr).to.include('unstaged');
expect(git(['write-tree'])).to.equal(index);
expect(fs.readFileSync(path.join(fixture, 'README.md'), 'utf8')).to.include('Unstaged edit');
});
});
beaugunderson-ip-address-438375e/test/functionality-v4-test.ts 0000664 0000000 0000000 00000112174 15272410673 0024430 0 ustar 00root root 0000000 0000000 import * as chai from 'chai';
import { Address4 } from '../src/ipv4';
import { AddressError } from '../src/address-error';
const should = chai.should();
// A convenience function to convert a list of IPv4 address notations
// to Address4 instances
function notationsToAddresseses(notations: string[]): Address4[] {
return notations.map((notation) => new Address4(notation));
}
describe('v4', () => {
describe('An invalid address', () => {
it('is invalid', () => {
should.Throw(() => new Address4('127.0.0'));
should.equal(Address4.isValid('127.0.0'), false);
});
});
describe('input length', () => {
// Four three-digit octets and three dots: the longest well-formed
// address is 15 characters. Anything longer is rejected before parsing,
// as Address6 does at its own limit.
const longest = '255.255.255.255';
it('accepts the longest well-formed address, with a suffix', () => {
longest.length.should.equal(15);
should.equal(Address4.isValid(longest), true);
should.equal(Address4.isValid(`${longest}/32`), true);
});
it('rejects a longer address', () => {
const inputs = ['1'.repeat(16), `${'1'.repeat(16)}/8`, '!'.repeat(1 << 20)];
for (const input of inputs) {
should.equal(Address4.isValid(input), false);
should.Throw(() => new Address4(input), AddressError, /at most 15 characters/);
}
});
});
describe('non-ASCII digits', () => {
// The WHATWG URL parser maps fullwidth digits and dots to ASCII
// (`new URL('http://127.0.0.1/').hostname` is '127.0.0.1'), so a
// parser that read them as numbers would agree with it on the address
// while a raw string comparison disagreed: the shape of Node's
// CVE-2026-105483 TLS hostname bypass. Every entry point rejects them.
const fullwidth = (s: string) =>
s.replace(/[!-~]/g, (c) => String.fromCharCode(c.charCodeAt(0) + 0xfee0));
const digitsFrom = (zero: number) => (s: string) =>
s.replace(/[0-9]/g, (d) => String.fromCharCode(zero + Number(d)));
// Each ASCII input parses, so a rejected variant is rejected for its
// Unicode, not for its shape.
const inputs = ['127.0.0.1', '10.0.0.1/8', '192.168.1.255/32'];
const variantsOf = (s: string) => {
const variants = [
fullwidth(s),
// Arabic-Indic and Devanagari digits
digitsFrom(0x0660)(s),
digitsFrom(0x0966)(s),
];
for (let i = 0; i < s.length; i++) {
variants.push(s.slice(0, i) + fullwidth(s[i]) + s.slice(i + 1));
}
return variants;
};
it('rejects them in an address or subnet', () => {
for (const input of inputs) {
should.equal(Address4.isValid(input), true);
for (const variant of variantsOf(input)) {
should.equal(Address4.isValid(variant), false, variant);
should.Throw(() => new Address4(variant), AddressError);
}
}
});
it('rejects them in hex and arpa forms', () => {
should.Throw(() => Address4.fromHex(fullwidth('7f000001')), AddressError);
should.Throw(() => Address4.fromHex(`7f00000${fullwidth('1')}`), AddressError);
const arpa = '1.0.0.127.in-addr.arpa.';
Address4.fromArpa(arpa).correctForm().should.equal('127.0.0.1');
should.Throw(() => Address4.fromArpa(fullwidth('1') + arpa.slice(1)), AddressError);
should.Throw(() => Address4.fromArpa(fullwidth(arpa)), AddressError);
});
it('rejects them in mask and wildcard forms', () => {
Address4.fromAddressAndMask('10.0.0.1', '255.255.255.0').subnet.should.equal('/24');
should.Throw(() => Address4.fromAddressAndMask(fullwidth('10.0.0.1'), '255.255.255.0'));
should.Throw(() => Address4.fromAddressAndMask('10.0.0.1', `255.255.255.${fullwidth('0')}`));
Address4.fromAddressAndWildcardMask('10.0.0.1', '0.0.0.255').subnet.should.equal('/24');
should.Throw(() => Address4.fromAddressAndWildcardMask(fullwidth('10.0.0.1'), '0.0.0.255'));
should.Throw(() => Address4.fromAddressAndWildcardMask('10.0.0.1', fullwidth('0.0.0.255')));
Address4.fromWildcard('192.168.0.*').subnet.should.equal('/24');
should.Throw(() => Address4.fromWildcard(`192.168.${fullwidth('0')}.*`), AddressError);
should.Throw(() => Address4.fromWildcard(`192.168.0.${fullwidth('*')}`), AddressError);
should.Throw(() => Address4.fromWildcard(`192.168.0${fullwidth('.')}*`), AddressError);
});
});
describe('A correct address', () => {
const topic = new Address4('127.0.0.1');
it('validates as correct', () => {
topic.isCorrect().should.equal(true);
should.equal(topic.correctForm(), '127.0.0.1');
should.equal(Address4.isValid('127.0.0.1'), true);
});
it('should group', () => {
topic
.groupForV6()
.should.equal(
'127.0.' +
'0.1',
);
});
});
describe('An address with a subnet', () => {
const topic = new Address4('127.0.0.1/16');
it('is contained by an identical address with an identical subnet', () => {
const same = new Address4('127.0.0.1/16');
topic.isInSubnet(same).should.equal(true);
});
});
describe('A small subnet', () => {
const topic = new Address4('127.0.0.1/16');
it('is contained by larger subnets', () => {
for (let i = 15; i > 0; i--) {
const larger = new Address4(`127.0.0.1/${i}`);
topic.isInSubnet(larger).should.equal(true);
}
});
});
describe('A large subnet', () => {
const topic = new Address4('127.0.0.1/8');
it('is not contained by smaller subnets', () => {
for (let i = 9; i <= 32; i++) {
const smaller = new Address4(`127.0.0.1/${i}`);
topic.isInSubnet(smaller).should.equal(false);
}
});
});
describe('An integer v4 address', () => {
const topic = Address4.fromInteger(432432423);
it('parses correctly', () => {
topic.address.should.equal('25.198.101.39');
topic.subnet.should.equal('/32');
topic.subnetMask.should.equal(32);
});
it('should match an address from its hex representation', () => {
const hex = Address4.fromHex('19c66527');
hex.address.should.equal('25.198.101.39');
hex.subnet.should.equal('/32');
hex.subnetMask.should.equal(32);
});
});
describe('An address with a subnet', () => {
const topic = new Address4('127.0.0.1/16');
it('parses the subnet', () => {
should.equal(topic.subnet, '/16');
});
it('has a correct start address', () => {
should.equal(topic.startAddress().correctForm(), '127.0.0.0');
});
it('has a correct start address hosts only', () => {
should.equal(topic.startAddressExclusive().correctForm(), '127.0.0.1');
});
it('has a correct end address', () => {
should.equal(topic.endAddress().correctForm(), '127.0.255.255');
});
it('has a correct end address hosts only', () => {
should.equal(topic.endAddressExclusive().correctForm(), '127.0.255.254');
});
it('has a correct subnet mask address', () => {
should.equal(topic.subnetMaskAddress().correctForm(), '255.255.0.0');
});
it('is in its own subnet', () => {
topic.isInSubnet(new Address4('127.0.0.1/16')).should.equal(true);
});
it('is not in another subnet', () => {
topic.isInSubnet(new Address4('192.168.0.1/16')).should.equal(false);
});
});
describe('subnetMaskAddress', () => {
it('returns 0.0.0.0 for /0', () => {
should.equal(new Address4('0.0.0.0/0').subnetMaskAddress().correctForm(), '0.0.0.0');
});
it('returns 255.0.0.0 for /8', () => {
should.equal(new Address4('10.0.0.1/8').subnetMaskAddress().correctForm(), '255.0.0.0');
});
it('returns 255.255.240.0 for /20', () => {
should.equal(
new Address4('127.0.0.2/20').subnetMaskAddress().correctForm(),
'255.255.240.0',
);
});
it('returns 255.255.255.255 for /32 (default)', () => {
should.equal(
new Address4('192.168.1.1').subnetMaskAddress().correctForm(),
'255.255.255.255',
);
});
});
describe('fromAddressAndMask', () => {
it('translates 255.255.255.0 to /24', () => {
const topic = Address4.fromAddressAndMask('192.168.1.1', '255.255.255.0');
topic.subnetMask.should.equal(24);
topic.subnet.should.equal('/24');
should.equal(topic.addressMinusSuffix, '192.168.1.1');
});
it('translates 0.0.0.0 to /0', () => {
Address4.fromAddressAndMask('192.168.1.1', '0.0.0.0').subnetMask.should.equal(0);
});
it('translates 255.255.255.255 to /32', () => {
Address4.fromAddressAndMask('192.168.1.1', '255.255.255.255').subnetMask.should.equal(32);
});
it('round-trips through subnetMaskAddress()', () => {
const original = new Address4('10.0.0.1/20');
const mask = original.subnetMaskAddress().correctForm();
Address4.fromAddressAndMask('10.0.0.1', mask).subnetMask.should.equal(20);
});
it('rejects a non-contiguous mask', () => {
(() => Address4.fromAddressAndMask('192.168.1.1', '255.0.255.0')).should.throw(
'Invalid subnet mask.',
);
});
it('rejects a mask with bytes out of range', () => {
(() => Address4.fromAddressAndMask('192.168.1.1', '256.0.0.0')).should.throw();
});
it('does not change isValid() behavior for mask-form input', () => {
Address4.isValid('192.168.1.1/255.255.255.0').should.equal(false);
});
});
describe('wildcardMask', () => {
it('returns 255.255.255.255 for /0', () => {
should.equal(new Address4('0.0.0.0/0').wildcardMask().correctForm(), '255.255.255.255');
});
it('returns 0.255.255.255 for /8', () => {
should.equal(new Address4('10.0.0.1/8').wildcardMask().correctForm(), '0.255.255.255');
});
it('returns 0.0.15.255 for /20', () => {
should.equal(new Address4('127.0.0.2/20').wildcardMask().correctForm(), '0.0.15.255');
});
it('returns 0.0.0.3 for /30', () => {
should.equal(new Address4('127.0.0.2/30').wildcardMask().correctForm(), '0.0.0.3');
});
it('returns 0.0.0.0 for /32 (default)', () => {
should.equal(new Address4('192.168.1.1').wildcardMask().correctForm(), '0.0.0.0');
});
it('is the inverse of subnetMaskAddress', () => {
for (let i = 0; i <= 32; i++) {
const topic = new Address4(`10.0.0.1/${i}`);
const mask = topic.subnetMaskAddress().bigInt();
const wildcard = topic.wildcardMask().bigInt();
const allOnes = (BigInt(1) << BigInt(32)) - BigInt(1);
(mask ^ wildcard).should.equal(allOnes);
}
});
});
describe('networkForm', () => {
it('returns 0.0.0.0/0 for /0', () => {
should.equal(new Address4('10.0.0.1/0').networkForm(), '0.0.0.0/0');
});
it('returns 10.0.0.0/8 for 10.0.0.1/8', () => {
should.equal(new Address4('10.0.0.1/8').networkForm(), '10.0.0.0/8');
});
it('returns 205.65.224.104/29 for the issue #39 example', () => {
should.equal(new Address4('205.65.224.110/29').networkForm(), '205.65.224.104/29');
});
it('returns 192.168.1.0/24 for 192.168.1.5/24', () => {
should.equal(new Address4('192.168.1.5/24').networkForm(), '192.168.1.0/24');
});
it('returns the address itself with /32 when no subnet is given', () => {
should.equal(new Address4('192.168.1.5').networkForm(), '192.168.1.5/32');
});
it('round-trips through the Address4 constructor', () => {
const original = new Address4('10.20.30.40/12');
const round = new Address4(original.networkForm());
round.correctForm().should.equal('10.16.0.0');
round.subnetMask.should.equal(12);
});
});
describe('fromAddressAndWildcardMask', () => {
it('translates 0.0.0.255 to /24', () => {
const topic = Address4.fromAddressAndWildcardMask('192.168.1.1', '0.0.0.255');
topic.subnetMask.should.equal(24);
topic.subnet.should.equal('/24');
should.equal(topic.addressMinusSuffix, '192.168.1.1');
});
it('translates 0.0.0.3 to /30 (Cisco ACL example)', () => {
Address4.fromAddressAndWildcardMask('192.168.1.1', '0.0.0.3').subnetMask.should.equal(30);
});
it('translates 255.255.255.255 to /0', () => {
Address4.fromAddressAndWildcardMask(
'192.168.1.1',
'255.255.255.255',
).subnetMask.should.equal(0);
});
it('translates 0.0.0.0 to /32', () => {
Address4.fromAddressAndWildcardMask('192.168.1.1', '0.0.0.0').subnetMask.should.equal(32);
});
it('round-trips through wildcardMask()', () => {
const original = new Address4('10.0.0.1/20');
const wildcard = original.wildcardMask().correctForm();
Address4.fromAddressAndWildcardMask('10.0.0.1', wildcard).subnetMask.should.equal(20);
});
it('rejects a non-contiguous wildcard mask', () => {
(() => Address4.fromAddressAndWildcardMask('192.168.1.1', '0.255.0.255')).should.throw(
'Invalid subnet mask.',
);
});
});
describe('fromWildcard', () => {
it('parses 192.168.0.* as /24', () => {
const topic = Address4.fromWildcard('192.168.0.*');
topic.subnet.should.equal('/24');
topic.startAddress().correctForm().should.equal('192.168.0.0');
topic.endAddress().correctForm().should.equal('192.168.0.255');
});
it('parses 192.168.*.* as /16', () => {
const topic = Address4.fromWildcard('192.168.*.*');
topic.subnet.should.equal('/16');
topic.startAddress().correctForm().should.equal('192.168.0.0');
topic.endAddress().correctForm().should.equal('192.168.255.255');
});
it('parses 10.*.*.* as /8', () => {
Address4.fromWildcard('10.*.*.*').subnet.should.equal('/8');
});
it('parses *.*.*.* as /0', () => {
Address4.fromWildcard('*.*.*.*').subnet.should.equal('/0');
});
it('parses a no-wildcard address as /32', () => {
const topic = Address4.fromWildcard('192.168.1.1');
topic.subnet.should.equal('/32');
topic.correctForm().should.equal('192.168.1.1');
});
it('rejects an interior wildcard', () => {
(() => Address4.fromWildcard('*.168.0.1')).should.throw(
'Wildcard `*` must only appear in trailing octets',
);
(() => Address4.fromWildcard('192.*.0.1')).should.throw(
'Wildcard `*` must only appear in trailing octets',
);
});
it('rejects a partial-octet wildcard', () => {
(() => Address4.fromWildcard('192.168.0.1*')).should.throw('Invalid IPv4 address.');
});
it('rejects a pattern with the wrong number of octets', () => {
(() => Address4.fromWildcard('192.168.*')).should.throw(
'Wildcard pattern must have 4 octets',
);
(() => Address4.fromWildcard('192.168.0.0.*')).should.throw(
'Wildcard pattern must have 4 octets',
);
});
it('rejects an out-of-range octet in the prefix', () => {
(() => Address4.fromWildcard('999.168.0.*')).should.throw('Invalid IPv4 address.');
});
});
describe('Creating an address from a BigInt', () => {
const topic = Address4.fromBigInt(BigInt('2130706433'));
it('should parse correctly', () => {
topic.correctForm().should.equal('127.0.0.1');
});
it('should accept the boundary values 0 and 2**32 - 1', () => {
Address4.fromBigInt(0n).correctForm().should.equal('0.0.0.0');
Address4.fromBigInt(0xffffffffn).correctForm().should.equal('255.255.255.255');
});
it('should reject negative values', () => {
(() => Address4.fromBigInt(-1n)).should.throw(
'IPv4 BigInt must be in the range 0 to 2**32 - 1',
);
});
it('should reject values greater than 2**32 - 1', () => {
(() => Address4.fromBigInt(0x100000000n)).should.throw(
'IPv4 BigInt must be in the range 0 to 2**32 - 1',
);
});
});
describe('Creating an address from an integer', () => {
it('should reject negative integers', () => {
(() => Address4.fromInteger(-1)).should.throw(
'IPv4 integer must be in the range 0 to 2**32 - 1',
);
});
it('should reject integers greater than 2**32 - 1', () => {
(() => Address4.fromInteger(2 ** 32)).should.throw(
'IPv4 integer must be in the range 0 to 2**32 - 1',
);
});
it('should reject non-integer numbers', () => {
(() => Address4.fromInteger(1.5)).should.throw(
'IPv4 integer must be in the range 0 to 2**32 - 1',
);
(() => Address4.fromInteger(NaN)).should.throw(
'IPv4 integer must be in the range 0 to 2**32 - 1',
);
});
});
describe('Converting an address to a BigInt', () => {
const topic = new Address4('127.0.0.1');
it('should convert properly', () => {
topic.bigInt().toString(10).should.equal('2130706433');
});
});
describe('Creating an address from hex', () => {
const topic = Address4.fromHex('7f:00:00:01');
it('should parse correctly', () => {
topic.correctForm().should.equal('127.0.0.1');
});
it('should accept 8 hex digits without separators', () => {
Address4.fromHex('7f000001').correctForm().should.equal('127.0.0.1');
});
it('should reject hex strings shorter than 8 digits', () => {
(() => Address4.fromHex('ff:ff')).should.throw('IPv4 hex must be exactly 8 hex digits');
});
it('should reject hex strings longer than 8 digits', () => {
(() => Address4.fromHex('1ff:ff:ff:ff')).should.throw(
'IPv4 hex must be exactly 8 hex digits',
);
});
it('should reject non-hex characters', () => {
(() => Address4.fromHex('zz:zz:zz:zz')).should.throw(
'IPv4 hex must be exactly 8 hex digits',
);
});
});
describe('Converting an address to hex', () => {
const topic = new Address4('127.0.0.1');
it('should convert correctly', () => {
topic.toHex().should.equal('7f:00:00:01');
});
});
describe('Converting an address to an array', () => {
const topic = new Address4('127.0.0.1');
it('should convert correctly', () => {
const a = topic.toArray();
a.should.be.an.instanceOf(Array).and.have.lengthOf(4);
a[0].should.equal(127);
a[1].should.equal(0);
a[2].should.equal(0);
a[3].should.equal(1);
});
});
describe('Creating an address from a byte array', () => {
it('should parse correctly from valid byte array', () => {
const topic = Address4.fromByteArray([127, 0, 0, 1]);
topic.correctForm().should.equal('127.0.0.1');
});
it('should parse correctly from different valid byte array', () => {
const topic = Address4.fromByteArray([192, 168, 1, 1]);
topic.correctForm().should.equal('192.168.1.1');
});
it('should handle maximum values correctly', () => {
const topic = Address4.fromByteArray([255, 255, 255, 255]);
topic.correctForm().should.equal('255.255.255.255');
});
it('should throw error for negative bytes', () => {
should.Throw(
() => Address4.fromByteArray([-1, -128, 0, 1]),
'All bytes must be integers between 0 and 255',
);
});
it('should throw error for bytes over 255', () => {
should.Throw(
() => Address4.fromByteArray([256, 0, 0, 1]),
'All bytes must be integers between 0 and 255',
);
});
it('should throw error for non-integer bytes', () => {
should.Throw(
() => Address4.fromByteArray([127.5, 0, 0, 1]),
'All bytes must be integers between 0 and 255',
);
});
it('should throw error for array with wrong length', () => {
should.Throw(
() => Address4.fromByteArray([127, 0, 0]),
'IPv4 addresses require exactly 4 bytes',
);
should.Throw(
() => Address4.fromByteArray([127, 0, 0, 1, 2]),
'IPv4 addresses require exactly 4 bytes',
);
should.Throw(() => Address4.fromByteArray([]), 'IPv4 addresses require exactly 4 bytes');
});
});
describe('Creating an address from an unsigned byte array', () => {
it('should parse correctly', () => {
const topic = Address4.fromUnsignedByteArray([127, 0, 0, 1]);
topic.correctForm().should.equal('127.0.0.1');
});
it('should throw error for array with wrong length', () => {
should.Throw(
() => Address4.fromUnsignedByteArray([127, 0, 0]),
'IPv4 addresses require exactly 4 bytes',
);
should.Throw(
() => Address4.fromUnsignedByteArray([127, 0, 0, 1, 2]),
'IPv4 addresses require exactly 4 bytes',
);
});
});
describe('A different notation of the same address', () => {
const addresses = notationsToAddresseses(['127.0.0.1/32', '127.0.0.1']);
it('is parsed to the same result', () => {
addresses.forEach((topic) => {
should.equal(topic.correctForm(), '127.0.0.1');
should.equal(topic.subnetMask, 32);
});
});
it('does not treat a zero-padded notation as the same address', () => {
// A leading zero is octal to every resolver, so these are not
// alternative spellings of 127.0.0.1 and are rejected outright.
['127.000.000.001/32', '127.000.000.001', '127.000.0.1'].forEach((notation) => {
should.equal(Address4.isValid(notation), false, notation);
});
});
});
describe('A multicast address', () => {
const multicastAddresses = notationsToAddresseses([
'224.0.1.0',
'224.0.1.255',
'224.0.2.0',
'224.0.255.255',
'224.3.0.0',
'224.4.255.255',
'232.0.0.0',
'232.255.255.255',
'233.0.0.0',
'233.251.255.255',
'233.252.0.0',
'233.255.255.255',
'234.0.0.0',
'234.255.255.255',
'239.0.0.0',
'239.255.255.255',
]);
it('is detected as multicast', () => {
multicastAddresses.forEach((topic) => {
should.equal(topic.isMulticast(), true);
});
});
});
describe('A unicast address', () => {
const unicastAddresses = notationsToAddresseses([
'124.0.1.0',
'124.0.1.255',
'124.0.2.0',
'124.0.255.255',
'124.3.0.0',
'124.4.255.255',
'132.0.0.0',
'132.255.255.255',
'133.0.0.0',
'133.251.255.255',
'133.252.0.0',
'133.255.255.255',
'134.0.0.0',
'134.255.255.255',
'139.0.0.0',
'139.255.255.255',
]);
it('is not detected as multicast', () => {
unicastAddresses.forEach((topic) => {
should.equal(topic.isMulticast(), false);
});
});
});
describe('isPrivate', () => {
it('detects RFC 1918 ranges', () => {
notationsToAddresseses([
'10.0.0.0',
'10.255.255.255',
'172.16.0.0',
'172.16.0.1',
'172.31.255.255',
'192.168.0.0',
'192.168.1.1',
'192.168.255.255',
]).forEach((topic) => {
should.equal(topic.isPrivate(), true);
});
});
it('rejects non-private addresses including range boundaries', () => {
notationsToAddresseses([
'8.8.8.8',
'9.255.255.255',
'11.0.0.0',
'172.15.255.255',
'172.32.0.0',
'192.167.255.255',
'192.169.0.0',
]).forEach((topic) => {
should.equal(topic.isPrivate(), false);
});
});
});
describe('isLoopback', () => {
it('detects 127.0.0.0/8', () => {
notationsToAddresseses(['127.0.0.0', '127.0.0.1', '127.255.255.255']).forEach((topic) => {
should.equal(topic.isLoopback(), true);
});
});
it('rejects non-loopback addresses', () => {
notationsToAddresseses(['126.255.255.255', '128.0.0.0', '8.8.8.8']).forEach((topic) => {
should.equal(topic.isLoopback(), false);
});
});
});
describe('isLinkLocal', () => {
it('detects 169.254.0.0/16', () => {
notationsToAddresseses(['169.254.0.0', '169.254.1.1', '169.254.255.255']).forEach(
(topic) => {
should.equal(topic.isLinkLocal(), true);
},
);
});
it('rejects addresses outside 169.254.0.0/16', () => {
notationsToAddresseses(['169.253.255.255', '169.255.0.0', '8.8.8.8']).forEach((topic) => {
should.equal(topic.isLinkLocal(), false);
});
});
});
describe('isUnspecified', () => {
it('detects 0.0.0.0', () => {
should.equal(new Address4('0.0.0.0').isUnspecified(), true);
});
it('rejects non-zero addresses', () => {
notationsToAddresseses(['0.0.0.1', '1.0.0.0', '8.8.8.8']).forEach((topic) => {
should.equal(topic.isUnspecified(), false);
});
});
});
describe('isBroadcast', () => {
it('detects 255.255.255.255', () => {
should.equal(new Address4('255.255.255.255').isBroadcast(), true);
});
it('rejects non-broadcast addresses including subnet broadcasts', () => {
notationsToAddresseses(['255.255.255.254', '192.168.1.255', '8.8.8.8']).forEach((topic) => {
should.equal(topic.isBroadcast(), false);
});
});
});
describe('isCGNAT', () => {
it('detects 100.64.0.0/10', () => {
notationsToAddresseses(['100.64.0.0', '100.64.0.1', '100.127.255.255']).forEach((topic) => {
should.equal(topic.isCGNAT(), true);
});
});
it('rejects addresses outside 100.64.0.0/10', () => {
notationsToAddresseses(['100.63.255.255', '100.128.0.0', '8.8.8.8']).forEach((topic) => {
should.equal(topic.isCGNAT(), false);
});
});
});
describe('offset', () => {
it('moves by n and keeps the subnet mask', () => {
should.equal(new Address4('10.0.0.0/24').offset(1).correctForm(), '10.0.0.1');
should.equal(new Address4('10.0.0.0/24').offset(1).subnetMask, 24);
should.equal(new Address4('10.0.0.0/24').offset(256).correctForm(), '10.0.1.0');
should.equal(new Address4('10.0.1.0').offset(-1).correctForm(), '10.0.0.255');
should.equal(
new Address4('0.0.0.0').offset(BigInt(2 ** 32 - 1)).correctForm(),
'255.255.255.255',
);
should.equal(new Address4('1.2.3.4').offset(0).correctForm(), '1.2.3.4');
});
it('rejects leaving the address space or a non-integer n', () => {
should.Throw(() => new Address4('255.255.255.255').offset(1), AddressError);
should.Throw(() => new Address4('0.0.0.0').offset(-1), AddressError);
should.Throw(() => new Address4('1.2.3.4').offset(1.5), AddressError);
should.Throw(() => new Address4('1.2.3.4').offset(NaN), AddressError);
should.Throw(() => new Address4('1.2.3.4').offset(Infinity), AddressError);
should.Throw(() => new Address4('1.2.3.4').offset(2 ** 53), AddressError);
should.Throw(() => new Address4('1.2.3.4').offset('1' as never), AddressError);
});
});
describe('nextNetwork', () => {
it('returns the network after this one with the same mask', () => {
should.equal(new Address4('10.0.0.0/24').nextNetwork().networkForm(), '10.0.1.0/24');
should.equal(new Address4('10.0.0.77/24').nextNetwork().networkForm(), '10.0.1.0/24');
should.equal(new Address4('10.0.0.0/8').nextNetwork().networkForm(), '11.0.0.0/8');
should.equal(new Address4('1.2.3.4').nextNetwork().correctForm(), '1.2.3.5');
});
it('rejects the last network in the address space', () => {
should.Throw(() => new Address4('255.255.255.0/24').nextNetwork(), AddressError);
should.Throw(() => new Address4('0.0.0.0/0').nextNetwork(), AddressError);
});
});
describe('isDocumentation', () => {
it('detects the three RFC 5737 ranges', () => {
notationsToAddresseses([
'192.0.2.0',
'192.0.2.255',
'198.51.100.1',
'203.0.113.254',
]).forEach((topic) => {
should.equal(topic.isDocumentation(), true, topic.address);
});
});
it('rejects their neighbors', () => {
notationsToAddresseses(['192.0.1.255', '192.0.3.0', '198.51.99.255', '203.0.114.0']).forEach(
(topic) => {
should.equal(topic.isDocumentation(), false, topic.address);
},
);
});
});
describe('isBenchmarking', () => {
it('detects 198.18.0.0/15 and rejects its neighbors', () => {
should.equal(new Address4('198.18.0.0').isBenchmarking(), true);
should.equal(new Address4('198.19.255.255').isBenchmarking(), true);
should.equal(new Address4('198.17.255.255').isBenchmarking(), false);
should.equal(new Address4('198.20.0.0').isBenchmarking(), false);
});
});
describe('isReserved', () => {
it('detects 240.0.0.0/4 including limited broadcast', () => {
should.equal(new Address4('240.0.0.0').isReserved(), true);
should.equal(new Address4('255.255.255.254').isReserved(), true);
should.equal(new Address4('255.255.255.255').isReserved(), true);
should.equal(new Address4('239.255.255.255').isReserved(), false);
});
});
describe('isGlobal', () => {
it('is false for every special-purpose block, named or not', () => {
notationsToAddresseses([
'0.0.0.1', // "this network", only 0.0.0.0 has a classifier
'10.0.0.1',
'100.64.0.1',
'127.0.0.1',
'169.254.169.254',
'172.16.0.1',
'192.0.0.1', // IETF protocol assignments
'192.0.0.170', // NAT64/DNS64 discovery
'192.0.2.1',
'192.88.99.2', // 6a44 relay anycast
'192.168.0.1',
'198.18.0.1',
'198.51.100.1',
'203.0.113.1',
'224.0.0.1', // multicast
'240.0.0.1',
'255.255.255.255',
]).forEach((topic) => {
should.equal(topic.isGlobal(), false, topic.address);
});
});
it('honors the registry entries that are globally reachable inside a non-reachable block', () => {
should.equal(new Address4('192.0.0.9').isGlobal(), true); // PCP anycast
should.equal(new Address4('192.0.0.10').isGlobal(), true); // TURN anycast
should.equal(new Address4('192.0.0.8').isGlobal(), false);
should.equal(new Address4('192.0.0.11').isGlobal(), false);
});
it('is true for ordinary addresses and the deprecated 6to4 relay block', () => {
notationsToAddresseses([
'1.1.1.1',
'8.8.8.8',
'192.88.99.1',
'192.31.196.1',
'11.0.0.0',
]).forEach((topic) => {
should.equal(topic.isGlobal(), true, topic.address);
});
});
it('ignores the address own subnet mask', () => {
should.equal(new Address4('127.0.0.1/0').isGlobal(), false);
should.equal(new Address4('8.8.8.8/0').isGlobal(), true);
});
});
describe('classification ignores the address own subnet mask', () => {
// A classifier answers a question about the address, so a CIDR suffix on
// the input must not change the answer. Suffixes shorter than the
// reference range's prefix are the interesting case.
const cases: [
string,
(
| 'isLoopback'
| 'isPrivate'
| 'isLinkLocal'
| 'isCGNAT'
| 'isUnspecified'
| 'isBroadcast'
| 'isMulticast'
),
][] = [
['127.0.0.1', 'isLoopback'],
['10.0.0.1', 'isPrivate'],
['172.16.5.5', 'isPrivate'],
['192.168.1.1', 'isPrivate'],
['169.254.169.254', 'isLinkLocal'],
['100.64.0.1', 'isCGNAT'],
['0.0.0.0', 'isUnspecified'],
['255.255.255.255', 'isBroadcast'],
['224.0.0.1', 'isMulticast'],
];
it('classifies the host identically with and without a /0 suffix', () => {
cases.forEach(([notation, method]) => {
should.equal(new Address4(notation)[method](), true, `${notation} ${method}`);
should.equal(new Address4(`${notation}/0`)[method](), true, `${notation}/0 ${method}`);
});
});
it('classifies the host identically for every prefix length', () => {
for (let prefix = 0; prefix <= 32; prefix++) {
should.equal(new Address4(`127.0.0.1/${prefix}`).isLoopback(), true, `/${prefix}`);
should.equal(new Address4(`10.0.0.5/${prefix}`).isPrivate(), true, `/${prefix}`);
should.equal(new Address4(`169.254.169.254/${prefix}`).isLinkLocal(), true, `/${prefix}`);
}
});
it('does not start misclassifying public addresses', () => {
for (let prefix = 0; prefix <= 32; prefix++) {
should.equal(new Address4(`8.8.8.8/${prefix}`).isLoopback(), false, `/${prefix}`);
should.equal(new Address4(`8.8.8.8/${prefix}`).isPrivate(), false, `/${prefix}`);
should.equal(new Address4(`8.8.8.8/${prefix}`).isLinkLocal(), false, `/${prefix}`);
should.equal(new Address4(`8.8.8.8/${prefix}`).isCGNAT(), false, `/${prefix}`);
}
});
});
describe('isInSubnet retains subnet-containment semantics', () => {
// isInSubnet answers "is my network inside yours", which is a different
// question from classification and must keep rejecting wider networks.
it('reports a wider network as not contained in a narrower one', () => {
should.equal(new Address4('127.0.0.1/0').isInSubnet(new Address4('127.0.0.0/8')), false);
should.equal(new Address4('10.0.0.0/8').isInSubnet(new Address4('10.0.0.0/16')), false);
});
it('still reports genuine containment', () => {
should.equal(new Address4('10.1.0.0/16').isInSubnet(new Address4('10.0.0.0/8')), true);
should.equal(new Address4('127.0.0.1/32').isInSubnet(new Address4('127.0.0.0/8')), true);
should.equal(new Address4('11.0.0.0/16').isInSubnet(new Address4('10.0.0.0/8')), false);
});
});
describe('fromArpa', () => {
it('reverses the octets of an in-addr.arpa name', () => {
should.equal(Address4.fromArpa('42.2.0.192.in-addr.arpa.').correctForm(), '192.0.2.42');
should.equal(Address4.fromArpa('42.2.0.192').correctForm(), '192.0.2.42');
});
it('accepts the suffix with or without the root dot, as Address6.fromArpa does', () => {
should.equal(Address4.fromArpa('42.2.0.192.in-addr.arpa').correctForm(), '192.0.2.42');
should.equal(Address4.fromArpa('42.2.0.192.').correctForm(), '192.0.2.42');
});
it('accepts the suffix in any case, as DNS does', () => {
should.equal(Address4.fromArpa('42.2.0.192.IN-ADDR.ARPA.').correctForm(), '192.0.2.42');
should.equal(Address4.fromArpa('42.2.0.192.In-Addr.Arpa').correctForm(), '192.0.2.42');
});
it('round-trips reverseForm for a host and a network', () => {
['192.0.2.42', '192.0.2.0/24', '10.0.0.0/8'].forEach((n) => {
const address = new Address4(n);
should.equal(
Address4.fromArpa(address.reverseForm()).correctForm(),
address.correctForm(),
n,
);
});
});
it('rejects a name whose labels are not four octets', () => {
[
'',
'.',
'in-addr.arpa.',
'a.b.c.d.',
'1.0.127.',
'1.0.0.0.127.',
'1.0.0.127.ip6.arpa.',
].forEach((s) => {
should.Throw(() => Address4.fromArpa(s), AddressError, undefined, JSON.stringify(s));
});
});
describe('input length', () => {
// A 15-character address, a "/32" prefix length on its last octet (the
// RFC 2317 classless form) and ".in-addr.arpa.": the longest name is 32
// characters. Anything longer is rejected before its labels are split.
const longest = '255/32.255.255.255.in-addr.arpa.';
it('accepts the longest name', () => {
longest.length.should.equal(32);
should.equal(Address4.fromArpa(longest).correctForm(), '255.255.255.255');
should.equal(Address4.fromArpa(longest).subnet, '/32');
should.equal(Address4.fromArpa('0/25.2.0.192.in-addr.arpa.').subnet, '/25');
});
it('rejects a longer name', () => {
const inputs = [`${longest}.`, `1${longest}`, '1.'.repeat(17), '.'.repeat(1 << 20)];
for (const input of inputs) {
should.Throw(() => Address4.fromArpa(input), AddressError, /at most 32 characters/);
}
});
});
});
describe('octets with a leading zero', () => {
// A leading zero is octal to the WHATWG URL parser, inet_aton, and
// getaddrinfo, and decimal to parseInt(part, 10). Accepting the notation
// means the library and the network stack disagree about which host a
// string names, so it is rejected outright. Address6 already rejects it
// on the v4-in-v6 path.
const ambiguous = [
'012.0.0.1',
'010.0.0.1',
'012.012.012.012',
'127.0.0.01',
'00.0.0.1',
'0.0.0.01',
'001.002.003.004',
];
it('are rejected by isValid', () => {
ambiguous.forEach((notation) => {
should.equal(Address4.isValid(notation), false, notation);
});
});
it('throw from the constructor', () => {
ambiguous.forEach((notation) => {
should.Throw(() => new Address4(notation), AddressError, undefined, notation);
});
});
it('are rejected with a subnet suffix too', () => {
should.equal(Address4.isValid('012.0.0.1/24'), false);
should.Throw(() => new Address4('010.0.0.0/8'), AddressError);
});
it('still accept a bare zero octet', () => {
['0.0.0.0', '0.0.0.1', '10.0.0.0', '192.168.0.1', '255.255.255.255'].forEach((notation) => {
should.equal(Address4.isValid(notation), true, notation);
should.equal(new Address4(notation).correctForm(), notation, notation);
});
});
it('no longer let an octal-ambiguous host read as public', () => {
// 012.0.0.1 resolves to 10.0.0.1, so a guard must not see it as public.
should.equal(Address4.isValid('012.0.0.1'), false);
should.equal(Address4.isValid('012.012.012.012'), false);
});
});
});
beaugunderson-ip-address-438375e/test/functionality-v6-test.ts 0000664 0000000 0000000 00000247377 15272410673 0024450 0 ustar 00root root 0000000 0000000 import * as chai from 'chai';
import { Address4 } from '../src/ipv4';
import { Address6 } from '../src/ipv6';
import { AddressError } from '../src/address-error';
import { v6 } from '../src/ip-address';
const { expect } = chai;
const should = chai.should();
// A convenience function to convert a list of IPv6 address notations
// to Address6 instances
function notationsToAddresseses(notations: string[]): Address6[] {
return notations.map((notation) => new Address6(notation));
}
describe('v6', () => {
describe('An invalid address', () => {
it('is invalid', () => {
should.Throw(() => new Address6('a:abcde::'));
should.equal(Address6.isValid('a:abcde::'), false);
});
});
describe('input length', () => {
// Six four-digit groups, six colons, and a dotted quad: the longest
// well-formed address is 45 characters, and CPython's ipaddress module
// draws the same line. Anything longer is rejected before the parser
// builds a diagnostic, since the bad-character diagnostic wraps every
// offending character in a span and an unbounded input made that
// allocation unbounded too.
const longest = 'ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255';
it('accepts the longest well-formed address, with a suffix and a zone', () => {
longest.length.should.equal(45);
should.equal(Address6.isValid(longest), true);
should.equal(Address6.isValid(`${longest}/128`), true);
should.equal(Address6.isValid(`${longest}%eth0`), true);
should.equal(Address6.isValid(`${longest}/128%eth0`), true);
should.equal(Address6.isValid(`2001:db8::1%${'x'.repeat(100)}`), true);
});
it('takes a zone from the first % and rejects a line terminator in it', () => {
new Address6('fe80::1%a%b').zone.should.equal('%a%b');
new Address6('fe80::1%').zone.should.equal('%');
for (const terminator of [
'\n',
'\r',
String.fromCharCode(0x2028),
String.fromCharCode(0x2029),
]) {
should.equal(Address6.isValid(`fe80::1%eth0${terminator}`), false);
should.equal(Address6.isValid(`fe80::1%a${terminator}b%c`), false);
}
});
it('rejects a longer address without building a diagnostic', () => {
const inputs = [
'f'.repeat(46),
`${'f'.repeat(46)}/64`,
'!'.repeat(1 << 20),
// A line terminator keeps a `%` from starting a zone, so every one of
// these is a candidate zone start that fails.
`${'%'.repeat(1 << 17)}\n`,
];
for (const input of inputs) {
should.equal(Address6.isValid(input), false);
should.Throw(() => new Address6(input), AddressError, /at most 45 characters/);
try {
// eslint-disable-next-line no-new
new Address6(input);
} catch (e) {
should.equal((e as AddressError).parseMessage, undefined);
(e as AddressError).message.length.should.be.below(100);
}
}
});
});
describe('non-ASCII digits', () => {
// The WHATWG URL parser maps fullwidth characters to ASCII, so a parser
// that read them as hex or decimal would agree with it on the address
// while a raw string comparison disagreed: the shape of Node's
// CVE-2026-105483 TLS hostname bypass. Every entry point rejects them.
const fullwidth = (s: string) =>
s.replace(/[!-~]/g, (c) => String.fromCharCode(c.charCodeAt(0) + 0xfee0));
const digitsFrom = (zero: number) => (s: string) =>
s.replace(/[0-9]/g, (d) => String.fromCharCode(zero + Number(d)));
// Each ASCII input parses, so a rejected variant is rejected for its
// Unicode, not for its shape. The zone is left out of the per-character
// swaps because it is opaque text (see the test below).
const inputs = ['::1', '2001:db8::1', '2001:db8::/32', '::ffff:127.0.0.1', 'fe80::1%eth0'];
const variantsOf = (s: string) => {
const zoneStart = s.indexOf('%');
const end = zoneStart === -1 ? s.length : zoneStart;
const variants = [
fullwidth(s),
// Arabic-Indic and Devanagari digits
digitsFrom(0x0660)(s.slice(0, end)) + s.slice(end),
digitsFrom(0x0966)(s.slice(0, end)) + s.slice(end),
];
// `%` itself is swapped: a fullwidth `%` must not start a zone
for (let i = 0; i <= Math.min(end, s.length - 1); i++) {
variants.push(s.slice(0, i) + fullwidth(s[i]) + s.slice(i + 1));
}
return variants.filter((variant) => variant !== s);
};
it('rejects them in an address, subnet, or embedded IPv4 address', () => {
for (const input of inputs) {
should.equal(Address6.isValid(input), true);
for (const variant of variantsOf(input)) {
should.equal(Address6.isValid(variant), false, variant);
should.Throw(() => new Address6(variant), AddressError);
}
}
});
it('rejects them in a URL host or port', () => {
Address6.fromURL('http://[2001:db8::1]:80/').port!.should.equal(80);
for (const url of [
`http://[${fullwidth('2001:db8::1')}]/`,
`http://[2001:db8::${fullwidth('1')}]:80/`,
`http://[2001:db8::1]:${fullwidth('80')}/`,
`http://[2001:db8::1]:8${fullwidth('0')}/`,
`http://${fullwidth('2001:db8::1')}/`,
]) {
should.equal(Address6.fromURL(url).address, null, url);
}
});
it('rejects them in arpa and IPv4 forms', () => {
const arpa = '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.';
Address6.fromArpa(arpa).correctForm().should.equal('2001:db8::1');
should.Throw(() => Address6.fromArpa(fullwidth('1') + arpa.slice(1)), AddressError);
Address6.fromAddress4('127.0.0.1').correctForm().should.equal('::ffff:7f00:1');
should.Throw(() => Address6.fromAddress4(fullwidth('127.0.0.1')), AddressError);
should.Throw(() => Address6.fromAddress4(`127.0.0.${fullwidth('1')}`), AddressError);
Address6.fromAddress4Nat64('192.0.2.1').correctForm().should.equal('64:ff9b::c000:201');
should.Throw(() => Address6.fromAddress4Nat64(`192.0.2.${fullwidth('1')}`), AddressError);
should.Throw(() => Address6.fromAddress4Nat64('192.0.2.1', fullwidth('64:ff9b::/96')));
should.Throw(() => Address6.fromAddress4Nat64('192.0.2.1', `64:ff9b::/9${fullwidth('6')}`));
});
it('rejects them in mask and wildcard forms', () => {
Address6.fromAddressAndMask('fe80::1', 'ffff:ffff:ffff:ffff::').subnet.should.equal('/64');
should.Throw(() =>
Address6.fromAddressAndMask(fullwidth('fe80::1'), 'ffff:ffff:ffff:ffff::'),
);
should.Throw(() =>
Address6.fromAddressAndMask('fe80::1', fullwidth('ffff:ffff:ffff:ffff::')),
);
const wildcardMask = '::ffff:ffff:ffff:ffff';
Address6.fromAddressAndWildcardMask('fe80::1', wildcardMask).subnet.should.equal('/64');
should.Throw(() => Address6.fromAddressAndWildcardMask(fullwidth('fe80::1'), wildcardMask));
should.Throw(() => Address6.fromAddressAndWildcardMask('fe80::1', fullwidth(wildcardMask)));
Address6.fromWildcard('2001:db8::*').subnet.should.equal('/112');
should.Throw(() => Address6.fromWildcard(`2001:db${fullwidth('8')}::*`), AddressError);
should.Throw(() => Address6.fromWildcard(`2001:db8::${fullwidth('*')}`), AddressError);
should.Throw(() => Address6.fromWildcard(`2001:db8${fullwidth('::')}*`), AddressError);
});
it('keeps them in a zone as opaque text', () => {
const address = new Address6(`fe80::1%eth${fullwidth('0')}`);
address.zone.should.equal(`%eth${fullwidth('0')}`);
address.correctForm().should.equal('fe80::1');
});
});
describe('a fully ellided /0 address', () => {
const topic = new Address6('::/0');
it('gets the correct reverse from', () => {
topic.reverseForm({ omitSuffix: true }).should.equal('');
topic.reverseForm().should.equal('ip6.arpa.');
});
});
describe('An address with an unknown scope', () => {
const topic = new Address6('ff03::1');
it('should return Unknown scope', () => {
topic.getScope().should.equal('Unknown');
});
});
describe('getScope', () => {
it('returns the multicast scope nibble for multicast addresses', () => {
new Address6('ff01::1').getScope().should.equal('Interface local');
new Address6('ff02::1').getScope().should.equal('Link local');
new Address6('ff04::1').getScope().should.equal('Admin local');
new Address6('ff05::2').getScope().should.equal('Site local');
new Address6('ff08::1').getScope().should.equal('Organization local');
new Address6('ff0e::1').getScope().should.equal('Global');
});
it('returns Link local for fe80::/10 (issue #122)', () => {
new Address6('fe80::2ff:33ff:feaa:bbcc').getScope().should.equal('Link local');
});
it('does not return Link local for 2002::/16 (issue #122)', () => {
new Address6('2002::').getScope().should.equal('Global');
});
it('returns Link local for the loopback address (RFC 4291 §2.5.3)', () => {
new Address6('::1').getScope().should.equal('Link local');
});
it('returns Global for ULA, documentation, 6to4, and ordinary unicast', () => {
new Address6('fd12:3456:789a::1').getScope().should.equal('Global');
new Address6('2001:db8::1').getScope().should.equal('Global');
new Address6('2002:c0a8:1::').getScope().should.equal('Global');
new Address6('2620:0:2d0:200::7').getScope().should.equal('Global');
});
it('returns Unknown for the unspecified address', () => {
new Address6('::').getScope().should.equal('Unknown');
});
});
describe('getType', () => {
it('classifies ULA addresses as Unique local', () => {
new Address6('fc00::').getType().should.equal('Unique local');
new Address6('fd12:3456:789a::1').getType().should.equal('Unique local');
});
it('classifies 2002::/16 as 6to4', () => {
new Address6('2002:c0a8:1::').getType().should.equal('6to4');
});
it('classifies 2001:db8::/32 as Documentation', () => {
new Address6('2001:db8::1').getType().should.equal('Documentation');
});
it('classifies the well-known NAT64 prefix', () => {
new Address6('64:ff9b::c000:221').getType().should.equal('NAT64 (well-known)');
});
it('classifies the local-use NAT64 prefix', () => {
new Address6('64:ff9b:1::1').getType().should.equal('NAT64 (local-use)');
});
});
describe('isMulticast', () => {
it('returns true for any multicast address, including specific subtypes', () => {
['ff00::', 'ff01::1', 'ff02::1', 'ff05::2', 'ff0e::1'].forEach((notation) => {
new Address6(notation).isMulticast().should.equal(true);
});
});
it('returns false for non-multicast addresses', () => {
['::', '::1', '2001:db8::1', 'fe80::1', 'fd00::1'].forEach((notation) => {
new Address6(notation).isMulticast().should.equal(false);
});
});
});
describe('A link local address', () => {
const topic = new Address6('fe80::baf6:b1ff:fe15:4885');
it('gets the correct type', () => {
topic.getType().should.equal('Link-local unicast');
topic.isTeredo().should.equal(false);
topic.isLoopback().should.equal(false);
topic.isMulticast().should.equal(false);
topic.isLinkLocal().should.equal(true);
});
});
describe('A correct address', () => {
const topic = new Address6('a:b:c:d:e:f:0:1/64');
it('contains no uppercase letters', () => {
/[A-Z]/.test(topic.address).should.equal(false);
});
it('validates as correct', () => {
topic.isCorrect().should.equal(true);
should.equal(topic.correctForm(), 'a:b:c:d:e:f:0:1');
should.equal(Address6.isValid('a:b:c:d:e:f:0:1'), true);
});
it('converts to and from a signed byte array', () => {
const bytes = topic.toByteArray();
const address = Address6.fromByteArray(bytes);
address.correctForm().should.equal(topic.correctForm());
});
it('converts to and from an unsigned byte array', () => {
const unsignedBytes = topic.toUnsignedByteArray();
const address = Address6.fromUnsignedByteArray(unsignedBytes);
address.correctForm().should.equal(topic.correctForm());
});
it('gets the correct type', () => {
topic.getType().should.equal('Global unicast');
topic.isTeredo().should.equal(false);
topic.isLoopback().should.equal(false);
topic.isMulticast().should.equal(false);
topic.isLinkLocal().should.equal(false);
});
it('gets the correct reverse from', () => {
topic.reverseForm({ omitSuffix: true }).should.equal('d.0.0.0.c.0.0.0.b.0.0.0.a.0.0.0');
topic.reverseForm().should.equal('d.0.0.0.c.0.0.0.b.0.0.0.a.0.0.0.ip6.arpa.');
});
it('gets the correct scope', () => {
topic.getScope().should.equal('Global');
});
it('gets the correct is6to4 information', () => {
topic.is6to4().should.equal(false);
});
it('gets the correct microsoft transcription', () => {
topic.microsoftTranscription().should.equal('a-b-c-d-e-f-0-1.ipv6-literal.net');
});
it('has correct bit information', () => {
topic
.getBitsPastSubnet()
.should.equal('0000000000001110000000000000111100000000000000000000000000000001');
topic.getBitsBase16(0, 64).should.equal('000a000b000c000d');
topic.getBitsBase16(0, 128).should.equal('000a000b000c000d000e000f00000001');
should.Throw(() => topic.getBitsBase16(0, 127));
topic
.binaryZeroPad()
.should.equal(
'0000000000001010000000000000101100000000000011000000000000001101' +
'0000000000001110000000000000111100000000000000000000000000000001',
);
});
});
describe('An address with a subnet', () => {
const topic = new Address6('ffff::/64');
it('is contained by an identical address with an identical subnet', () => {
const same = new Address6('ffff::/64');
topic.isInSubnet(same).should.equal(true);
});
it('has a correct start address', () => {
should.equal(topic.startAddress().correctForm(), 'ffff::');
});
it('has a correct start address hosts only', () => {
should.equal(topic.startAddressExclusive().correctForm(), 'ffff::1');
});
it('has a correct end address', () => {
should.equal(topic.endAddress().correctForm(), 'ffff::ffff:ffff:ffff:ffff');
});
it('has a correct end address hosts only', () => {
should.equal(topic.endAddressExclusive().correctForm(), 'ffff::ffff:ffff:ffff:fffe');
});
it('has a correct subnet mask address', () => {
should.equal(topic.subnetMaskAddress().correctForm(), 'ffff:ffff:ffff:ffff::');
});
it('calculates and formats the subnet size', () => {
topic.possibleSubnets().should.equal('18,446,744,073,709,551,616');
topic.possibleSubnets(128).should.equal('18,446,744,073,709,551,616');
topic.possibleSubnets(96).should.equal('4,294,967,296');
topic.possibleSubnets(65).should.equal('2');
topic.possibleSubnets(64).should.equal('1');
topic.possibleSubnets(63).should.equal('0');
topic.possibleSubnets(0).should.equal('0');
});
});
describe('Small subnets', () => {
const topic = new Address6('ffff::/64');
it('is contained by larger subnets', () => {
for (let i = 63; i > 0; i--) {
const larger = new Address6(`ffff::/${i}`);
topic.isInSubnet(larger).should.equal(true);
}
});
});
describe('Large subnets', () => {
const topic = new Address6('ffff::/8');
it('is not contained by smaller subnets', () => {
for (let i = 9; i <= 128; i++) {
const smaller = new Address6(`ffff::/${i}`);
topic.isInSubnet(smaller).should.equal(false);
}
});
});
describe('A canonical address', () => {
const topic = new Address6('000a:0000:0000:0000:0000:0000:0000:000b');
it('is 39 characters long', () => {
should.equal(topic.address.length, 39);
});
it('validates as canonical', () => {
topic.isCanonical().should.equal(true);
should.equal(topic.canonicalForm(), '000a:0000:0000:0000:0000:0000:0000:000b');
});
});
describe('A v4-in-v6 address', () => {
const topic = new Address6('::192.168.0.1');
it('is v4', () => {
topic.is4().should.equal(true);
});
});
describe('An address with a subnet', () => {
const topic = new Address6('a:b::/48');
it('parses the subnet', () => {
should.equal(topic.subnet, '/48');
});
it('is in its own subnet', () => {
topic.isInSubnet(new Address6('a:b::/48')).should.equal(true);
});
it('is not in another subnet', () => {
topic.isInSubnet(new Address6('a:c::/48')).should.equal(false);
});
});
describe('An address with a zone', () => {
const topic = new Address6('a::b%abcdefg');
it('parses the zone', () => {
should.equal(topic.zone, '%abcdefg');
});
});
describe('group() with a zone containing HTML characters', () => {
const payload = 'fe80::1%';
const topic = new Address6(payload);
it('stores the raw zone on the instance', () => {
should.equal(topic.zone, '%');
});
it('does not include the zone in the grouped HTML output', () => {
const html = topic.group();
html.should.not.include('');
});
it('does not include the zone in the non-elided grouped HTML output', () => {
const nonElided = new Address6('a:b:c:d:1:2:3:4%');
const html = nonElided.group();
html.should.not.include('');
});
});
describe('link() with options containing HTML characters', () => {
const topic = new Address6('2001:db8::1');
it('escapes the className', () => {
const html = topic.link({ className: 'a"b' });
html.should.include('class="a"b"');
});
it('escapes the prefix', () => {
const html = topic.link({ prefix: 'a"b' });
html.should.include('href="a"b');
});
});
describe('parse4in6 leading-zero error', () => {
it('highlights the offending IPv4 octet in parseMessage', () => {
try {
// eslint-disable-next-line no-new
new Address6('::ffff:10.0.01.1');
throw new Error('expected Address6 constructor to throw');
} catch (e) {
(e as any).parseMessage.should.include('0');
(e as any).parseMessage.should.include('::ffff:');
}
});
it('escapes HTML characters in the prefix', () => {
try {
// eslint-disable-next-line no-new
new Address6(':10.0.01.1');
throw new Error('expected Address6 constructor to throw');
} catch (e) {
const { parseMessage } = e as any;
parseMessage.should.not.include('');
parseMessage.should.include('<b>');
}
});
});
describe('bad-character error', () => {
it('highlights each offending character in parseMessage', () => {
try {
// eslint-disable-next-line no-new
new Address6('2001:db8::g1');
throw new Error('expected Address6 constructor to throw');
} catch (e) {
(e as any).parseMessage.should.equal('2001:db8::g1');
}
});
it('escapes HTML characters in the highlighted characters', () => {
try {
// eslint-disable-next-line no-new
new Address6(`<>&"'::1`);
throw new Error('expected Address6 constructor to throw');
} catch (e) {
(e as any).parseMessage.should.equal(
[
'<',
'>',
'&',
'"',
''',
'::1',
].join(''),
);
}
});
});
describe('A teredo address', () => {
const topic = new Address6('2001:0000:ce49:7601:e866:efff:62c3:fffe');
it('validates as Teredo', () => {
topic.isTeredo().should.equal(true);
});
it('gets the Teredo type', () => {
topic.getType().should.equal('Teredo');
new Address6('2001::1').getType().should.equal('Teredo');
new Address6('2001:1::1').getType().should.equal('Global unicast');
});
it('contains valid Teredo information', () => {
const teredo = topic.inspectTeredo();
should.equal(teredo.prefix, '2001:0000');
should.equal(teredo.server4, '206.73.118.1');
should.equal(teredo.flags, '1110100001100110');
should.equal(teredo.udpPort, '4096');
should.equal(teredo.client4, '157.60.0.1');
should.equal(teredo.coneNat, true);
should.equal(teredo.microsoft.reserved, true);
should.equal(teredo.microsoft.universalLocal, false);
should.equal(teredo.microsoft.groupIndividual, false);
should.equal(teredo.microsoft.nonce, '2662');
});
it('reads each Teredo flag from its own bit', () => {
const cone = new Address6('2001:0:4136:e378:8000:63bf:3fff:fdd2').inspectTeredo();
should.equal(cone.coneNat, true);
should.equal(cone.microsoft.reserved, false);
const reserved = new Address6('2001:0:4136:e378:4000:63bf:3fff:fdd2').inspectTeredo();
should.equal(reserved.coneNat, false);
should.equal(reserved.microsoft.reserved, true);
const universalLocal = new Address6('2001:0:4136:e378:0200:63bf:3fff:fdd2').inspectTeredo();
should.equal(universalLocal.microsoft.universalLocal, true);
should.equal(universalLocal.microsoft.groupIndividual, false);
const groupIndividual = new Address6('2001:0:4136:e378:0100:63bf:3fff:fdd2').inspectTeredo();
should.equal(groupIndividual.microsoft.universalLocal, false);
should.equal(groupIndividual.microsoft.groupIndividual, true);
});
// Published addresses, each decoded against the flag layout in RFC 5991
// section 3.1: "CRAAAAUG AAAAAAAA", most significant bit first
it('decodes the Wikipedia cone NAT example', () => {
// https://en.wikipedia.org/wiki/Teredo_tunneling
const teredo = new Address6('2001:0000:4136:e378:8000:63bf:3fff:fdd2').inspectTeredo();
should.equal(teredo.prefix, '2001:0000');
should.equal(teredo.server4, '65.54.227.120');
should.equal(teredo.client4, '192.0.2.45');
should.equal(teredo.udpPort, '40000');
should.equal(teredo.flags, '1000000000000000');
should.equal(teredo.coneNat, true);
should.equal(teredo.microsoft.reserved, false);
should.equal(teredo.microsoft.universalLocal, false);
should.equal(teredo.microsoft.groupIndividual, false);
should.equal(teredo.microsoft.nonce, '0');
});
it('decodes the Black Hat 2007 cone NAT example', () => {
// Hoagland, "The Teredo Protocol: Tunneling Past Network Security and
// Other Security Implications", Black Hat USA 2007
const teredo = new Address6('2001::4136:E37E:8000:EEFB:3FFF:DD59').inspectTeredo();
should.equal(teredo.prefix, '2001:0000');
should.equal(teredo.server4, '65.54.227.126');
should.equal(teredo.client4, '192.0.34.166');
should.equal(teredo.udpPort, '4356');
should.equal(teredo.flags, '1000000000000000');
should.equal(teredo.coneNat, true);
should.equal(teredo.microsoft.reserved, false);
should.equal(teredo.microsoft.universalLocal, false);
should.equal(teredo.microsoft.groupIndividual, false);
should.equal(teredo.microsoft.nonce, '0');
});
it('decodes a Windows client address with RFC 5991 random flags', () => {
// ipconfig output posted to https://forums.overclockers.co.uk/threads/teredo.18711529/
// The reserved bit is clear while the bit beside it is set.
const teredo = new Address6('2001:0:9d38:6abd:286b:145e:ade5:1579').inspectTeredo();
should.equal(teredo.prefix, '2001:0000');
should.equal(teredo.server4, '157.56.106.189');
should.equal(teredo.client4, '82.26.234.134');
should.equal(teredo.udpPort, '60321');
should.equal(teredo.flags, '0010100001101011');
should.equal(teredo.coneNat, false);
should.equal(teredo.microsoft.reserved, false);
should.equal(teredo.microsoft.universalLocal, false);
should.equal(teredo.microsoft.groupIndividual, false);
should.equal(teredo.microsoft.nonce, '2667');
});
it('decodes a second Windows client address with RFC 5991 random flags', () => {
// ipconfig output posted to
// https://learn.microsoft.com/en-us/answers/questions/4373830/teredo-tunneling-pseudo-interface-how-to-reinstall
const teredo = new Address6('2001:0:284a:364:140a:f1d6:d204:199d').inspectTeredo();
should.equal(teredo.prefix, '2001:0000');
should.equal(teredo.server4, '40.74.3.100');
should.equal(teredo.client4, '45.251.230.98');
should.equal(teredo.udpPort, '3625');
should.equal(teredo.flags, '0001010000001010');
should.equal(teredo.coneNat, false);
should.equal(teredo.microsoft.reserved, false);
should.equal(teredo.microsoft.universalLocal, false);
should.equal(teredo.microsoft.groupIndividual, false);
should.equal(teredo.microsoft.nonce, '1290');
});
});
describe('A 6to4 address', () => {
const topic = new Address6('2002:ce49:7601:1:2de:adff:febe:eeef');
it('validates as 6to4', () => {
topic.is6to4().should.equal(true);
});
it('contains valid 6to4 information', () => {
const sixToFourProperties = topic.inspect6to4();
should.equal(sixToFourProperties.prefix, '2002');
should.equal(sixToFourProperties.gateway, '206.73.118.1');
});
});
describe('Internal assertions', () => {
it('should throw when group() is called with corrupted elidedGroups', () => {
const topic = new Address6('2001:db8::1');
(topic as any).elidedGroups = undefined;
should.Throw(() => topic.group(), 'Assertion failed.');
});
});
describe('to6to4 on a non-v4 address', () => {
const topic = new Address6('2001:db8::1');
it('should return null', () => {
expect(topic.to6to4()).to.equal(null);
});
});
describe('NAT64 (RFC 6052)', () => {
// Test vectors from RFC 6052 §2.4 (IPv4 192.0.2.33 across all prefix lengths).
const cases: Array<{ pl: number; prefix: string; encoded: string }> = [
{ pl: 32, prefix: '2001:db8::/32', encoded: '2001:db8:c000:221::' },
{ pl: 40, prefix: '2001:db8:100::/40', encoded: '2001:db8:1c0:2:21::' },
{ pl: 48, prefix: '2001:db8:122::/48', encoded: '2001:db8:122:c000:2:2100::' },
{ pl: 56, prefix: '2001:db8:122:300::/56', encoded: '2001:db8:122:3c0:0:221::' },
{ pl: 64, prefix: '2001:db8:122:344::/64', encoded: '2001:db8:122:344:c0:2:2100:0' },
{ pl: 96, prefix: '2001:db8:122:344::/96', encoded: '2001:db8:122:344::c000:221' },
];
cases.forEach(({ pl, prefix, encoded }) => {
it(`encodes 192.0.2.33 with a /${pl} prefix`, () => {
Address6.fromAddress4Nat64('192.0.2.33', prefix).correctForm().should.equal(encoded);
});
it(`decodes ${encoded} with a /${pl} prefix`, () => {
const v4 = new Address6(encoded).toAddress4Nat64(prefix);
should.exist(v4);
v4!.correctForm().should.equal('192.0.2.33');
});
});
it('uses the well-known prefix 64:ff9b::/96 by default', () => {
Address6.fromAddress4Nat64('192.0.2.33').correctForm().should.equal('64:ff9b::c000:221');
new Address6('64:ff9b::c000:221')
.toAddress4Nat64()!
.correctForm()
.should.equal('192.0.2.33');
});
it('encodes the example from issue #72', () => {
Address6.fromAddress4Nat64('127.0.0.1').correctForm().should.equal('64:ff9b::7f00:1');
});
it('returns null when decoding an address outside the prefix', () => {
expect(new Address6('2001:db8::1').toAddress4Nat64()).to.equal(null);
});
it('throws on an invalid prefix length', () => {
should.Throw(() => Address6.fromAddress4Nat64('192.0.2.33', '2001:db8::/80'));
should.Throw(() => new Address6('64:ff9b::1').toAddress4Nat64('2001:db8::/80'));
});
});
describe('A different notation of the same address', () => {
const addresses = notationsToAddresseses([
'2001:db8:0:0:1:0:0:1/128',
'2001:db8:0:0:1:0:0:1/128%eth0',
'2001:db8:0:0:1:0:0:1%eth0',
'2001:db8:0:0:1:0:0:1',
'2001:0db8:0:0:1:0:0:1',
'2001:db8::1:0:0:1',
'2001:db8::0:1:0:0:1',
'2001:0db8::1:0:0:1',
'2001:db8:0:0:1::1',
'2001:db8:0000:0:1::1',
'2001:DB8:0:0:1::1',
]);
it('is parsed to the same result', () => {
addresses.forEach((topic) => {
should.equal(topic.correctForm(), '2001:db8::1:0:0:1');
should.equal(topic.canonicalForm(), '2001:0db8:0000:0000:0001:0000:0000:0001');
should.equal(topic.to4in6(), '2001:db8::1:0:0.0.0.1');
should.equal(topic.decimal(), '08193:03512:00000:00000:00001:00000:00000:00001');
should.equal(
topic.binaryZeroPad(),
'0010000000000001000011011011100000000000000000000000000000000000' +
'0000000000000001000000000000000000000000000000000000000000000001',
);
});
});
});
describe('to4in6', () => {
it('should produce a valid 4in6 address', () => {
const topic1 = new Address6('1:2:3:4:5:6:7:8');
const topic2 = new Address6('1:2:3:4::7:8');
topic1.to4in6().should.equal('1:2:3:4:5:6:0.7.0.8');
topic2.to4in6().should.equal('1:2:3:4::0.7.0.8');
});
});
describe('Address from an IPv4 address', () => {
const obj = Address6.fromAddress4('192.168.0.1/30');
it('should parse correctly', () => {
expect(obj.correctForm()).to.equal('::ffff:c0a8:1');
expect(obj.to4in6()).to.equal('::ffff:192.168.0.1');
expect(obj.subnetMask).to.equal(126);
});
it('should generate a 6to4 address', () => {
expect(obj.to6to4()?.correctForm()).to.equal('2002:c0a8:1::');
});
it('should generate a v4 address', () => {
expect(obj.to4().correctForm()).to.equal('192.168.0.1');
});
it('preserves the subnet on the embedded address4', () => {
expect(obj.address4?.subnetMask).to.equal(30);
expect(obj.address4?.subnet).to.equal('/30');
});
it('round-trips the subnet through to4()', () => {
const v4 = obj.to4();
expect(v4.subnetMask).to.equal(30);
expect(v4.subnet).to.equal('/30');
});
});
describe('to4() subnet derivation', () => {
it('derives /24 from a /120 v4-mapped address', () => {
const mapped = Address6.fromAddress4('192.168.0.1/24');
expect(mapped.subnetMask).to.equal(120);
expect(mapped.to4().subnetMask).to.equal(24);
expect(mapped.to4().subnet).to.equal('/24');
});
it('keeps /32 for an unprefixed v4-mapped address', () => {
expect(new Address6('::ffff:192.168.0.1').to4().subnetMask).to.equal(32);
});
it('keeps /32 when the v6 mask does not cover the v4 portion', () => {
// /64 prefix covers none of the trailing 32 bits — degrade to host.
expect(new Address6('::ffff:192.168.0.1/64').to4().subnetMask).to.equal(32);
});
});
describe('Address given in ap6.arpa form', () => {
const obj = Address6.fromArpa(
'e.f.f.f.3.c.2.6.f.f.f.e.6.6.8.e.1.0.6.7.9.4.e.c.0.0.0.0.1.0.0.2.ip6.arpa.',
);
it('should return an Address6 object', () => {
expect(obj instanceof Address6).to.equal(true);
});
it('should generate a valid v6 address', () => {
expect(obj.correctForm()).to.equal('2001:0:ce49:7601:e866:efff:62c3:fffe');
});
it('should fail with more than 32 nibbles', () => {
should.Throw(() =>
Address6.fromArpa(
'0.e.f.f.f.3.c.2.6.f.f.f.e.6.6.8.e.1.0.6.7.9.4.e.c.0.0.0.0.1.0.0.2.ip6.arpa.',
),
);
});
});
describe('Address inside a URL or inside a URL with a port', () => {
it('should work with a host address', () => {
const obj = Address6.fromURL('2001:db8::5');
expect(obj.address?.address).to.equal('2001:db8::5');
expect(obj.port).to.equal(null);
});
it('should fail with an invalid URL', () => {
const obj = Address6.fromURL('http://zombo/foo');
expect(obj.error).to.equal('failed to parse address from URL');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should work with a basic URL', () => {
const obj = Address6.fromURL('http://2001:db8::5/foo');
expect(obj.address?.address).equal('2001:db8::5');
expect(obj.port).to.equal(null);
});
it('should work with a basic URL enclosed in brackets', () => {
const obj = Address6.fromURL('http://[2001:db8::5]/foo');
expect(obj.address?.address).equal('2001:db8::5');
expect(obj.port).to.equal(null);
});
it('should work with a URL with a port', () => {
const obj = Address6.fromURL('http://[2001:db8::5]:80/foo');
expect(obj.address?.address).to.equal('2001:db8::5');
expect(obj.port).to.equal(80);
});
it('should work with the highest valid port number', () => {
const obj = Address6.fromURL('http://[2001:db8::5]:65535/foo');
expect(obj.address?.address).to.equal('2001:db8::5');
expect(obj.port).to.equal(65535);
});
it('should parse the address but fail with a port number one past the valid range', () => {
const obj = Address6.fromURL('http://[2001:db8::5]:65536/foo');
expect(obj.address?.address).to.equal('2001:db8::5');
expect(obj.port).to.equal(null);
});
it('should work with a address with a port', () => {
const obj = Address6.fromURL('[2001:db8::5]:80');
expect(obj.address?.address).to.equal('2001:db8::5');
expect(obj.port).to.equal(80);
});
it('should parse the address but fail with an out of range port', () => {
const obj = Address6.fromURL('[2001:db8::5]:65536');
expect(obj.address?.address).to.equal('2001:db8::5');
expect(obj.port).to.equal(null);
});
it('should parse the address but fail with an invalid port', () => {
const obj = Address6.fromURL('[2001:db8::5]:65537');
expect(obj.address?.address).to.equal('2001:db8::5');
expect(obj.port).to.equal(null);
});
it('should fail with an invalid address and not return a port', () => {
const obj = Address6.fromURL('[2001:db8:z:5]:65536');
expect(obj.error).to.equal('failed to parse address with port');
expect(obj.port).to.equal(null);
});
it('should reject trailing junk in a bracketed URL (#158)', () => {
const obj = Address6.fromURL('http://[1234:5678::abcdxyz]');
expect(obj.error).to.equal('failed to parse address from URL');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should reject trailing junk in an unbracketed URL (#158)', () => {
const obj = Address6.fromURL('http://1234:5678::abcdxyz');
expect(obj.error).to.equal('failed to parse address from URL');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should reject trailing junk in a bracketed URL with a port', () => {
const obj = Address6.fromURL('http://[1234:5678::abcdxyz]:80');
expect(obj.error).to.equal('failed to parse address with port');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should accept v4-in-v6 addresses in URLs', () => {
const obj = Address6.fromURL('http://[::ffff:192.168.1.1]/foo');
expect(obj.address?.address).to.equal('::ffff:192.168.1.1');
expect(obj.port).to.equal(null);
});
it('should accept v4-in-v6 addresses in URLs with a port', () => {
const obj = Address6.fromURL('http://[::ffff:192.168.1.1]:8080/foo');
expect(obj.address?.address).to.equal('::ffff:192.168.1.1');
expect(obj.port).to.equal(8080);
});
it('should fail gracefully for an IPv4 host', () => {
const obj = Address6.fromURL('http://127.0.0.1/admin');
expect(obj.error).to.equal('failed to parse address from URL');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should fail gracefully for a bracketed IPv4 host with a port', () => {
const obj = Address6.fromURL('http://[169.254.169.254]:8080/latest');
expect(obj.error).to.equal('failed to parse address with port');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should fail gracefully for a bare IPv4 address', () => {
const obj = Address6.fromURL('0.0.0.0');
expect(obj.error).to.equal('failed to parse address from URL');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should fail gracefully for too many colons', () => {
const obj = Address6.fromURL('http://[:::]/foo');
expect(obj.error).to.equal('failed to parse address from URL');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should fail gracefully for too many groups', () => {
const obj = Address6.fromURL('http://[1:2:3:4:5:6:7:8:9]:80/foo');
expect(obj.error).to.equal('failed to parse address with port');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should fail gracefully for out of range v4-in-v6 octets', () => {
const obj = Address6.fromURL('http://[::ffff:999.1.1.1]/foo');
expect(obj.error).to.equal('failed to parse address from URL');
expect(obj.address).to.equal(null);
expect(obj.port).to.equal(null);
});
it('should never throw for a host matching the URL character class', () => {
const hosts = [
'1.2.3.4',
'255.255.255.255',
'[127.0.0.1]:65535',
'.',
'..',
':',
'::::',
'ffff',
'abcdef',
'1:2',
'[::ffff:1.2.3.4.5]:80',
];
hosts.forEach((host) => {
expect(() => Address6.fromURL(`http://${host}/`), host).to.not.throw();
expect(() => Address6.fromURL(host), host).to.not.throw();
});
});
});
describe('regularExpressionString', () => {
it('should work without arguments (using defaults)', () => {
const topic = new Address6('2001:db8::1');
const re = topic.regularExpressionString();
re.should.be.a('string');
re.length.should.be.greaterThan(0);
});
it('should work with substringSearch=true', () => {
const topic = new Address6('2001:db8::1');
const re = topic.regularExpressionString(true);
re.should.be.a('string');
// substring search should not include boundary assertions
re.should.not.include('(?=^|');
});
});
describe('An address from a BigInt', () => {
const topic = Address6.fromBigInt(BigInt('51923840109643282840007714694758401'));
it('should parse correctly', () => {
should.equal(topic.correctForm(), 'a:b:c:d:e:f:0:1');
});
it('should accept the boundary values 0 and 2**128 - 1', () => {
should.equal(Address6.fromBigInt(0n).correctForm(), '::');
should.equal(
Address6.fromBigInt((1n << 128n) - 1n).correctForm(),
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
);
});
it('should reject negative values', () => {
(() => Address6.fromBigInt(-1n)).should.throw(
'IPv6 BigInt must be in the range 0 to 2**128 - 1',
);
});
it('should reject values greater than 2**128 - 1', () => {
(() => Address6.fromBigInt(1n << 128n)).should.throw(
'IPv6 BigInt must be in the range 0 to 2**128 - 1',
);
});
});
describe('subnetMaskAddress', () => {
it('returns :: for /0', () => {
should.equal(new Address6('::/0').subnetMaskAddress().correctForm(), '::');
});
it('returns ffff:ffff:: for /32', () => {
should.equal(new Address6('2001:db8::/32').subnetMaskAddress().correctForm(), 'ffff:ffff::');
});
it('returns ffff:ffff:ffff:ffff:: for /64', () => {
should.equal(
new Address6('2001:db8::/64').subnetMaskAddress().correctForm(),
'ffff:ffff:ffff:ffff::',
);
});
it('returns ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff for /128 (default)', () => {
should.equal(
new Address6('2001:db8::1').subnetMaskAddress().correctForm(),
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
);
});
});
describe('fromAddressAndMask', () => {
it('translates ffff:ffff:ffff:ffff:: to /64', () => {
const topic = Address6.fromAddressAndMask('2001:db8::1', 'ffff:ffff:ffff:ffff::');
topic.subnetMask.should.equal(64);
topic.subnet.should.equal('/64');
should.equal(topic.addressMinusSuffix, '2001:db8::1');
});
it('translates :: to /0', () => {
Address6.fromAddressAndMask('2001:db8::1', '::').subnetMask.should.equal(0);
});
it('translates an all-ones mask to /128', () => {
Address6.fromAddressAndMask(
'2001:db8::1',
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
).subnetMask.should.equal(128);
});
it('round-trips through subnetMaskAddress()', () => {
const original = new Address6('2001:db8::/48');
const mask = original.subnetMaskAddress().correctForm();
Address6.fromAddressAndMask('2001:db8::', mask).subnetMask.should.equal(48);
});
it('rejects a non-contiguous mask', () => {
(() => Address6.fromAddressAndMask('2001:db8::1', 'ffff::ffff')).should.throw(
'Invalid subnet mask.',
);
});
it('rejects an invalid mask address', () => {
(() => Address6.fromAddressAndMask('2001:db8::1', 'not:an:address')).should.throw();
});
it('does not change isValid() behavior for mask-form input', () => {
Address6.isValid('2001:db8::1/ffff:ffff:ffff:ffff::').should.equal(false);
});
});
describe('wildcardMask', () => {
it('returns ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff for /0', () => {
should.equal(
new Address6('::/0').wildcardMask().correctForm(),
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
);
});
it('returns ::ffff:ffff:ffff:ffff:ffff:ffff for /32', () => {
should.equal(
new Address6('2001:db8::/32').wildcardMask().correctForm(),
'::ffff:ffff:ffff:ffff:ffff:ffff',
);
});
it('returns ::ffff:ffff:ffff:ffff for /64', () => {
should.equal(
new Address6('2001:db8::/64').wildcardMask().correctForm(),
'::ffff:ffff:ffff:ffff',
);
});
it('returns :: for /128 (default)', () => {
should.equal(new Address6('2001:db8::1').wildcardMask().correctForm(), '::');
});
it('is the inverse of subnetMaskAddress', () => {
for (const i of [0, 16, 32, 48, 64, 80, 96, 112, 128]) {
const topic = new Address6(`2001:db8::1/${i}`);
const mask = topic.subnetMaskAddress().bigInt();
const wildcard = topic.wildcardMask().bigInt();
const allOnes = (BigInt(1) << BigInt(128)) - BigInt(1);
(mask ^ wildcard).should.equal(allOnes);
}
});
});
describe('fromAddressAndWildcardMask', () => {
it('translates ::ffff:ffff:ffff:ffff to /64', () => {
const topic = Address6.fromAddressAndWildcardMask('2001:db8::1', '::ffff:ffff:ffff:ffff');
topic.subnetMask.should.equal(64);
topic.subnet.should.equal('/64');
});
it('translates :: to /128', () => {
Address6.fromAddressAndWildcardMask('2001:db8::1', '::').subnetMask.should.equal(128);
});
it('translates an all-ones wildcard to /0', () => {
Address6.fromAddressAndWildcardMask(
'2001:db8::1',
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
).subnetMask.should.equal(0);
});
it('round-trips through wildcardMask()', () => {
const original = new Address6('2001:db8::/48');
const wildcard = original.wildcardMask().correctForm();
Address6.fromAddressAndWildcardMask('2001:db8::', wildcard).subnetMask.should.equal(48);
});
it('rejects a non-contiguous wildcard mask', () => {
(() => Address6.fromAddressAndWildcardMask('2001:db8::1', 'ffff::ffff')).should.throw(
'Invalid subnet mask.',
);
});
});
describe('networkForm', () => {
it('returns ::/0 for /0', () => {
should.equal(new Address6('2001:db8::1/0').networkForm(), '::/0');
});
it('returns 2001:db8::/32 for 2001:db8::1/32', () => {
should.equal(new Address6('2001:db8::1/32').networkForm(), '2001:db8::/32');
});
it('returns 2001:db8::/64 for 2001:db8::abcd/64', () => {
should.equal(new Address6('2001:db8::abcd/64').networkForm(), '2001:db8::/64');
});
it('returns the address itself with /128 when no subnet is given', () => {
should.equal(new Address6('2001:db8::1').networkForm(), '2001:db8::1/128');
});
it('round-trips through the Address6 constructor', () => {
const original = new Address6('2001:db8:abcd:ef01::1/48');
const round = new Address6(original.networkForm());
round.correctForm().should.equal('2001:db8:abcd::');
round.subnetMask.should.equal(48);
});
});
describe('fromWildcard', () => {
it('parses 2001:db8:*:*:*:*:*:* as /32', () => {
const topic = Address6.fromWildcard('2001:db8:*:*:*:*:*:*');
topic.subnet.should.equal('/32');
topic.startAddress().correctForm().should.equal('2001:db8::');
});
it('parses 2001:db8:1:2:3:4:5:* as /112', () => {
Address6.fromWildcard('2001:db8:1:2:3:4:5:*').subnet.should.equal('/112');
});
it('parses 2001:db8::* as /112 (with `::` expansion)', () => {
const topic = Address6.fromWildcard('2001:db8::*');
topic.subnet.should.equal('/112');
topic.startAddress().correctForm().should.equal('2001:db8::');
});
it('parses *:*:*:*:*:*:*:* as /0', () => {
Address6.fromWildcard('*:*:*:*:*:*:*:*').subnet.should.equal('/0');
});
it('parses a no-wildcard address as /128', () => {
const topic = Address6.fromWildcard('2001:db8::1');
topic.subnet.should.equal('/128');
topic.correctForm().should.equal('2001:db8::1');
});
it('rejects an interior wildcard', () => {
(() => Address6.fromWildcard('*:db8:1:2:3:4:5:6')).should.throw(
'Wildcard `*` must only appear in trailing groups',
);
(() => Address6.fromWildcard('2001:*:1:2:3:4:5:6')).should.throw(
'Wildcard `*` must only appear in trailing groups',
);
});
it('rejects a partial-group wildcard', () => {
(() => Address6.fromWildcard('2001:db8:1:2:3:4:5:0*')).should.throw();
});
it('rejects a pattern with the wrong number of groups', () => {
(() => Address6.fromWildcard('2001:db8:*:*:*:*:*')).should.throw(
'Wildcard pattern must have 8 groups',
);
});
it('rejects multiple `::`', () => {
(() => Address6.fromWildcard('2001::db8::*')).should.throw(
"Wildcard pattern cannot contain more than one '::'",
);
});
it('rejects a CIDR suffix', () => {
(() => Address6.fromWildcard('2001:db8:*:*:*:*:*:*/32')).should.throw(
'Wildcard pattern must not include a zone or CIDR suffix',
);
});
it('rejects a zone identifier', () => {
(() => Address6.fromWildcard('fe80::*%eth0')).should.throw(
'Wildcard pattern must not include a zone or CIDR suffix',
);
});
});
describe('HTML helpers', () => {
describe('href', () => {
const topic = new Address6('2001:4860:4001:803::1011');
it('should generate a URL correctly', () => {
topic.href().should.equal('http://[2001:4860:4001:803::1011]/');
topic.href(8080).should.equal('http://[2001:4860:4001:803::1011]:8080/');
});
});
describe('link', () => {
const topic = new Address6('2001:4860:4001:803::1011');
it('should generate an anchor correctly', () => {
topic
.link()
.should.equal(
'2001:4860:4001:803::1011',
);
topic
.link({ className: 'highlight', prefix: '/?address=' })
.should.equal(
'2001:4860:4001:803::1011',
);
});
it('should generate a v4inv6 anchor correctly', () => {
const topic4 = new Address6('::ffff:c0a8:1');
topic4
.link({ v4: true })
.should.equal('::ffff:192.168.0.1');
});
});
describe('group', () => {
it('should group a fully ellided address', () => {
const topic = new Address6('::');
topic
.group()
.should.equal(
'::',
);
});
it('should group an address with no ellision', () => {
const topic = new Address6('a:b:c:d:1:2:3:4');
topic
.group()
.should.equal(
'a:' +
'b:' +
'c:' +
'd:' +
'1:' +
'2:' +
'3:' +
'4',
);
});
it('should group an ellided address', () => {
const topic = new Address6('2001:4860:4001:803::1011');
topic
.group()
.should.equal(
'2001:' +
'4860:' +
'4001:' +
'803:' +
':' +
'1011',
);
});
it('should group an IPv4 address', () => {
const topic = new Address6('::ffff:192.168.0.1');
topic.is4().should.equal(true);
topic
.group()
.should.equal(
':' +
':ffff:' +
'192.168.0.1',
);
});
});
});
describe('isULA', () => {
it('detects fc00::/7', () => {
notationsToAddresseses([
'fc00::',
'fc00::1',
'fcff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
'fd00::',
'fd12:3456:789a::1',
'fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
]).forEach((topic) => {
should.equal(topic.isULA(), true);
});
});
it('rejects addresses outside fc00::/7 including fe80::/10 and global unicast', () => {
notationsToAddresseses([
'::',
'::1',
'fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
'fe00::',
'fe80::1',
'2001:db8::1',
]).forEach((topic) => {
should.equal(topic.isULA(), false);
});
});
});
describe('isUnspecified', () => {
it('detects ::', () => {
should.equal(new Address6('::').isUnspecified(), true);
});
it('rejects non-zero addresses', () => {
notationsToAddresseses(['::1', '2001:db8::1', 'fc00::']).forEach((topic) => {
should.equal(topic.isUnspecified(), false);
});
});
});
describe('isMapped4', () => {
it('detects ::ffff:0:0/96 regardless of notation', () => {
notationsToAddresseses([
'::ffff:0:0',
'::ffff:127.0.0.1',
'::ffff:7f00:1',
'::ffff:7f00:0001',
'::ffff:c0a8:1',
'::ffff:192.168.0.1',
'::ffff:ffff:ffff',
]).forEach((topic) => {
should.equal(topic.isMapped4(), true);
});
});
it('rejects addresses outside ::ffff:0:0/96', () => {
notationsToAddresseses([
'::',
'::1',
'::1.2.3.4',
'::1:ffff:0:0',
'64:ff9b::192.0.2.1',
'2001:db8::1',
'fc00::',
]).forEach((topic) => {
should.equal(topic.isMapped4(), false);
});
});
it('agrees with is4 for IPv4-mapped addresses written in dotted-quad', () => {
const dotted = new Address6('::ffff:127.0.0.1');
const hex = new Address6('::ffff:7f00:1');
should.equal(dotted.isMapped4(), true);
should.equal(hex.isMapped4(), true);
should.equal(dotted.is4(), true);
should.equal(hex.is4(), false);
});
});
describe('isDocumentation', () => {
it('detects 2001:db8::/32', () => {
notationsToAddresseses([
'2001:db8::',
'2001:db8::1',
'2001:db8:ffff:ffff:ffff:ffff:ffff:ffff',
]).forEach((topic) => {
should.equal(topic.isDocumentation(), true);
});
});
it('rejects addresses outside 2001:db8::/32', () => {
notationsToAddresseses([
'2001:db7:ffff:ffff:ffff:ffff:ffff:ffff',
'2001:db9::',
'2001::1',
'fc00::',
]).forEach((topic) => {
should.equal(topic.isDocumentation(), false);
});
});
});
describe('String helpers', () => {
describe('spanLeadingZeroes', () => {
it('should span leading zeroes', () => {
const topic = v6.helpers.spanLeadingZeroes('0000:0000:4444:0001');
topic.should.equal(
'0000:' +
'0000:4444:' +
'0001',
);
});
});
describe('simpleGroup', () => {
it('should pass through groups containing group-v4', () => {
const topic = v6.helpers.simpleGroup(
'ffff:192.168.0.1',
);
topic[0].should.equal('ffff');
// The group-v4 segment should pass through unchanged
topic[1].should.equal(
'192.168.0.1',
);
});
it('should HTML-escape non-pass-through segments', () => {
const topic = v6.helpers.simpleGroup('bold');
topic[0].should.equal('<b>bold</b>');
});
});
describe('spanAll', () => {
it('should HTML-escape characters in the class attribute', () => {
const topic = v6.helpers.spanAll('"');
topic.should.equal('"');
});
it('should span leading zeroes', () => {
const topic = v6.helpers.spanAll('001100');
topic.should.equal(
'' +
'0' +
'' +
'0' +
'1' +
'1' +
'' +
'0' +
'' +
'0',
);
});
it('should span leading zeroes with offset', () => {
const topic = v6.helpers.spanAll('001100', 1);
topic.should.equal(
'' +
'0' +
'' +
'0' +
'1' +
'1' +
'' +
'0' +
'' +
'0',
);
});
});
});
// Regression tests for GHSA-22jq-vg5j-6vgg: IPv4-mapped (`::ffff:0:0/96`) and
// NAT64 well-known (`64:ff9b::/96`) addresses must be classified by the IPv4
// address they embed, not by their IPv6 wrapper. Before the fix every literal
// below read as "Global unicast" / non-internal, bypassing any guard built on
// these checks.
describe('embedded-IPv4 classification (GHSA-22jq-vg5j-6vgg)', () => {
describe('embeddedIPv4', () => {
it('returns the embedded address for IPv4-mapped and NAT64 well-known', () => {
const cases: [string, string][] = [
['::ffff:127.0.0.1', '127.0.0.1'],
['::ffff:7f00:1', '127.0.0.1'],
['::ffff:10.0.0.1', '10.0.0.1'],
['::ffff:169.254.169.254', '169.254.169.254'],
['::ffff:a9fe:a9fe', '169.254.169.254'],
['64:ff9b::7f00:1', '127.0.0.1'],
['64:ff9b::a9fe:a9fe', '169.254.169.254'],
];
cases.forEach(([notation, expected]) => {
const embedded = new Address6(notation).embeddedIPv4();
should.exist(embedded);
should.equal(embedded?.correctForm(), expected);
});
});
it('returns null for addresses that embed no routable IPv4 address', () => {
notationsToAddresseses([
'::1',
'::',
'2001:db8::1',
'fe80::1',
'fc00::1',
'ff02::1',
'64:ff9b:1::1', // NAT64 local-use /48 has no single decoding; isPrivate() covers it
]).forEach((topic) => {
should.equal(topic.embeddedIPv4(), null);
});
});
});
describe('isLoopback', () => {
it('detects mapped/NAT64 loopback', () => {
notationsToAddresseses([
'::ffff:127.0.0.1',
'::ffff:7f00:1',
'::ffff:127.255.255.254',
'64:ff9b::7f00:1',
]).forEach((topic) => {
should.equal(topic.isLoopback(), true);
});
});
it('still reports ::1 and rejects mapped public addresses', () => {
should.equal(new Address6('::1').isLoopback(), true);
should.equal(new Address6('::ffff:8.8.8.8').isLoopback(), false);
});
});
describe('isLinkLocal', () => {
it('detects mapped/NAT64 cloud-metadata link-local', () => {
notationsToAddresseses([
'::ffff:169.254.169.254',
'::ffff:a9fe:a9fe',
'64:ff9b::a9fe:a9fe',
]).forEach((topic) => {
should.equal(topic.isLinkLocal(), true);
});
});
it('still reports native fe80::/10 and rejects mapped public addresses', () => {
should.equal(new Address6('fe80::1').isLinkLocal(), true);
should.equal(new Address6('::ffff:8.8.8.8').isLinkLocal(), false);
});
// RFC 4291 §2.4 assigns the whole of fe80::/10 to link-local unicast, not
// only the fe80::/64 that stateless autoconfiguration happens to land in.
it('covers all of fe80::/10, not only fe80::/64', () => {
notationsToAddresseses([
'fe81::1',
'fe8f::1',
'fe90::1',
'fea0::1',
'febf::1',
'febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
'fe80:0:0:1::1',
'fe80::1:0:0:0:1',
]).forEach((topic) => {
should.equal(topic.isLinkLocal(), true, topic.address);
});
});
it('rejects the neighbors of fe80::/10', () => {
notationsToAddresseses(['fe7f::1', 'fec0::1', 'fc00::1', 'ff02::1']).forEach((topic) => {
should.equal(topic.isLinkLocal(), false, topic.address);
});
});
});
describe('isPrivate', () => {
it('detects mapped RFC 1918 addresses', () => {
notationsToAddresseses([
'::ffff:10.0.0.1',
'::ffff:172.16.5.5',
'::ffff:192.168.1.1',
'64:ff9b::c0a8:101', // ::ffff:192.168.1.1 over NAT64
]).forEach((topic) => {
should.equal(topic.isPrivate(), true);
});
});
it('detects native ULAs and rejects mapped public addresses', () => {
should.equal(new Address6('fc00::1').isPrivate(), true);
should.equal(new Address6('fd12:3456:789a::1').isPrivate(), true);
should.equal(new Address6('::ffff:8.8.8.8').isPrivate(), false);
should.equal(new Address6('2001:db8::1').isPrivate(), false);
});
// RFC 8215 reserves 64:ff9b:1::/48 for local-use NAT64. An operator may
// carve a prefix of any RFC 6052 length out of it, so there is no single
// embedded IPv4 address to decode; the whole range is not globally
// reachable and is private.
it('detects the NAT64 local-use range 64:ff9b:1::/48 (RFC 8215)', () => {
notationsToAddresseses([
'64:ff9b:1::1',
'64:ff9b:1:7f00:0:100::', // 127.0.0.1 under a /48 prefix
'64:ff9b:1::7f00:1', // 127.0.0.1 under a /96 prefix
'64:ff9b:1:a9fe:a9:fe00::', // 169.254.169.254 under a /48 prefix
'64:ff9b:1::a9fe:a9fe', // 169.254.169.254 under a /96 prefix
'64:ff9b:1:ffff:ffff:ffff:ffff:ffff',
]).forEach((topic) => {
should.equal(topic.isPrivate(), true, topic.address);
});
});
it('rejects the neighbors of 64:ff9b:1::/48', () => {
notationsToAddresseses(['64:ff9b:0:ffff::1', '64:ff9b:2::1', '64:ff9c::1']).forEach(
(topic) => {
should.equal(topic.isPrivate(), false, topic.address);
},
);
});
});
describe('offset', () => {
it('moves by n and keeps the subnet mask', () => {
should.equal(new Address6('2001:db8::/64').offset(1).correctForm(), '2001:db8::1');
should.equal(new Address6('2001:db8::/64').offset(1).subnetMask, 64);
should.equal(new Address6('2001:db8::1').offset(-1).correctForm(), '2001:db8::');
should.equal(
new Address6('2001:db8::').offset(BigInt(1) << BigInt(64)).correctForm(),
'2001:db8:0:1::',
);
should.equal(
new Address6('::').offset((BigInt(1) << BigInt(128)) - BigInt(1)).correctForm(),
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
);
});
it('rejects leaving the address space or a non-integer n', () => {
should.Throw(
() => new Address6('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff').offset(1),
AddressError,
);
should.Throw(() => new Address6('::').offset(-1), AddressError);
should.Throw(() => new Address6('::1').offset(0.5), AddressError);
should.Throw(() => new Address6('::1').offset(NaN), AddressError);
should.Throw(() => new Address6('::1').offset(2 ** 53), AddressError);
should.Throw(() => new Address6('::1').offset(null as never), AddressError);
});
});
describe('nextNetwork', () => {
it('returns the network after this one with the same mask', () => {
should.equal(
new Address6('2001:db8::/64').nextNetwork().networkForm(),
'2001:db8:0:1::/64',
);
should.equal(
new Address6('2001:db8::abcd/64').nextNetwork().networkForm(),
'2001:db8:0:1::/64',
);
should.equal(new Address6('2001:db8::/32').nextNetwork().networkForm(), '2001:db9::/32');
should.equal(new Address6('::1').nextNetwork().correctForm(), '::2');
});
it('rejects the last network in the address space', () => {
should.Throw(() => new Address6('ffff::/16').nextNetwork(), AddressError);
should.Throw(() => new Address6('::/0').nextNetwork(), AddressError);
});
});
describe('fromArpa with a prefix-length name', () => {
it('returns the delegated network and round-trips reverseForm', () => {
should.equal(
Address6.fromArpa('8.b.d.0.1.0.0.2.ip6.arpa.').networkForm(),
'2001:db8::/32',
);
should.equal(Address6.fromArpa('8.b.d.0.1.0.0.2.ip6.arpa').networkForm(), '2001:db8::/32');
should.equal(Address6.fromArpa('8.b.d.0.1.0.0.2').networkForm(), '2001:db8::/32');
should.equal(Address6.fromArpa('2.ip6.arpa.').networkForm(), '2000::/4');
});
it('accepts the suffix in any case, as DNS does', () => {
should.equal(
Address6.fromArpa('8.B.D.0.1.0.0.2.IP6.ARPA.').networkForm(),
'2001:db8::/32',
);
should.equal(Address6.fromArpa('8.b.d.0.1.0.0.2.Ip6.Arpa').networkForm(), '2001:db8::/32');
[
'2001:db8::/32',
'2001:db8:1234::/48',
'2001:db8::/64',
'2001:db8::1',
'fe80::1/12',
].forEach((n) => {
const address = new Address6(n);
should.equal(
Address6.fromArpa(address.reverseForm()).networkForm(),
address.networkForm(),
n,
);
});
});
it('still gives a /128 for a full-length name', () => {
const full = Address6.fromArpa(
'1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.',
);
should.equal(full.correctForm(), '2001:db8::1');
should.equal(full.subnetMask, 128);
});
it('rejects malformed names', () => {
[
'',
'.',
'ip6.arpa.',
'g.ip6.arpa.',
'1..2.ip6.arpa.',
'12.ip6.arpa.',
'1.0.0.127.in-addr.arpa.',
`${'1.'.repeat(32)}1.ip6.arpa.`,
'1.ip6.arpa..',
' 1.ip6.arpa.',
].forEach((s) => {
should.Throw(() => Address6.fromArpa(s), AddressError, undefined, JSON.stringify(s));
});
});
});
describe('isDocumentation', () => {
it('detects 2001:db8::/32 and 3fff::/20 (RFC 9637)', () => {
notationsToAddresseses([
'2001:db8::1',
'3fff::1',
'3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff',
]).forEach((topic) => {
should.equal(topic.isDocumentation(), true, topic.address);
});
should.equal(new Address6('3ffe:ffff::1').isDocumentation(), false);
should.equal(new Address6('4000::1').isDocumentation(), false);
should.equal(new Address6('3fff::1').getType(), 'Documentation');
});
});
describe('isBenchmarking', () => {
it('detects 2001:2::/48 and mapped 198.18.0.0/15', () => {
should.equal(new Address6('2001:2::1').isBenchmarking(), true);
should.equal(new Address6('2001:2:0:ffff::1').isBenchmarking(), true);
should.equal(new Address6('2001:2:1::1').isBenchmarking(), false);
should.equal(new Address6('::ffff:198.18.0.1').isBenchmarking(), true);
should.equal(new Address6('::ffff:8.8.8.8').isBenchmarking(), false);
should.equal(new Address6('2001:2::1').getType(), 'Benchmarking');
});
});
describe('isGlobal', () => {
it('is false for every special-purpose block, named or not', () => {
notationsToAddresseses([
'::',
'::1',
'64:ff9b:1::1', // NAT64 local-use
'100::1', // discard-only
'100:0:0:1::1', // dummy prefix
'2001::1', // Teredo
'2001:1::4', // IETF protocol assignments
'2001:2::1', // benchmarking
'2001:10::1', // deprecated ORCHID, inherits 2001::/23
'2001:db8::1',
'2002::1', // 6to4
'3fff::1',
'5f00::1', // SRv6 SIDs
'fec0::1', // deprecated site-local, reserved
'::127.0.0.1', // deprecated IPv4-compatible, reserved
'::2', // reserved ::/8
'1fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', // last address before 2000::/3
'4000::1', // unallocated
'fc00::1',
'fe81::1',
'ff02::1', // multicast
'::ffff:10.0.0.1', // mapped private
'::ffff:192.0.2.1', // mapped documentation
'64:ff9b::7f00:1', // NAT64 well-known loopback
]).forEach((topic) => {
should.equal(topic.isGlobal(), false, topic.address);
});
});
it('honors the registry entries that are globally reachable inside 2001::/23', () => {
notationsToAddresseses([
'2001:1::1', // PCP anycast
'2001:1::2', // TURN anycast
'2001:1::3', // DNS-SD SRP anycast
'2001:3::1', // AMT
'2001:4:112::1', // AS112
'2001:20::1', // ORCHIDv2
'2001:30::1', // DETs
]).forEach((topic) => {
should.equal(topic.isGlobal(), true, topic.address);
});
});
it('is true for ordinary addresses, including mapped and NAT64 forms of them', () => {
notationsToAddresseses([
'2606:4700::1111',
'2001:4860:4860::8888',
'::ffff:8.8.8.8',
'64:ff9b::808:808',
]).forEach((topic) => {
should.equal(topic.isGlobal(), true, topic.address);
});
});
it('ignores the address own subnet mask', () => {
should.equal(new Address6('::1/0').isGlobal(), false);
should.equal(new Address6('2606:4700::1111/0').isGlobal(), true);
});
});
describe('isCGNAT', () => {
it('detects mapped CGNAT and rejects everything else', () => {
should.equal(new Address6('::ffff:100.64.0.1').isCGNAT(), true);
should.equal(new Address6('::ffff:8.8.8.8').isCGNAT(), false);
should.equal(new Address6('2001:db8::1').isCGNAT(), false);
});
});
describe('isBroadcast', () => {
it('detects mapped broadcast and rejects everything else', () => {
should.equal(new Address6('::ffff:255.255.255.255').isBroadcast(), true);
should.equal(new Address6('::ffff:8.8.8.8').isBroadcast(), false);
should.equal(new Address6('2001:db8::1').isBroadcast(), false);
});
});
describe('isUnspecified', () => {
it('detects mapped 0.0.0.0 and rejects mapped non-zero addresses', () => {
should.equal(new Address6('::ffff:0.0.0.0').isUnspecified(), true);
should.equal(new Address6('::ffff:127.0.0.1').isUnspecified(), false);
});
});
describe('isMulticast', () => {
it('detects mapped IPv4 multicast and rejects mapped unicast', () => {
should.equal(new Address6('::ffff:224.0.0.1').isMulticast(), true);
should.equal(new Address6('::ffff:8.8.8.8').isMulticast(), false);
});
});
describe('getType', () => {
it('labels IPv4-mapped addresses', () => {
should.equal(new Address6('::ffff:127.0.0.1').getType(), 'IPv4-mapped');
should.equal(new Address6('::ffff:8.8.8.8').getType(), 'IPv4-mapped');
});
});
it('a README-style SSRF guard blocks every mapped/NAT64 internal target', () => {
// Mirrors the guard from the advisory PoC, now using Address6.isPrivate().
function isBlocked(host: string): boolean {
let address: Address6;
try {
address = new Address6(host);
} catch {
return false;
}
return (
address.isLoopback() ||
address.isLinkLocal() ||
address.isPrivate() ||
address.isCGNAT() ||
address.isMulticast() ||
address.isUnspecified() ||
address.isBroadcast()
);
}
[
'::ffff:127.0.0.1',
'::ffff:7f00:1',
'::ffff:10.0.0.1',
'::ffff:172.16.5.5',
'::ffff:192.168.1.1',
'::ffff:169.254.169.254',
'::ffff:a9fe:a9fe',
'::ffff:100.64.0.1',
'::ffff:0.0.0.0',
'::ffff:255.255.255.255',
'64:ff9b::7f00:1',
'64:ff9b::a9fe:a9fe',
].forEach((host) => {
should.equal(isBlocked(host), true, `expected ${host} to be blocked`);
});
// Genuinely public hosts still pass through.
['::ffff:8.8.8.8', '2001:4860:4860::8888'].forEach((host) => {
should.equal(isBlocked(host), false, `expected ${host} to be allowed`);
});
});
});
describe('classification ignores the address own subnet mask', () => {
// A classifier answers a question about the address, so a CIDR suffix on
// the input must not change the answer. Suffixes shorter than the
// reference range's prefix are the interesting case.
type Predicate =
| 'isLoopback'
| 'isLinkLocal'
| 'isULA'
| 'isPrivate'
| 'isUnspecified'
| 'isMulticast'
| 'isMapped4'
| 'isTeredo'
| 'is6to4'
| 'isDocumentation';
const cases: [string, Predicate][] = [
['::1', 'isLoopback'],
['fe80::1', 'isLinkLocal'],
['fc00::1', 'isULA'],
['fc00::1', 'isPrivate'],
['::', 'isUnspecified'],
['ff02::1', 'isMulticast'],
['::ffff:1.2.3.4', 'isMapped4'],
['2001::1', 'isTeredo'],
['2002::1', 'is6to4'],
['2001:db8::1', 'isDocumentation'],
// IPv4-mapped and NAT64 normalization (GHSA-22jq-vg5j-6vgg) must also
// survive a suffix, otherwise that fix is trivially undone.
['::ffff:127.0.0.1', 'isLoopback'],
['::ffff:10.0.0.1', 'isPrivate'],
['::ffff:169.254.169.254', 'isLinkLocal'],
['64:ff9b::7f00:1', 'isLoopback'],
['64:ff9b::a9fe:a9fe', 'isLinkLocal'],
];
it('classifies the host identically with and without a /0 suffix', () => {
cases.forEach(([notation, method]) => {
should.equal(new Address6(notation)[method](), true, `${notation} ${method}`);
should.equal(new Address6(`${notation}/0`)[method](), true, `${notation}/0 ${method}`);
});
});
it('classifies the host identically for every prefix length', () => {
for (let prefix = 0; prefix <= 128; prefix++) {
should.equal(new Address6(`::1/${prefix}`).isLoopback(), true, `::1/${prefix}`);
should.equal(new Address6(`fc00::1/${prefix}`).isPrivate(), true, `fc00::1/${prefix}`);
should.equal(
new Address6(`::ffff:127.0.0.1/${prefix}`).isLoopback(),
true,
`::ffff:127.0.0.1/${prefix}`,
);
}
});
it('reports getType by the host bits regardless of suffix', () => {
should.equal(new Address6('::1/0').getType(), 'Loopback');
should.equal(new Address6('fe80::1/0').getType(), 'Link-local unicast');
should.equal(new Address6('fc00::1/0').getType(), 'Unique local');
should.equal(new Address6('::ffff:127.0.0.1/0').getType(), 'IPv4-mapped');
});
it('does not start misclassifying public addresses', () => {
for (let prefix = 0; prefix <= 128; prefix++) {
const address = new Address6(`2001:4860:4860::8888/${prefix}`);
should.equal(address.isLoopback(), false, `/${prefix}`);
should.equal(address.isPrivate(), false, `/${prefix}`);
should.equal(address.isULA(), false, `/${prefix}`);
should.equal(address.isMulticast(), false, `/${prefix}`);
should.equal(address.isMapped4(), false, `/${prefix}`);
}
});
});
describe('isInSubnet retains subnet-containment semantics', () => {
// isInSubnet answers "is my network inside yours", which is a different
// question from classification and must keep rejecting wider networks.
it('reports a wider network as not contained in a narrower one', () => {
should.equal(new Address6('::1/0').isInSubnet(new Address6('::1/128')), false);
should.equal(new Address6('fc00::/7').isInSubnet(new Address6('fc00::/16')), false);
});
it('still reports genuine containment', () => {
should.equal(new Address6('fc00::/16').isInSubnet(new Address6('fc00::/7')), true);
should.equal(new Address6('::1/128').isInSubnet(new Address6('::/0')), true);
should.equal(new Address6('2001::/16').isInSubnet(new Address6('fc00::/7')), false);
});
});
describe('containment across address families', () => {
// mask() is a bit string of the family's width, and the leading bits of
// a 32-bit string can coincide with those of a 128-bit one: a00::1 and
// 10.0.0.0/8 both mask to 00001010. An address of one family is never
// inside a network of the other.
const pairs: Array<[Address4 | Address6, Address4 | Address6]> = [
[new Address6('a00::1'), new Address4('10.0.0.0/8')],
[new Address4('10.0.0.1'), new Address6('a00::/8')],
[new Address4('32.0.0.1'), new Address6('2000::/3')],
[new Address6('::ffff:10.0.0.1'), new Address4('10.0.0.0/8')],
[new Address4('10.0.0.1'), new Address6('::ffff:10.0.0.0/104')],
[new Address4('0.0.0.0/0'), new Address6('::/0')],
[new Address6('::/0'), new Address4('0.0.0.0/0')],
];
it('isInSubnet is false for an address of the other family', () => {
for (const [address, network] of pairs) {
should.equal(
address.isInSubnet(network),
false,
`${address.address} in ${network.address}`,
);
}
});
it('isHostInSubnet is false for an address of the other family', () => {
for (const [address, network] of pairs) {
should.equal(
address.isHostInSubnet(network),
false,
`${address.address} in ${network.address}`,
);
}
});
it('still reports containment once the address is converted', () => {
should.equal(
new Address6('::ffff:10.0.0.1').to4().isInSubnet(new Address4('10.0.0.0/8')),
true,
);
should.equal(
Address6.fromAddress4('10.0.0.1').isInSubnet(new Address6('::ffff:10.0.0.0/104')),
true,
);
});
});
describe('toByteArray', () => {
it('always returns 16 bytes, including for addresses with leading zero bytes', () => {
// RFC 4291 section 2: an IPv6 address is a 128-bit (16-octet) identifier,
// so its byte array must always be 16 bytes long.
new Address6('::').toByteArray().length.should.equal(16);
new Address6('::1').toByteArray().length.should.equal(16);
new Address6('::ffff:192.168.0.1').toByteArray().length.should.equal(16);
new Address6('64:ff9b::c000:221').toByteArray().length.should.equal(16);
new Address6('a:b:c:d:e:f:0:1').toByteArray().length.should.equal(16);
new Address6('::1').toUnsignedByteArray().length.should.equal(16);
});
it('preserves the high-order zero bytes', () => {
new Address6('::1')
.toByteArray()
.should.deep.equal([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
new Address6('::ffff:192.168.0.1')
.toByteArray()
.should.deep.equal([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 192, 168, 0, 1]);
});
});
describe('fromByteArray', () => {
const zeros = (count: number) => Array(count).fill(0);
it('parses a valid 16-byte array', () => {
should.equal(
Address6.fromByteArray([32, 1, 13, 184, ...zeros(12)]).correctForm(),
'2001:db8::',
);
should.equal(Address6.fromByteArray([...zeros(15), 1]).correctForm(), '::1');
should.equal(
Address6.fromByteArray(Array(16).fill(255)).correctForm(),
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
);
});
it('round-trips through toByteArray', () => {
const topic = new Address6('2001:db8::1');
Address6.fromByteArray(topic.toByteArray()).correctForm().should.equal(topic.correctForm());
});
it('folds signed bytes to their unsigned equivalent', () => {
// An Int8Array or a Java byte[] carries 128 to 255 as -128 to -1.
should.equal(
Address6.fromByteArray(Array(16).fill(-1)).correctForm(),
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
);
should.equal(Address6.fromByteArray([-1, ...zeros(15)]).correctForm(), 'ff00::');
should.equal(Address6.fromByteArray([-128, ...zeros(15)]).correctForm(), '8000::');
});
it('throws unless given exactly 16 bytes', () => {
// RFC 4291 section 2: an IPv6 address is exactly 16 octets.
should.Throw(() => Address6.fromByteArray([]), 'IPv6 addresses require exactly 16 bytes');
should.Throw(
() => Address6.fromByteArray([1, 2, 3]),
'IPv6 addresses require exactly 16 bytes',
);
// A 17-byte array with a leading zero has the same magnitude as the
// 16-byte value, so bounds-checking the folded BigInt never catches it.
should.Throw(
() => Address6.fromByteArray([...zeros(16), 1]),
'IPv6 addresses require exactly 16 bytes',
);
});
it('throws for bytes outside -128 to 255', () => {
// 300 in the low byte stays under 2**128-1, so a result-only bound misses it.
should.Throw(
() => Address6.fromByteArray([...zeros(15), 300]),
'All bytes must be integers between -128 and 255',
);
should.Throw(
() => Address6.fromByteArray([256, ...zeros(15)]),
'All bytes must be integers between -128 and 255',
);
// -129 would fold to 127 rather than to anything the caller meant.
should.Throw(
() => Address6.fromByteArray([-129, ...zeros(15)]),
'All bytes must be integers between -128 and 255',
);
});
it('throws for non-integer bytes', () => {
should.Throw(
() => Address6.fromByteArray([1.5, ...zeros(15)]),
'All bytes must be integers between -128 and 255',
);
should.Throw(
() => Address6.fromByteArray([Number.NaN, ...zeros(15)]),
'All bytes must be integers between -128 and 255',
);
});
});
describe('fromUnsignedByteArray', () => {
const zeros = (count: number) => Array(count).fill(0);
it('parses a valid 16-byte array', () => {
Address6.fromUnsignedByteArray([32, 1, 13, 184, ...zeros(12)])
.correctForm()
.should.equal('2001:db8::');
});
it('round-trips through toUnsignedByteArray', () => {
const topic = new Address6('ffff::1');
Address6.fromUnsignedByteArray(topic.toUnsignedByteArray())
.correctForm()
.should.equal(topic.correctForm());
});
it('throws unless given exactly 16 bytes', () => {
should.Throw(
() => Address6.fromUnsignedByteArray([]),
'IPv6 addresses require exactly 16 bytes',
);
should.Throw(
() => Address6.fromUnsignedByteArray([1, 2, 3]),
'IPv6 addresses require exactly 16 bytes',
);
should.Throw(
() => Address6.fromUnsignedByteArray([...zeros(16), 1]),
'IPv6 addresses require exactly 16 bytes',
);
});
it('throws for bytes outside 0 to 255, signed values included', () => {
should.Throw(
() => Address6.fromUnsignedByteArray([...zeros(15), 300]),
'All bytes must be integers between 0 and 255',
);
should.Throw(
() => Address6.fromUnsignedByteArray([-1, ...zeros(15)]),
'All bytes must be integers between 0 and 255',
);
});
it('throws for non-integer bytes', () => {
should.Throw(
() => Address6.fromUnsignedByteArray([1.5, ...zeros(15)]),
'All bytes must be integers between 0 and 255',
);
});
});
describe('an address with more than one subnet suffix', () => {
// RE_SUBNET_STRING anchors on the end of the address, so it strips only
// the trailing suffix. Anything left over is malformed and must be
// rejected rather than parsed as an address group, which produced a NaN
// group and a correctForm() of '::NaN'. Address4 already rejects the
// equivalent '10.0.0.1/8/16'.
const malformed = ['::/0/1', '::1/64/8', 'fe80::/10/64', '2001:db8::1/32/16'];
it('is rejected by isValid', () => {
malformed.forEach((notation) => {
should.equal(Address6.isValid(notation), false, notation);
});
});
it('throws from the constructor', () => {
malformed.forEach((notation) => {
should.Throw(() => new Address6(notation), AddressError, undefined, notation);
});
});
it('never leaves NaN in a parsed group', () => {
malformed.forEach((notation) => {
try {
const address = new Address6(notation);
address.parsedAddress.forEach((group) => {
should.equal(group.includes('NaN'), false, `${notation} -> ${group}`);
});
should.equal(address.correctForm().includes('NaN'), false, notation);
} catch {
// Throwing is the expected outcome.
}
});
});
it('still accepts a single suffix', () => {
should.equal(new Address6('::/0').subnetMask, 0);
should.equal(new Address6('::1/128').subnetMask, 128);
should.equal(new Address6('fe80::/10').subnetMask, 10);
should.equal(new Address6('fe80::1%eth0/64').subnetMask, 64);
});
});
});
beaugunderson-ip-address-438375e/test/iana-corpus-test.ts 0000664 0000000 0000000 00000011654 15272410673 0023433 0 ustar 00root root 0000000 0000000 /* eslint-disable import/extensions */
import * as chai from 'chai';
import corpus from './data/iana-corpus.json';
import { Address4 } from '../src/ipv4';
import { Address6 } from '../src/ipv6';
const should = chai.should();
// test/data/iana-corpus.json is generated by scripts/gen-iana-corpus.py from
// the IANA special-purpose address registries checked in beside it. Every
// probe is a boundary of a registry block (or an IPv4-mapped / NAT64 form of
// one) with the registry's own answer attached, so this suite fails when the
// classifiers disagree with the registry rather than when a reporter notices.
//
// Python's ipaddress classification rides along for cross-checking; it
// disagrees with the registry on a few rows (see PYTHON_DISAGREES).
interface Probe {
address: string;
family: 4 | 6;
block: string | null;
embedded?: string;
allocation?: string;
global: boolean;
python: {
loopback: boolean;
linkLocal: boolean;
multicast: boolean;
unspecified: boolean;
global: boolean;
};
}
const probes = corpus as Probe[];
// Blocks where Python 3.14's ipaddress and the registry disagree on global
// reachability. The registry is the authority here.
const PYTHON_DISAGREES: Array = [
new Address4('192.88.99.2/32'), // 6a44-relay anycast: registry false, Python true
new Address6('100:0:0:1::/64'), // Dummy IPv6 Prefix: registry false, Python true
new Address6('2001:1::3/128'), // DNS-SD SRP anycast: registry true, Python false
new Address6('5f00::/16'), // SRv6 SIDs: registry false, Python true
];
function parse(probe: Probe): Address4 | Address6 {
return probe.family === 4 ? new Address4(probe.address) : new Address6(probe.address);
}
// Python classifies the NAT64 well-known prefix by its IPv6 block; the
// library, like the mapped form, answers for the embedded IPv4 address, so
// Python's view of those probes is not comparable. Python also treats any
// IPv6 address outside a special-purpose block as global, including reserved
// space the IANA IPv6 Address Space Registry never allocated (fec0::/10,
// 4000::/3, ::/96), which the library reports as not global.
function pythonComparable(probe: Probe, address: Address4 | Address6): boolean {
if (address instanceof Address6 && address.embeddedIPv4() && !address.isMapped4()) {
return false;
}
return !(probe.family === 6 && probe.block === null && probe.allocation !== 'Global Unicast');
}
function inException(address: Address4 | Address6): boolean {
const embedded = address instanceof Address6 ? address.embeddedIPv4() : null;
const subject = embedded ?? address;
return PYTHON_DISAGREES.some(
(subnet) =>
subnet.constructor === subject.constructor && subject.isHostInSubnet(subnet as never),
);
}
describe('IANA special-purpose registry corpus', () => {
it('has probes from both registries', () => {
probes.filter((p) => p.family === 4).length.should.be.greaterThan(100);
probes.filter((p) => p.family === 6).length.should.be.greaterThan(100);
});
it('isGlobal() agrees with the registry on every probe', () => {
probes.forEach((probe) => {
should.equal(parse(probe).isGlobal(), probe.global, `${probe.address} (${probe.block})`);
});
});
it('isLoopback, isLinkLocal, isMulticast, and isUnspecified agree with Python', () => {
probes.forEach((probe) => {
const address = parse(probe);
if (!pythonComparable(probe, address)) {
return;
}
const context = `${probe.address} (${probe.block})`;
should.equal(address.isLoopback(), probe.python.loopback, context);
should.equal(address.isLinkLocal(), probe.python.linkLocal, context);
should.equal(address.isMulticast(), probe.python.multicast, context);
should.equal(address.isUnspecified(), probe.python.unspecified, context);
});
});
it('isGlobal() agrees with Python outside the documented exceptions', () => {
probes.forEach((probe) => {
const address = parse(probe);
if (!pythonComparable(probe, address) || inException(address)) {
return;
}
// Python calls multicast global; the library does not.
should.equal(
address.isGlobal(),
probe.python.global && !probe.python.multicast,
`${probe.address} (${probe.block})`,
);
});
});
it('every documented exception still disagrees', () => {
// Delete the entry from PYTHON_DISAGREES once Python and the registry agree.
PYTHON_DISAGREES.forEach((subnet) => {
const inside = probes.filter((probe) => {
const address = parse(probe);
return (
!probe.embedded &&
subnet.constructor === address.constructor &&
address.isHostInSubnet(subnet as never)
);
});
inside.length.should.be.greaterThan(0, subnet.address);
inside
.some((probe) => probe.python.global !== probe.global)
.should.equal(true, `${subnet.address}: Python now agrees with the registry`);
});
});
});
beaugunderson-ip-address-438375e/test/node-12-smoke.js 0000664 0000000 0000000 00000006167 15272410673 0022507 0 ustar 00root root 0000000 0000000 // A dependency-free smoke test of the built `dist` output, run by CI on the
// oldest node version `engines` claims. The dev toolchain (mocha, tsx, c8)
// needs a modern node, so the real suite cannot run there; this covers what
// actually breaks a consumer on an old runtime, which is emitted syntax the
// runtime cannot parse. Keep it to es2019 so a failure here is always about
// dist and never about this file.
const assert = require('assert');
const { Address4, Address6, AddressError } = require('../dist/ip-address');
// v4 parsing and forms
const v4 = new Address4('127.0.0.1');
assert.strictEqual(v4.correctForm(), '127.0.0.1');
assert.strictEqual(v4.toHex(), '7f:00:00:01');
assert.strictEqual(v4.bigInt().toString(), '2130706433');
assert.strictEqual(Address4.isValid('127.0.0.1'), true);
assert.strictEqual(Address4.isValid('127.0.0.999'), false);
// v4 subnets
const v4Subnet = new Address4('10.0.0.0/8');
assert.strictEqual(v4Subnet.startAddress().correctForm(), '10.0.0.0');
assert.strictEqual(v4Subnet.endAddress().correctForm(), '10.255.255.255');
assert.strictEqual(new Address4('10.1.2.3').isInSubnet(v4Subnet), true);
assert.strictEqual(new Address4('11.1.2.3').isInSubnet(v4Subnet), false);
// v4 conversions
assert.strictEqual(Address4.fromBigInt(BigInt('2130706433')).correctForm(), '127.0.0.1');
assert.strictEqual(Address4.fromInteger(2130706433).correctForm(), '127.0.0.1');
assert.strictEqual(Address4.fromHex('7f000001').correctForm(), '127.0.0.1');
// v6 parsing and forms
const v6 = new Address6('2001:0db8:0000:0000:0000:0000:0000:0001');
assert.strictEqual(v6.correctForm(), '2001:db8::1');
assert.strictEqual(v6.canonicalForm(), '2001:0db8:0000:0000:0000:0000:0000:0001');
assert.strictEqual(v6.to4in6(), '2001:db8::0.0.0.1');
assert.strictEqual(v6.reverseForm({ omitSuffix: true }).length > 0, true);
assert.strictEqual(Address6.isValid('2001:db8::1'), true);
assert.strictEqual(Address6.isValid('fffff::1'), false);
// v6 subnets and BigInt round-tripping
const v6Subnet = new Address6('2001:db8::/32');
assert.strictEqual(new Address6('2001:db8::1').isInSubnet(v6Subnet), true);
assert.strictEqual(Address6.fromBigInt(v6.bigInt()).correctForm(), '2001:db8::1');
assert.throws(() => Address6.fromBigInt(BigInt(-1)), AddressError);
// v6 from other representations
const bytes = [32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
assert.strictEqual(Address6.fromAddress4('127.0.0.1').correctForm(), '::ffff:7f00:1');
assert.strictEqual(Address6.fromByteArray(bytes).correctForm(), '2001:db8::1');
// URL parsing: the code path whose nullish coalescing broke node 12 outright
const withPort = Address6.fromURL('http://[2001:db8::1]:8080/foo');
assert.strictEqual(withPort.address.correctForm(), '2001:db8::1');
assert.strictEqual(withPort.port, 8080);
const withoutPort = Address6.fromURL('http://2001:db8::1/');
assert.strictEqual(withoutPort.address.correctForm(), '2001:db8::1');
assert.strictEqual(withoutPort.port, null);
// Errors still carry parse detail
assert.throws(() => new Address4('not an address'), AddressError);
// eslint-disable-next-line no-console
console.log(`node ${process.version}: dist smoke test passed`);
beaugunderson-ip-address-438375e/test/readme-test.ts 0000664 0000000 0000000 00000004223 15272410673 0022441 0 ustar 00root root 0000000 0000000 import * as chai from 'chai';
import * as fs from 'node:fs';
import * as path from 'node:path';
const { expect } = chai;
const README = fs.readFileSync(path.join(__dirname, '..', 'README.md'), 'utf8');
// Every API bullet is a backticked signature at the start of a list item
const SIGNATURES = README.split('\n')
.filter((line) => line.startsWith('- `'))
.map((line) => line.slice(3, line.indexOf('`', 3)));
describe('the generated API reference', () => {
it('finds signatures to check', () => {
expect(SIGNATURES.length).to.be.above(80);
});
it('never presents a `this` annotation as an argument', () => {
// `this` is a TypeScript type annotation, so rendering it makes a
// one-argument method read as taking two
const leaked = SIGNATURES.filter((s) => /\(this:|, this:/.test(s));
expect(leaked, `these signatures expose a \`this\` parameter: ${leaked.join(', ')}`).to.eql(
[],
);
});
it('marks parameters that carry a default as optional', () => {
// TypeDoc sets isOptional inconsistently for defaulted parameters, so a
// caller reading these would think the argument is required
const expected = [
'static fromAddress4Nat64(address: string, prefix?: string): Address6',
'toAddress4Nat64(prefix?: string): Address4 | null',
'regularExpressionString(substringSearch?: boolean): string',
'regularExpression(substringSearch?: boolean): RegExp',
'mask(mask?: number): string',
'possibleSubnets(subnetSize?: number): string',
];
expected.forEach((signature) => {
expect(SIGNATURES, `missing: ${signature}`).to.include(signature);
});
});
it('documents the methods that return HTML as returning HTML', () => {
// These are the surfaces GHSA-v2v4-37r5-5v8g was about; a reader who
// doesn't know they emit markup can't reason about escaping them
['group()', 'groupForV6()', 'link('].forEach((method) => {
const bullet = README.split('\n').find((line) => line.startsWith(`- \`${method}`));
expect(bullet, `no API bullet for ${method}`).to.be.a('string');
expect(bullet, `${method} does not mention HTML`).to.match(/HTML/);
});
});
});
beaugunderson-ip-address-438375e/tsconfig.json 0000664 0000000 0000000 00000002247 15272410673 0021413 0 ustar 00root root 0000000 0000000 {
"compilerOptions": {
// Node 12 is the oldest runtime `engines` claims, and it predates
// nullish coalescing and optional chaining. Emitting for es2019 makes tsc
// downlevel those and reject any newer syntax at compile time, so the
// published output cannot drift past what node 12 can parse. `lib` stays
// at es2020 for the BigInt types; BigInt itself exists in node 12.
"target": "es2019",
"module": "commonjs",
"allowJs": true,
"declaration": true,
"declarationMap": false,
"rootDir": "./src",
"outDir": "./dist",
"resolveJsonModule": true,
"sourceMap": true,
"inlineSources": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"lib": ["es2020"]
},
"include": ["./src/**/*.ts"]
}