pax_global_header 0000666 0000000 0000000 00000000064 15233026452 0014514 g ustar 00root root 0000000 0000000 52 comment=fbb8db28f1559842b7191cab7d8ea6408ed82f7b
beaugunderson-ip-address-e54ae23/ 0000775 0000000 0000000 00000000000 15233026452 0017020 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/.eslintignore 0000664 0000000 0000000 00000000023 15233026452 0021516 0 ustar 00root root 0000000 0000000 dist/
node_modules/ beaugunderson-ip-address-e54ae23/.eslintrc.js 0000664 0000000 0000000 00000005735 15233026452 0021271 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-e54ae23/.github/ 0000775 0000000 0000000 00000000000 15233026452 0020360 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/.github/workflows/ 0000775 0000000 0000000 00000000000 15233026452 0022415 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/.github/workflows/ci.yml 0000664 0000000 0000000 00000006471 15233026452 0023543 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
git diff --exit-code README.md || {
echo 'README.md is out of date; run `npm run docs` and commit the result.'
exit 1
}
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-e54ae23/.github/workflows/release.yml 0000664 0000000 0000000 00000001636 15233026452 0024566 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-e54ae23/.gitignore 0000664 0000000 0000000 00000000250 15233026452 0021005 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-e54ae23/.mocharc.yml 0000664 0000000 0000000 00000000211 15233026452 0021227 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-e54ae23/.prettierignore 0000664 0000000 0000000 00000000236 15233026452 0022064 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-e54ae23/.prettierrc 0000664 0000000 0000000 00000000110 15233026452 0021174 0 ustar 00root root 0000000 0000000 {
"printWidth": 99,
"singleQuote": true,
"trailingComma": "all"
}
beaugunderson-ip-address-e54ae23/.vscode/ 0000775 0000000 0000000 00000000000 15233026452 0020361 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/.vscode/settings.json 0000664 0000000 0000000 00000000513 15233026452 0023113 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-e54ae23/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000006223 15233026452 0021622 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-e54ae23/LICENSE 0000664 0000000 0000000 00000002045 15233026452 0020026 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-e54ae23/README.md 0000664 0000000 0000000 00000116424 15233026452 0020307 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=master)
[![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=master
[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 all standard IPv4 and IPv6 notations, including subnets and zones
- 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 an IPv4 address as the second 16 bits of a `2002::/16` IPv6 address. `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/master/src/ipv4.ts#L53)
- `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/master/src/ipv4.ts#L110)
- `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/master/src/ipv4.ts#L124)
- `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/master/src/ipv4.ts#L145)
- `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/master/src/ipv4.ts#L180)
- `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/master/src/ipv4.ts#L203)
- `static fromArpa(arpaFormAddress: string): Address4` — Return an address from in-addr.arpa form [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L219)
- `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/master/src/ipv4.ts#L366)
- `static fromByteArray(bytes: number[]): Address4` — Convert a byte array to an Address4 object. To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L381)
- `static fromUnsignedByteArray(bytes: number[]): Address4` — Convert an unsigned byte array to an Address4 object [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L392)
**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/master/src/ipv4.ts#L70)
- `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/master/src/ipv4.ts#L91)
- `toHex(): string` — Converts an IPv4 address object to a hex string [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L232)
- `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/master/src/ipv4.ts#L242)
- `toGroup6(): string` — Converts an IPv4 address object to an IPv6 address group [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L250)
- `bigInt(): bigint` — Returns the address as a `bigint` [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L269)
- `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/master/src/ipv4.ts#L286)
- `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/master/src/ipv4.ts#L295)
- `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/master/src/ipv4.ts#L313)
- `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/master/src/ipv4.ts#L322)
- `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/master/src/ipv4.ts#L332)
- `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/master/src/ipv4.ts#L344)
- `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/master/src/ipv4.ts#L356)
- `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/master/src/ipv4.ts#L406)
- `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/master/src/ipv4.ts#L418)
- `reverseForm(options?: ReverseFormOptions): string` — Return the reversed ip6.arpa form of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L428)
- `isMulticast(): boolean` — Returns true if the given address is a multicast address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L460)
- `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/master/src/ipv4.ts#L468)
- `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/master/src/ipv4.ts#L476)
- `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/master/src/ipv4.ts#L484)
- `isUnspecified(): boolean` — Returns true if the address is the unspecified address `0.0.0.0`. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L492)
- `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/master/src/ipv4.ts#L500)
- `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/master/src/ipv4.ts#L508)
- `binaryZeroPad(): string` — Returns a zero-padded base-2 string representation of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L516)
- `groupForV6(): string` — Groups an IPv4 address for inclusion at the end of an IPv6 address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L527)
**Properties**
- `address: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L14)
- `addressMinusSuffix: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L15)
- `groups: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L16)
- `parsedAddress: string[]` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L17)
- `parsedSubnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L18)
- `subnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L19)
- `subnetMask: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L20)
- `v4: boolean` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L21)
- `isCorrect: (this: Address4 | Address6) => boolean` — Returns true if the address is correct, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L99)
- `isInSubnet: (this: Address4 | Address6, address: Address4 | Address6) => boolean` — Returns true if the given address is in the subnet of the current address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L446)
- `isHostInSubnet: (this: Address4 | Address6, address: Address4 | Address6) => boolean` — Returns true if this address's host bits fall inside the given subnet, ignoring this address's own subnet mask. See common.isHostInSubnet. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L454)
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/master/src/ipv6.ts#L167)
- `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/master/src/ipv6.ts#L188)
- `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/master/src/ipv6.ts#L213)
- `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/master/src/ipv6.ts#L277)
- `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/master/src/ipv6.ts#L291)
- `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/master/src/ipv6.ts#L313)
- `static fromAddress4(address: string): Address6` — Create an IPv6-mapped address given an IPv4 address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L374)
- `static fromArpa(arpaFormAddress: string): Address6` — Return an address from ip6.arpa form [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L390)
- `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/master/src/ipv6.ts#L1060)
- `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/master/src/ipv6.ts#L1175)
- `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/master/src/ipv6.ts#L1192)
**Instance methods**
- `microsoftTranscription(): string` — Return the Microsoft UNC transcription of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L416)
- `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/master/src/ipv6.ts#L425)
- `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/master/src/ipv6.ts#L435)
- `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/master/src/ipv6.ts#L460)
- `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/master/src/ipv6.ts#L469)
- `endAddress(): Address6` — 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/master/src/ipv6.ts#L487)
- `endAddressExclusive(): Address6` — 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/master/src/ipv6.ts#L496)
- `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/master/src/ipv6.ts#L506)
- `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/master/src/ipv6.ts#L518)
- `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/master/src/ipv6.ts#L531)
- `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/master/src/ipv6.ts#L543)
- `getType(): string` — Return the type of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L570)
- `getBits(start: number, end: number): bigint` — Return the bits in the given range as a BigInt [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L585)
- `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/master/src/ipv6.ts#L593)
- `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/master/src/ipv6.ts#L601)
- `getBitsPastSubnet(): string` — Return the bits that are set past the subnet mask length [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L617)
- `reverseForm(options?: ReverseFormOptions): string` — Return the reversed ip6.arpa form of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L627)
- `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/master/src/ipv6.ts#L662)
- `binaryZeroPad(): string` — Return a zero-padded base-2 string representation of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L724)
- `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/master/src/ipv6.ts#L738)
- `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/master/src/ipv6.ts#L795)
- `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/master/src/ipv6.ts#L875)
- `decimal(): string` — Return the decimal form of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L883)
- `bigInt(): bigint` — Return the address as a BigInt [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L891)
- `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/master/src/ipv6.ts#L906)
- `to4in6(): string` — Return the v4-in-v6 form of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L930)
- `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/master/src/ipv6.ts#L951)
- `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/master/src/ipv6.ts#L1014)
- `to6to4(): Address6 | null` — Return a v6 6to4 address from a v6 v4inv6 address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1034)
- `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/master/src/ipv6.ts#L1103)
- `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/master/src/ipv6.ts#L1138)
- `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/master/src/ipv6.ts#L1157)
- `isCanonical(): boolean` — Returns true if the address is in the canonical form, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1233)
- `isLinkLocal(): boolean` — Returns true if the address is a link local address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1241)
- `isMulticast(): boolean` — Returns true if the address is a multicast address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1262)
- `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/master/src/ipv6.ts#L1279)
- `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/master/src/ipv6.ts#L1291)
- `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/master/src/ipv6.ts#L1312)
- `isTeredo(): boolean` — Returns true if the address is a Teredo address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1324)
- `is6to4(): boolean` — Returns true if the address is a 6to4 address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1332)
- `isLoopback(): boolean` — Returns true if the address is a loopback address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1340)
- `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/master/src/ipv6.ts#L1353)
- `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)) or an IPv4-mapped / NAT64 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. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1367)
- `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/master/src/ipv6.ts#L1384)
- `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/master/src/ipv6.ts#L1401)
- `isUnspecified(): boolean` — Returns true if the address is the unspecified address `::`. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1414)
- `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/master/src/ipv6.ts#L1427)
- `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/master/src/ipv6.ts#L1438)
- `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/master/src/ipv6.ts#L1456)
- `group(): string` — Groups an address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1496)
- `regularExpressionString(this: Address6, 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/master/src/ipv6.ts#L1548)
- `regularExpression(this: Address6, 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/master/src/ipv6.ts#L1602)
**Properties**
- `address4: Address4` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L97)
- `address: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L98)
- `addressMinusSuffix: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L99)
- `elidedGroups: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L100)
- `elisionBegin: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L101)
- `elisionEnd: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L102)
- `groups: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L103)
- `parsedAddress4: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L104)
- `parsedAddress: string[]` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L105)
- `parsedSubnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L106)
- `subnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L107)
- `subnetMask: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L108)
- `v4: boolean` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L109)
- `zone: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L110)
- `isInSubnet: (this: Address4 | Address6, address: Address4 | Address6) => boolean` — Returns true if the given address is in the subnet of the current address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1213)
- `isHostInSubnet: (this: Address4 | Address6, address: Address4 | Address6) => boolean` — Returns true if this address's host bits fall inside the given subnet, ignoring this address's own subnet mask. See common.isHostInSubnet. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1221)
- `isCorrect: (this: Address4 | Address6) => boolean` — Returns true if the address is correct, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1227)
AddressError
**Constructor**
- `new AddressError(message: string, parseMessage?: string): AddressError`
**Properties**
- `parseMessage: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/address-error.ts#L2)
### 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.
### Used by
`ip-address` is downloaded ~66 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) (~57M 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) (~44M 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-e54ae23/SECURITY.md 0000664 0000000 0000000 00000004715 15233026452 0020620 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.
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-e54ae23/coverage.sh 0000775 0000000 0000000 00000000076 15233026452 0021155 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
set -e
mkdir -p coverage
npm run test-ci
beaugunderson-ip-address-e54ae23/hooks/ 0000775 0000000 0000000 00000000000 15233026452 0020143 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/hooks/pre-commit 0000775 0000000 0000000 00000000460 15233026452 0022145 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
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-e54ae23/package-lock.json 0000664 0000000 0000000 00000652310 15233026452 0022243 0 ustar 00root root 0000000 0000000 {
"name": "ip-address",
"version": "10.4.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ip-address",
"version": "10.4.0",
"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": "^11.7.5",
"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/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
"strip-ansi": "^7.0.1",
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
"wrap-ansi": "^8.1.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-regex": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-styles": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@isaacs/cliui/node_modules/strip-ansi": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
"integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.2.2"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"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/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
"node": ">=14"
}
},
"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.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
"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.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"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.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
"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": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
},
"engines": {
"node": ">= 14.16.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/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"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/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
"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/flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"dev": true,
"bin": {
"flat": "cli.js"
}
},
"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/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true,
"bin": {
"he": "bin/he"
}
},
"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,
"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/jackspeak": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
},
"optionalDependencies": {
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/js-yaml": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
"integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
"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/log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"dev": true,
"dependencies": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/lru-cache": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true,
"license": "ISC"
},
"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.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz",
"integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==",
"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": "11.7.5",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz",
"integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==",
"dev": true,
"license": "MIT",
"dependencies": {
"browser-stdout": "^1.3.1",
"chokidar": "^4.0.1",
"debug": "^4.3.5",
"diff": "^7.0.0",
"escape-string-regexp": "^4.0.0",
"find-up": "^5.0.0",
"glob": "^10.4.5",
"he": "^1.2.0",
"is-path-inside": "^3.0.3",
"js-yaml": "^4.1.0",
"log-symbols": "^4.1.0",
"minimatch": "^9.0.5",
"ms": "^2.1.3",
"picocolors": "^1.1.1",
"serialize-javascript": "^6.0.2",
"strip-json-comments": "^3.1.1",
"supports-color": "^8.1.1",
"workerpool": "^9.2.0",
"yargs": "^17.7.2",
"yargs-parser": "^21.1.1",
"yargs-unparser": "^2.0.0"
},
"bin": {
"_mocha": "bin/_mocha",
"mocha": "bin/mocha.js"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/mocha/node_modules/brace-expansion": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz",
"integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/mocha/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/mocha/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/mocha/node_modules/glob": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
"integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"dev": true,
"license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
"minimatch": "^9.0.4",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^1.11.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"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/minimatch": {
"version": "9.0.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/mocha/node_modules/path-scurry": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
},
"engines": {
"node": ">=16 || 14 >=14.18"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/mocha/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/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/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"dev": true,
"license": "BlueOak-1.0.0"
},
"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": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14.18.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.0.5",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz",
"integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==",
"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-cjs": {
"name": "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,
"license": "MIT",
"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-cjs/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,
"license": "MIT"
},
"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-ansi-cjs": {
"name": "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,
"license": "MIT",
"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.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
"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": "9.3.4",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz",
"integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/wrap-ansi-cjs": {
"name": "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/wrap-ansi-cjs/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/wrap-ansi-cjs/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/wrap-ansi-cjs/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/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/yargs-unparser": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
"integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
"dev": true,
"dependencies": {
"camelcase": "^6.0.0",
"decamelize": "^4.0.0",
"flat": "^5.0.2",
"is-plain-obj": "^2.1.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/yargs-unparser/node_modules/camelcase": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/yargs-unparser/node_modules/decamelize": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
"integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/yargs-unparser/node_modules/is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"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-e54ae23/package.json 0000664 0000000 0000000 00000004400 15233026452 0021304 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.4.0",
"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",
"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": "^11.7.5",
"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-e54ae23/scripts/ 0000775 0000000 0000000 00000000000 15233026452 0020507 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/scripts/build-readme.ts 0000664 0000000 0000000 00000016444 15233026452 0023422 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/master';
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 renderSignature(name: string, sig: TypeDoc.SignatureReflection): string {
const params = (sig.parameters ?? [])
.map((p) => {
const optional = p.flags.isOptional ? '?' : '';
const typeStr = renderType(p.type);
return `${p.name}${optional}: ${typeStr}`;
})
.join(', ');
const returnType = renderType(sig.type);
return `${name}(${params}): ${returnType}`;
}
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 = renderType(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}`;
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-e54ae23/scripts/readme-template.md 0000664 0000000 0000000 00000017337 15233026452 0024112 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=master)
[![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=master
[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 all standard IPv4 and IPv6 notations, including subnets and zones
- 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 an IPv4 address as the second 16 bits of a `2002::/16` IPv6 address. `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.
### Used by
`ip-address` is downloaded ~66 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) (~57M 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) (~44M 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-e54ae23/src/ 0000775 0000000 0000000 00000000000 15233026452 0017607 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/src/address-error.ts 0000664 0000000 0000000 00000000336 15233026452 0022735 0 ustar 00root root 0000000 0000000 export class AddressError extends Error {
parseMessage?: string;
constructor(message: string, parseMessage?: string) {
super(message);
this.name = 'AddressError';
this.parseMessage = parseMessage;
}
}
beaugunderson-ip-address-e54ae23/src/common.ts 0000664 0000000 0000000 00000007557 15233026452 0021465 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.
*/
export function isHostInSubnet(this: Address4 | Address6, address: Address4 | Address6) {
return this.mask(address.subnetMask) === address.mask();
}
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;
return binaryValue.substring(positionInString, positionInString + 1) === '1';
}
beaugunderson-ip-address-e54ae23/src/ip-address.ts 0000664 0000000 0000000 00000000300 15233026452 0022203 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-e54ae23/src/ipv4.ts 0000664 0000000 0000000 00000040530 15233026452 0021043 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, '');
}
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
* @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 {
// remove ending ".in-addr.arpa." or just "."
const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.$/, '');
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);
}
/**
* 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.
*
* 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
* @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 ip6.arpa form of the address
* @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
* @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. See
* {@link common.isHostInSubnet}.
* @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 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 {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');
beaugunderson-ip-address-e54ae23/src/ipv6.ts 0000664 0000000 0000000 00000137254 15233026452 0021057 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.');
}
const zone = constants6.RE_ZONE_STRING.exec(address);
if (zone) {
this.zone = zone[0];
address = address.replace(constants6.RE_ZONE_STRING, '');
}
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;
// 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) {
result = constants6.RE_URL_WITH_PORT.exec(stripped);
if (result === null) {
return {
error: 'failed to parse address with port',
address: null,
port: null,
};
}
host = result[1];
port = result[2];
} else {
result = constants6.RE_URL.exec(stripped);
if (result === null) {
return {
error: 'failed to parse address from URL',
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;
}
return {
address: new Address6(host),
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
* @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'
*/
static fromArpa(arpaFormAddress: string): Address6 {
// remove ending ".ip6.arpa." or just "."
let address = arpaFormAddress.replace(/(\.ip6\.arpa)?\.$/, '');
const semicolonAmount = 7;
// correct ip6.arpa form with ending removed will be 63 characters
if (address.length !== 63) {
throw new AddressError("Invalid 'ip6.arpa' form.");
}
const parts = address.split('.').reverse();
for (let i = semicolonAmount; i > 0; i--) {
const insertIndex = i * 4;
parts.splice(insertIndex, 0, ':');
}
address = parts.join('');
return new Address6(address);
}
/**
* 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' subnet
* Often referred to as the Broadcast
* @returns {Address6}
*/
endAddress(): Address6 {
return Address6.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 {Address6}
*/
endAddressExclusive(): Address6 {
const adjust = BigInt('1');
return Address6.fromBigInt(this._endAddress() - adjust);
}
/**
* 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, '$1'),
);
}
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
* @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. See
* {@link common.isHostInSubnet}.
* @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 address, false otherwise
* @returns {boolean}
*/
isLinkLocal(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isLinkLocal();
}
// Zeroes are required, i.e. we can't check isHostInSubnet with 'fe80::/10'
if (
this.getBitsBase2(0, 64) ===
'1111111010000000000000000000000000000000000000000000000000000000'
) {
return true;
}
return false;
}
/**
* 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)) or an
* IPv4-mapped / NAT64 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.
* @returns {boolean}
*/
isPrivate(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isPrivate();
}
return this.isULA();
}
/**
* 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 this.isHostInSubnet(DOCUMENTATION_SUBNET);
}
// #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 {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 DOCUMENTATION_SUBNET = new Address6('2001:db8::/32');
const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96');
const NAT64_WELL_KNOWN_SUBNET = new Address6('64:ff9b::/96');
beaugunderson-ip-address-e54ae23/src/v4/ 0000775 0000000 0000000 00000000000 15233026452 0020140 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/src/v4/constants.ts 0000664 0000000 0000000 00000001142 15233026452 0022522 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}$/;
beaugunderson-ip-address-e54ae23/src/v6/ 0000775 0000000 0000000 00000000000 15233026452 0020142 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/src/v6/constants.ts 0000664 0000000 0000000 00000005046 15233026452 0022533 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',
'2002::/16': '6to4',
'2001:db8::/32': 'Documentation',
'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
*/
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;
beaugunderson-ip-address-e54ae23/src/v6/helpers.ts 0000664 0000000 0000000 00000002772 15233026452 0022164 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-e54ae23/src/v6/regular-expressions.ts 0000664 0000000 0000000 00000004526 15233026452 0024542 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-e54ae23/test/ 0000775 0000000 0000000 00000000000 15233026452 0017777 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/test/.eslintrc 0000664 0000000 0000000 00000000067 15233026452 0021626 0 ustar 00root root 0000000 0000000 {
"env": {
"node": true,
"mocha": true
}
}
beaugunderson-ip-address-e54ae23/test/address-test.ts 0000664 0000000 0000000 00000015552 15233026452 0022761 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-e54ae23/test/common-test.ts 0000664 0000000 0000000 00000003001 15233026452 0022606 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('testBit', () => {
it('should return value per specific bit', () => {
should.equal(testBit('0', 1), false);
should.equal(testBit('1', 1), true);
should.equal(testBit('1010', 1), false);
should.equal(testBit('1010', 2), true);
should.equal(testBit('1010', 3), false);
should.equal(testBit('1010', 4), true);
// Length bigger than the size of string
should.equal(testBit('1010', 5), false);
});
});
beaugunderson-ip-address-e54ae23/test/data/ 0000775 0000000 0000000 00000000000 15233026452 0020710 5 ustar 00root root 0000000 0000000 beaugunderson-ip-address-e54ae23/test/data/intermapper-invalid-ipv6-addresses.json 0000664 0000000 0000000 00000057041 15233026452 0030421 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-e54ae23/test/data/intermapper-valid-ipv6-addresses.json 0000664 0000000 0000000 00000031575 15233026452 0030076 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-e54ae23/test/data/invalid-ipv4-addresses.json 0000664 0000000 0000000 00000001455 15233026452 0026071 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-e54ae23/test/data/invalid-ipv6-addresses.json 0000664 0000000 0000000 00000060563 15233026452 0026100 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-e54ae23/test/data/valid-ipv4-addresses.json 0000664 0000000 0000000 00000000514 15233026452 0025535 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-e54ae23/test/data/valid-ipv6-addresses.json 0000664 0000000 0000000 00000040455 15233026452 0025547 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-e54ae23/test/functionality-v4-test.ts 0000664 0000000 0000000 00000063621 15233026452 0024553 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('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('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('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-e54ae23/test/functionality-v6-test.ts 0000664 0000000 0000000 00000164023 15233026452 0024553 0 ustar 00root root 0000000 0000000 import * as chai from 'chai';
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('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('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('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');
});
});
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 an invalid ip6.arpa length', () => {
should.Throw(() =>
Address6.fromArpa('e.f.f.f.3.c.2.6.f.f.f.e.6.6.8.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);
});
});
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 is not extracted via the trailing 32 bits
]).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);
});
});
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);
});
});
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('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-e54ae23/test/node-12-smoke.js 0000664 0000000 0000000 00000006167 15233026452 0022630 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-e54ae23/tsconfig.json 0000664 0000000 0000000 00000002247 15233026452 0021534 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"]
}