From 7c43dd1281b0b67b53e88e1cea5dc372d24f990d Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 19 Jul 2025 18:31:31 +0300 Subject: [PATCH 1/7] Refactored the codebase --- src/IP.ts | 30 +++++ src/IPAddress.ts | 58 ++++++++-- src/IPv4.ts | 41 ++++--- src/IPv6.ts | 52 +++++---- src/Network.ts | 104 ++--------------- src/Subnet.ts | 281 ++++++++++++++++++++++++++++++++++++++-------- src/SubnetList.ts | 208 ++++++++++++++++++++++++++++++++++ src/index.ts | 4 +- 8 files changed, 593 insertions(+), 185 deletions(-) create mode 100644 src/IP.ts create mode 100644 src/SubnetList.ts diff --git a/src/IP.ts b/src/IP.ts new file mode 100644 index 0000000..3e1b87f --- /dev/null +++ b/src/IP.ts @@ -0,0 +1,30 @@ +/* + * Copyright © 2025 Cloudnode OÜ. + * + * This file is part of @cldn/ip. + * + * @cldn/ip is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser + * General Public License as published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * @cldn/ip is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with @cldn/ip. + * If not, see + */ +import {IPv4} from "./IPv4.js"; +import {IPv6} from "./IPv6.js"; + +/** + * An {@link IPv4} or {@link IPv6} address. + */ +export type IP = IPv4 | IPv6; + +export namespace IP { + /** + * An {@link IPv4} or {@link IPv6} address class. + */ + export type Class = typeof IPv4 | typeof IPv6; +} diff --git a/src/IPAddress.ts b/src/IPAddress.ts index 0ec69df..9266e56 100644 --- a/src/IPAddress.ts +++ b/src/IPAddress.ts @@ -14,22 +14,24 @@ * You should have received a copy of the GNU Lesser General Public License along with @cldn/ip. * If not, see . */ -import {IPv4, IPv6} from "./index.js"; +import {IP, IPv4, IPv6} from "./index.js"; /** - * An IP address. + * Represents an Internet Protocol (IP) address. + * + * @sealed */ export abstract class IPAddress { /** - * The integer representation of the IP address. + * Integer representation of the IP address. */ public readonly value: bigint; /** * Creates a new IP address instance. * - * @param value The integer representation of the IP address. - * @deprecated This class will be sealed in v2.0.0 and should not be extended by public API users. + * @param value Integer representation of the IP address. + * @internal */ protected constructor(value: bigint) { this.value = value; @@ -38,27 +40,59 @@ export abstract class IPAddress { /** * Creates an IP address from a string. * - * @throws {@link !RangeError} If provided string is not a valid IPv4 or IPv6 address + * @param ip String representation of the IP address. + * @param [resolveMapped=false] Whether to resolve IPv4-mapped IPv6 addresses (see {@link IPv6.hasMappedIPv4}). + * @throws {@link !RangeError} If the string is not a valid IPv4 or IPv6 address. */ - public static fromString(str: string): IPv4 | IPv6 { - if (str.includes(":")) return IPv6.fromString(str); - return IPv4.fromString(str); + public static fromString(ip: string, resolveMapped = false): IP { + if (ip.includes(":")) { + const ipv6 = IPv6.fromString(ip); + if (resolveMapped && ipv6.hasMappedIPv4()) + return ipv6.getMappedIPv4(); + return ipv6; + } + return IPv4.fromString(ip); } /** - * Gets the IP address binary representation. + * Returns the binary representation of the IP address. */ public abstract binary(): ArrayBufferView; /** - * Checks if the given addresses are equal. + * Checks if the given address is equal to this address. + * + * @param other Address to compare. */ public equals(other: IPAddress): boolean { return other instanceof this.constructor && other.value === this.value; } /** - * Formats the IP address as string. + * Returns the IP address as a bigint or string primitive. + * + * @param hint Preferred primitive type. + */ + public [Symbol.toPrimitive](hint: "number" | "string" | "default"): bigint | string { + if (hint === "string") + return this.toString(); + return this.value; + } + + /** + * Returns the IP address as a string. */ public abstract toString(): string; + + /** + * Returns a new IP address offset by the given amount from this address. + * + * @example ip.offset(1) // Returns the next IP address. + * @example ip.offset(-1) // Returns the previous IP address. + * @example IPAddress.fromString("203.0.113.42").offset(-18) // Returns 203.0.113.24. + * + * @param offset Number of steps to offset, positive or negative. + * @throws {@link !TypeError} If the resulting address is outside the IP address family range. + */ + public abstract offset(offset: number | bigint): IPAddress; } diff --git a/src/IPv4.ts b/src/IPv4.ts index f9ff16c..34f6c9d 100644 --- a/src/IPv4.ts +++ b/src/IPv4.ts @@ -17,38 +17,38 @@ import {IPAddress} from "./index.js"; /** - * An IPv4 address. + * Represents an Internet Protocol version 4 (IPv4) address. */ export class IPv4 extends IPAddress { /** - * Regular expression for testing IPv4 addresses in string form. + * Regular expression for testing IPv4 addresses in dotted-decimal string notation. */ - public static regex = /^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/; + public static REGEX = /^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/; /** * Bit length of IPv4 addresses. */ - public static bitLength = 32; + public static BIT_LENGTH = 32; /** * Creates a new IPv4 address instance. * - * @param value A 32-bit unsigned big integer. - * @throws {@link !TypeError} If provided value is not a 32-bit unsigned integer. + * @param value 32-bit unsigned integer. + * @throws {@link !TypeError} If the value is not a 32-bit unsigned integer. */ public constructor(value: bigint); /** * Creates a new IPv4 address instance. * - * @param value A 32-bit unsigned number. - * @throws {@link !TypeError} If provided value is not a 32-bit unsigned integer. + * @param value 32-bit unsigned number. + * @throws {@link !TypeError} If the value is not a 32-bit unsigned integer. */ public constructor(value: number); public constructor(value: number | bigint) { const int = BigInt(value); - if (int < 0n || int > (1n << BigInt(IPv4.bitLength)) - 1n) + if (int < 0n || int > (1n << BigInt(IPv4.BIT_LENGTH)) - 1n) throw new TypeError("Expected 32-bit unsigned integer, got " + int.constructor.name + " " + int.toString(10)); super(int); } @@ -56,8 +56,8 @@ export class IPv4 extends IPAddress { /** * Creates an IPv4 address instance from octets. * - * @param octets A typed array of 4 octets. - * @throws {@link !RangeError} If provided octets are not 4. + * @param octets Typed array of 4 octets. + * @throws {@link !RangeError} If the number of octets is not 4. */ public static fromBinary(octets: Uint8Array): IPv4 { if (octets.length !== 4) throw new RangeError("Expected 4 octets, got " + octets.length); @@ -75,19 +75,19 @@ export class IPv4 extends IPAddress { /** * Creates an IPv4 address instance from a string. * - * @param str A string representation of an IPv4 address. - * @throws {@link !RangeError} If provided string is not a valid IPv4 address. + * @param ip String representation of an IPv4 address. + * @throws {@link !RangeError} If the string is not a valid IPv4 address. */ - public static override fromString(str: string): IPv4 { - const octets = str.split(".", 4).map(octet => Number.parseInt(octet, 10)); + public static override fromString(ip: string): IPv4 { + const octets = ip.split(".", 4).map(octet => Number.parseInt(octet, 10)); if (octets.some(octet => Number.isNaN(octet) || octet < 0 || octet > 255)) - throw new RangeError("Expected valid IPv4 address, got " + str); + throw new RangeError("Expected valid IPv4 address, got " + ip); return IPv4.fromBinary(new Uint8Array(octets)); } /** - * Gets the 4 octets of the IPv4 address. + * Returns the 4 octets of the IPv4 address. */ public override binary(): Uint8Array { return new Uint8Array([ @@ -98,7 +98,14 @@ export class IPv4 extends IPAddress { ].map(Number)); } + /** + * Returns the IP address as a string in dotted-decimal notation. + */ public override toString(): string { return Array.from(this.binary()).map(octet => octet.toString(10)).join("."); } + + public override offset(offset: bigint | number): IPv4 { + return new IPv4(this.value + BigInt(offset)); + } } diff --git a/src/IPv6.ts b/src/IPv6.ts index a9a1c18..0a6ceaa 100644 --- a/src/IPv6.ts +++ b/src/IPv6.ts @@ -17,19 +17,22 @@ import {IPAddress, IPv4, Subnet} from "./index.js"; /** - * An IPv6 address. + * Represents an Internet Protocol version 6 (IPv6) address. */ export class IPv6 extends IPAddress { - public static bitLength = 128; + /** + * Bit length of IPv6 addresses. + */ + public static BIT_LENGTH = 128; /** * Creates a new IPv6 address instance. * - * @param value A 128-bit unsigned big integer. - * @throws {@link !TypeError} If provided value is not a 128-bit unsigned integer. + * @param value 128-bit unsigned integer. + * @throws {@link !TypeError} If the value is not a 128-bit unsigned integer. */ public constructor(value: bigint) { - if (value < 0n || value > ((1n << BigInt(IPv6.bitLength)) - 1n)) + if (value < 0n || value > ((1n << BigInt(IPv6.BIT_LENGTH)) - 1n)) throw new TypeError("Expected 128-bit unsigned integer, got " + value.constructor.name + " 0x" + value.toString(16)); super(value); } @@ -37,8 +40,8 @@ export class IPv6 extends IPAddress { /** * Creates an IPv6 address instance from hextets. * - * @param hextets A typed array of 8 hextets. - * @throws {@link !RangeError} If provided hextets are not 8. + * @param hextets Typed array of 8 hextets. + * @throws {@link !RangeError} If the number of hextets is not 8. */ public static fromBinary(hextets: Uint16Array): IPv6 { if (hextets.length !== 8) throw new RangeError("Expected 8 hextets, got " + hextets.length); @@ -58,11 +61,11 @@ export class IPv6 extends IPAddress { /** * Creates an IPv6 address instance from a string. * - * @param str A string representation of an IPv6 address. - * @throws {@link !RangeError} If provided string is not a valid IPv6 address. + * @param ip String representation of an IPv6 address. + * @throws {@link !RangeError} If the string is not a valid IPv6 address. */ - public static override fromString(str: string): IPv6 { - const parts = str.split("::", 2); + public static override fromString(ip: string): IPv6 { + const parts = ip.split("::", 2); const hextestStart = parts[0]! === "" ? [] : parts[0]!.split(":").flatMap(IPv6.parseHextet); @@ -74,7 +77,7 @@ export class IPv6 extends IPAddress { hextestEnd.some(hextet => Number.isNaN(hextet) || hextet < 0 || hextet > 0xFFFF) || (parts.length === 2 && hextestStart.length + hextestEnd.length > 6) || (parts.length < 2 && hextestStart.length + hextestEnd.length !== 8) - ) throw new RangeError("Expected valid IPv6 address, got " + str); + ) throw new RangeError("Expected valid IPv6 address, got " + ip); const hextets = new Uint16Array(8); hextets.set(hextestStart, 0); @@ -85,10 +88,12 @@ export class IPv6 extends IPAddress { /** * Parses a string hextet into unsigned 16-bit integer. + * + * @param hextet String representation of a hextet. * @internal */ private static parseHextet(hextet: string): number | number[] { - if (IPv4.regex.test(hextet)) { + if (IPv4.REGEX.test(hextet)) { const ip = IPv4.fromString(hextet).binary(); return [ (ip[0]! << 8) | ip[1]!, @@ -99,7 +104,7 @@ export class IPv6 extends IPAddress { } /** - * Gets the 8 hextets of the IPv6 address + * Returns the 8 hextets of the IPv6 address. */ public binary(): Uint16Array { return new Uint16Array([ @@ -115,16 +120,17 @@ export class IPv6 extends IPAddress { } /** - * Checks whether this is an IPv4-mapped IPv6 address. Only works for `::ffff:0:0/96`. + * Checks whether this IPv6 address is an IPv4-mapped IPv6 address as defined by the `::ffff:0:0/96` prefix. This + * method does not detect other IPv4 embedding or tunnelling formats. */ public hasMappedIPv4(): boolean { - return Subnet.IPV4_MAPPED_IPV6.has(this); + return Subnet.IPV4_MAPPED_IPV6.contains(this); } /** - * Gets the IPv4-mapped IPv6 address. + * Returns the IPv4-mapped IPv6 address. * - * @returns An IPv4 address from the least significant 32 bits of this IPv6 address. + * @returns The IPv4 address from the least significant 32 bits of this IPv6 address. * @see {@link IPv6#hasMappedIPv4} */ public getMappedIPv4(): IPv4 { @@ -137,10 +143,18 @@ export class IPv6 extends IPAddress { ])); } + /** + * Returns the IP address as a string in colon-hexadecimal notation. + */ public override toString(): string { const str = Array.from(this.binary()).map(octet => octet.toString(16)).join(":"); - const longest = str.match(/(?:^|:)0(?::0)+(?:$|:)/g)?.reduce((acc, cur) => cur.length > acc.length ? cur : acc, "") ?? null; + const longest = str.match(/(?:^|:)0(?::0)+(?:$|:)/g) + ?.reduce((acc, cur) => cur.length > acc.length ? cur : acc, "") ?? null; if (longest === null) return str; return str.replace(longest, "::"); } + + public override offset(offset: bigint | number): IPv6 { + return new IPv6(this.value + BigInt(offset)); + } } diff --git a/src/Network.ts b/src/Network.ts index 5c6cff6..ab606ae 100644 --- a/src/Network.ts +++ b/src/Network.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024–2025 Cloudnode OÜ + * Copyright © 2025 Cloudnode OÜ. * * This file is part of @cldn/ip. * @@ -12,108 +12,28 @@ * for more details. * * You should have received a copy of the GNU Lesser General Public License along with @cldn/ip. - * If not, see . + * If not, see */ -import {IPv4, IPv6, Subnet} from "./index.js" +import {IP} from "./IP.js"; /** - * A network that can contain multiple subnets. + * A network of IP addresses. */ -export class Network { +export interface Network extends Iterable { /** - * A network of reserved subnets. This network does not contain publicly routable IP addresses. - */ - public static readonly BOGON = new Network([ - // IPv4 - Subnet.fromCIDR("0.0.0.0/8"), - Subnet.fromCIDR("10.0.0.0/8"), - Subnet.fromCIDR("100.64.0.0/10"), - Subnet.fromCIDR("127.0.0.0/8"), - Subnet.fromCIDR("169.254.0.0/16"), - Subnet.fromCIDR("172.16.0.0/12"), - Subnet.fromCIDR("192.0.0.0/24"), - Subnet.fromCIDR("192.0.2.0/24"), - Subnet.fromCIDR("192.88.99.0/24"), - Subnet.fromCIDR("192.168.0.0/16"), - Subnet.fromCIDR("198.18.0.0/15"), - Subnet.fromCIDR("198.51.100.0/24"), - Subnet.fromCIDR("203.0.113.0/24"), - Subnet.fromCIDR("224.0.0.0/4"), - Subnet.fromCIDR("233.252.0.0/24"), - Subnet.fromCIDR("240.0.0.0/4"), - Subnet.fromCIDR("255.255.255.255/32"), - // IPv6 - Subnet.fromCIDR("::/128"), - Subnet.fromCIDR("::1/128"), - Subnet.fromCIDR("64:ff9b:1::/48"), - Subnet.fromCIDR("100::/64"), - Subnet.fromCIDR("2001:20::/28"), - Subnet.fromCIDR("2001:db8::/32"), - Subnet.fromCIDR("3fff::/20"), - Subnet.fromCIDR("5f00::/16"), - Subnet.fromCIDR("fc00::/7"), - Subnet.fromCIDR("fe80::/10"), - ]); - - readonly #subnets: Map> = new Map(); - - /** - * Creates a new network. - * - * @param [subnets] Initial subnets to add to this network. - */ - public constructor(subnets?: Iterable>) { - if (subnets) for (const subnet of subnets) this.add(subnet); - } - - /** - * Adds a subnet to this network. - */ - public add(subnet: Subnet): void { - this.#subnets.set(subnet.toString(), subnet); - } - - /** - * Removes a subnet from this network. + * Determines whether this network contains the provided IP address. * - * @param cidr CIDR notation of the subnet to remove. - */ - public remove(cidr: string): void { - this.#subnets.delete(Subnet.fromCIDR(cidr).toString()); - } - - /** - * Checks if a subnet is in this network. - * - * @param cidr CIDR notation of the subnet to check. - */ - public hasSubnet(cidr: string): boolean { - return this.#subnets.has(Subnet.fromCIDR(cidr).toString()); - } - - /** - * Gets all subnets in this network mapped to their CIDR notation. + * @param address IP address to check. */ - public subnets(): ReadonlyMap> { - return this.#subnets; - } + contains(address: T): boolean; /** - * Checks if an IP address is in this network. - * - * @param address IP address to check. + * Returns the exact number of IP addresses in this network. */ - public has(address: IPv4 | IPv6): boolean { - for (const subnet of this.#subnets.values()) if (subnet.has(address)) return true; - return false; - } + size(): bigint; /** - * Gets the number of addresses in this network. + * Iterates over all IP addresses in this network. */ - public size(): bigint { - let size = 0n; - for (const subnet of this.#subnets.values()) size += subnet.size(); - return size; - } + [Symbol.iterator](): Iterator; } diff --git a/src/Subnet.ts b/src/Subnet.ts index a344bcc..1649ef2 100644 --- a/src/Subnet.ts +++ b/src/Subnet.ts @@ -14,89 +14,170 @@ * You should have received a copy of the GNU Lesser General Public License along with @cldn/ip. * If not, see . */ -import {IPAddress, IPv4, IPv6} from "./index.js"; +import {IP, IPAddress, Network} from "./index.js"; /** - * An address range subnetwork of IP addresses. + * Represents an address range subnetwork of Internet Protocol (IP) addresses. * * @typeParam T IP address family. */ -export class Subnet implements Iterable { +export class Subnet implements Network { /** - * IPv4-mapped IPv6 subnet. + * Subnet for IPv4-mapped IPv6 addresses (`::ffff:0.0.0.0/96`). */ public static readonly IPV4_MAPPED_IPV6 = Subnet.fromCIDR("::ffff:0.0.0.0/96"); /** - * The subnet address (i.e. the first/gateway IP address of the network). + * Subnet address (i.e. the first IP address of the network). */ public readonly address: T; + /** + * Bit length of the subnet prefix. + */ + public readonly prefix: number; + /** * IP address constructor. + * + * @internal */ - readonly #AddressClass: typeof IPv4 | typeof IPv6; + public readonly _AddressClass: IP.Class; /** * Creates a new subnet instance. * - * @param address An IP address. - * @param suffix Subnet suffix bits. - * @throws {@link !RangeError} If the suffix is greater than the IP address family bit-length. + * @param address IP address. + * @param prefix Bit length of the subnet prefix. + * @throws {@link !RangeError} If the prefix is greater than the IP address family bit length, or if negative. */ - public constructor(address: T, public readonly suffix: number) { - this.#AddressClass = address.constructor as typeof IPv4 | typeof IPv6; - if (suffix > this.#AddressClass.bitLength) throw new RangeError("Expected suffix less than " + this.#AddressClass.bitLength + ", got " + suffix); - this.address = new this.#AddressClass(address.value & this.netmask()) as T; + public constructor(address: T, prefix: number) { + this._AddressClass = address.constructor as IP.Class; + if (prefix < 0) + throw new RangeError("Expected positive prefix, got " + prefix); + if (prefix > this._AddressClass.BIT_LENGTH) + throw new RangeError(`Expected prefix less than ${this._AddressClass.BIT_LENGTH}, got ${prefix}`); + this.prefix = prefix; + this.address = new this._AddressClass(address.value & this.netmask()) as T; } /** * Creates a subnet from a string in CIDR notation. * - * @param cidr A string in CIDR notation. - * @throws {@link !RangeError} If the address or suffix is invalid + * @param cidr String in CIDR notation. + * @throws {@link !RangeError} If the address or prefix is invalid. */ - public static fromCIDR(cidr: string): Subnet { + public static fromCIDR(cidr: string): Subnet { const parts = cidr.split("/", 2); if (parts.length !== 2) throw new RangeError("Expected CIDR notation, got " + cidr); - const suffix = Number.parseInt(parts[1]!, 10); - return new Subnet(IPAddress.fromString(parts[0]!), suffix); + const prefix = Number.parseInt(parts[1]!, 10); + if (Number.isNaN(prefix)) throw new RangeError("Expected numeric prefix, got " + parts[1]); + return new Subnet(IPAddress.fromString(parts[0]!) as T, prefix); + } + + /** + * Creates an array of subnets to represent an arbitrary range of IP addresses. + * + * @param start Starting IP address. + * @param end Ending IP address. + */ + public static range(start: T, end: T): Subnet[] { + const AddressClass = start.constructor as IP.Class; + const result: Subnet[] = []; + + let current = start.value; + + while (current <= end.value) { + let tz = 0; + while (tz < AddressClass.BIT_LENGTH && ((current >> BigInt(tz)) & 1n) === 0n) + ++tz; + const prefixAlign = AddressClass.BIT_LENGTH - tz; + + let remaining = end.value - current + 1n; + let maxBlockBits = 0; + while (remaining > 1n) { + remaining >>= 1n; + ++maxBlockBits; + } + const prefixRange = AddressClass.BIT_LENGTH - maxBlockBits; + + const subnet = new Subnet(new AddressClass(current) as T, Math.max(prefixAlign, prefixRange)); + result.push(subnet); + current += subnet.size(); + } + + return result; } /** - * Gets the network mask. + * Returns the network mask of this subnet. */ public netmask(): bigint { - return ((1n << BigInt(this.suffix)) - 1n) << BigInt(this.#AddressClass.bitLength - this.suffix); + return ((1n << BigInt(this.prefix)) - 1n) << BigInt(this._AddressClass.BIT_LENGTH - this.prefix); } /** - * Gets the network wildcard mask. + * Returns the wildcard (host) mask—the inverse of the {@link netmask}. */ public wildcard(): bigint { - return ((1n << BigInt(this.#AddressClass.bitLength - this.suffix)) - 1n); + return (1n << BigInt(this._AddressClass.BIT_LENGTH - this.prefix)) - 1n; } /** - * Gets the last IP address in the subnet (i.e. broadcast address). + * Returns the address at the specific index. + * + * @param index Zero-based index of the address to be returned. Negative index counts from the end of the subnet. + * @returns The address in the subnet matching the given index. Always returns `undefined` if `index < -size()` or + * `index >= size()`. */ - public broadcast(): T { - return new this.#AddressClass(this.address.value | this.wildcard()) as T; + public at(index: 0 | 0n | -1 | -1n): T; + + /** + * Returns the address at the specific index. + * + * @param index Zero-based index of the address to be returned. Negative index counts from the end of the subnet. + * @returns The address in the subnet matching the given index. Always returns `undefined` if `index < -size()` or + * `index >= size()`. + */ + public at(index: bigint): T | undefined; + + /** + * Returns the address at the specific index. + * + * @param index Zero-based index of the address to be returned. Negative index counts from the end of the subnet. + * @returns The address in the subnet matching the given index. Always returns `undefined` if `index < -size()` or + * `index >= size()`. + */ + public at(index: number): T | undefined; + + public at(a: bigint | number): T | undefined { + const index = BigInt(a); + if (index < -this.size() || index >= this.size()) return undefined; + if (index < 0) + return this.at(this.size() + index); + return new this._AddressClass(this.address.value + BigInt(index)) as T; } /** - * Checks if the provided IP address is in this subnet. + * Determines whether the provided address is contained within this subnet. * * @param address IP address to check. */ - public has(address: T): boolean { - if (!(address instanceof this.#AddressClass)) return false; - return (address.value & this.netmask()) === this.address.value; + public contains(address: T): boolean { + return address instanceof this._AddressClass && (address.value & this.netmask()) === this.address.value; } /** - * Gets the number of addresses in this subnet. This number includes the broadcast and gateway addresses, so for the - * number of *usable* addresses, subtract 2. + * Determines whether the provided subnet is fully contained within this subnet. + * + * @param subnet Subnet to check. + */ + public containsSubnet(subnet: Subnet): boolean { + return this.prefix <= subnet.prefix && this.contains(subnet.address); + } + + /** + * Returns the exact number of addresses in this subnet. */ public size(): bigint { return this.wildcard() + 1n; @@ -105,39 +186,151 @@ export class Subnet implements Iterable { /** * Iterates all IP addresses in this subnet. * - * **NOTE**: This can be slow for large subnets. If you need to check if an - * IP address is in the subnet, use {@link Subnet#has}. + * **NOTE**: This can be slow for large subnets. */ - public* iterate(): IterableIterator { - for (let i = this.address.value; i <= this.broadcast().value; ++i) yield new this.#AddressClass(i) as T; + public* addresses(): IterableIterator { + const end = this.address.value + this.size(); + for (let i = this.address.value; i < end; ++i) + yield new this._AddressClass(i) as T; } /** * Iterates all IP addresses in this subnet. * - * **NOTE**: This can be slow for large subnets. If you need to check if an - * IP address is in the subnet, use {@link Subnet#has}. + * **NOTE**: This can be slow for large subnets. */ - public [Symbol.iterator](): IterableIterator { - return this.iterate(); + public [Symbol.iterator](): Iterator { + return this.addresses(); } /** * Creates a set containing all IP addresses in this subnet. * - * **NOTE**: This can be slow for large subnets. If you need to check if an - * IP address is in the subnet, use {@link Subnet#has}. + * **NOTE**: This can be slow for large subnets. */ public set(): Set { - return new Set(this.iterate()); + return new Set(this.addresses()); } /** - * Creates a string representation of this subnet in CIDR notation. + * Returns the string representation of this subnet in CIDR notation. * * @example "203.0.113.0/24" */ public toString(): string { - return this.address.toString() + "/" + this.suffix; + return this.address.toString() + "/" + this.prefix; + } + + /** + * Checks if this subnet is adjacent to another subnet. + * + * @param subnet Subnet to check. + * @throws {@link !TypeError} If the provided subnet is not of the same family. + */ + public isAdjacent(subnet: Subnet): boolean { + if (this._AddressClass !== subnet._AddressClass) + throw new TypeError(`Expected ${this._AddressClass.name} subnet, but got ${subnet._AddressClass.name}.`); + + return (this.address.value + this.size() === subnet.address.value) + || (subnet.address.value + subnet.size() === this.address.value); + } + + /** + * Checks whether another subnet can be merged with this subnet. + * + * @param subnet Subnet to check. + */ + public canMerge(subnet: Subnet): boolean { + if (this.prefix !== subnet.prefix) + return false; + try { + return this.isAdjacent(subnet); + } + catch { + return false; + } + } + + /** + * Creates a larger subnet by merging with an adjacent subnet of the same family and size. + * + * @param subnet Subnet to merge with. + * @throws {@link !TypeError} If the subnet is not of the same family or size. + * @throws {@link !RangeError} If the subnet is not adjacent to this subnet. + */ + public merge(subnet: Subnet): Subnet { + if (!this.isAdjacent(subnet)) + throw new RangeError(`${subnet.toString()} is not adjacent to ${this.toString()}.`); + if (this.prefix !== subnet.prefix) + throw new TypeError(`Expected /${this.prefix} subnet, but got /${subnet.prefix}.`); + + return new Subnet( + this.address.value < subnet.address.value + ? this.address + : subnet.address, + this.prefix - 1, + ); + } + + /** + * Splits this subnet into as many subnets of the specified prefix length as possible. + * + * @param prefix Prefix length of the resulting subnets. + * @throws {@link !RangeError} If the prefix is smaller than the current prefix, or over the IP address + * family bit length. + */ + public split(prefix: number): Subnet[] { + if (prefix < this.prefix || prefix > this._AddressClass.BIT_LENGTH) + throw new RangeError( + `Expected prefix in the range [${this.prefix + 1}, ${this._AddressClass.BIT_LENGTH}], got ${prefix}.`, + ); + + const length = 1 << (prefix - this.prefix); + const size = this.size() / BigInt(length); + + return Array.from({length}, (_, i) => new Subnet( + new this._AddressClass(this.address.value + BigInt(i) * size) as T, + prefix, + )); + } + + /** + * Subtracts a subnet from this subnet. + * + * @param subnet Subnet to exclude. + * @throws {@link !TypeError} If the subnet is not of the same family. + * @returns An array of subnets representing the portions of this subnet that do not overlap with the given subnet. + * Returns an empty array if the given subnet fully covers this subnet. + */ + public subtract(subnet: Subnet): Subnet[] { + if (this._AddressClass !== subnet._AddressClass) + throw new TypeError(`Expected ${this._AddressClass.name} subnet, but got ${subnet._AddressClass.name}.`); + + if (subnet.containsSubnet(this)) + return []; + + if (!this.containsSubnet(subnet)) + return [this]; + + const result: Subnet[] = []; + + if (this.address.value < subnet.address.value) + result.push(...Subnet.range(this.address, subnet.address.offset(-1) as T)); + + if (subnet.at(-1).value < this.at(-1).value) + result.push(...Subnet.range(subnet.at(-1).offset(1) as T, this.at(-1))); + + return result; + } + + /** + * Checks if the given subnets are equal. + * + * @param subnet Subnet to compare. + */ + public equals(subnet: Subnet): boolean { + return this._AddressClass === subnet._AddressClass + && this.address.equals(subnet.address) + && this.prefix === subnet.prefix; } } diff --git a/src/SubnetList.ts b/src/SubnetList.ts new file mode 100644 index 0000000..16f6a68 --- /dev/null +++ b/src/SubnetList.ts @@ -0,0 +1,208 @@ +/* + * Copyright © 2024–2025 Cloudnode OÜ + * + * This file is part of @cldn/ip. + * + * @cldn/ip is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser + * General Public License as published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * @cldn/ip is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with @cldn/ip. + * If not, see . + */ +import {IP, IPAddress, Network, Subnet} from "./index.js"; + +/** + * Represents a network comprised of subnets. + */ +export class SubnetList implements Network { + /** + * A network of reserved subnets. This network does not contain publicly routable IP addresses. + */ + public static readonly BOGON = new SubnetList([ + // IPv4 + Subnet.fromCIDR("0.0.0.0/8"), + Subnet.fromCIDR("10.0.0.0/8"), + Subnet.fromCIDR("100.64.0.0/10"), + Subnet.fromCIDR("127.0.0.0/8"), + Subnet.fromCIDR("169.254.0.0/16"), + Subnet.fromCIDR("172.16.0.0/12"), + Subnet.fromCIDR("192.0.0.0/24"), + Subnet.fromCIDR("192.0.2.0/24"), + Subnet.fromCIDR("192.88.99.0/24"), + Subnet.fromCIDR("192.168.0.0/16"), + Subnet.fromCIDR("198.18.0.0/15"), + Subnet.fromCIDR("198.51.100.0/24"), + Subnet.fromCIDR("203.0.113.0/24"), + Subnet.fromCIDR("224.0.0.0/4"), + Subnet.fromCIDR("233.252.0.0/24"), + Subnet.fromCIDR("240.0.0.0/4"), + Subnet.fromCIDR("255.255.255.255/32"), + // IPv6 + Subnet.fromCIDR("::/128"), + Subnet.fromCIDR("::1/128"), + Subnet.fromCIDR("64:ff9b:1::/48"), + Subnet.fromCIDR("100::/64"), + Subnet.fromCIDR("2001:20::/28"), + Subnet.fromCIDR("2001:db8::/32"), + Subnet.fromCIDR("3fff::/20"), + Subnet.fromCIDR("5f00::/16"), + Subnet.fromCIDR("fc00::/7"), + Subnet.fromCIDR("fe80::/10"), + ]); + + readonly #subnets: Subnet[] = []; + + /** + * Creates a new network. + * + * @param [subnets] Initial subnets to add to this network. + */ + public constructor(subnets?: Iterable>) { + if (subnets) + for (const subnet of subnets) + this.add(subnet); + } + + public* [Symbol.iterator](): Iterator { + for (const subnet of this.#subnets.values()) + for (const address of subnet) + yield address; + } + + /** + * Adds a subnet to this network. + * + * @param subnet Subnet to add. + * @returns Whether the subnet was not already fully in the network. + */ + public add(subnet: Subnet): boolean; + + /** + * Adds an IP address to this network. + * + * @param ip IP address to add. + * @returns Whether the IP address was not already in the network. + */ + public add(ip: IP): boolean; + + /** + * Adds a subnet list to this network. + * + * @param subnets Network of subnets to add. + */ + public add(subnets: SubnetList): void; + + public add(a: Subnet | IP | SubnetList): boolean | void { + if (a instanceof Subnet) { + if (this.hasSubnet(a)) return false; + + const subSubnet = this.#subnets.findIndex(s => a.containsSubnet(s)); + if (subSubnet !== -1) { + this.#subnets.splice(subSubnet, 1, a); + this.optimise(); + return true; + } + + this.#subnets.push(a); + this.optimise(); + return true; + } + else if (a instanceof IPAddress) { + const Class = a.constructor as IP.Class; + return this.add(new Subnet(a, Class.BIT_LENGTH)); + } + else { + for (const subnet of a.#subnets) + this.add(subnet); + this.optimise(); + return; + } + } + + /** + * Removes a subnet from this network. + * + * @param subnet Subnet to remove. + * @returns Whether the subnet was found and removed. + */ + public remove(subnet: Subnet) { + for (const [index, s] of this.#subnets.entries()) { + if (s.equals(subnet)) { + this.#subnets.splice(index, 1); + return true; + } + if (s.containsSubnet(subnet)) { + this.#subnets.splice(index, 1, ...s.subtract(subnet)); + return true; + } + } + return false; + } + + /** + * Checks if a subnet is in this network. + * + * @param subnet Subnet to check. + */ + public hasSubnet(subnet: Subnet): boolean { + return this.#subnets.some(s => s.containsSubnet(subnet)); + } + + /** + * Returns all subnets in this network. + */ + public subnets(): Subnet[] { + return Array.from(this.#subnets); + } + + /** + * Checks if an IP address is in this network. + * + * @param address IP address to check. + */ + public contains(address: IP): boolean { + for (const subnet of this.#subnets.values()) if (subnet.contains(address)) return true; + return false; + } + + /** + * Returns the number of addresses in this network. + */ + public size(): bigint { + let size = 0n; + for (const subnet of this.#subnets.values()) size += subnet.size(); + return size; + } + + /** + * Optimises memory by merging adjacent subnets. + */ + private optimise(): void { + this.#subnets.sort((a, b) => a._AddressClass.BIT_LENGTH - b._AddressClass.BIT_LENGTH + || b.prefix - a.prefix + || (a.address.value < b.address.value ? -1 : 1), + ); + + let merged = false; + + for (let i = 0; i + 1 < this.#subnets.length;) { + const left = this.#subnets.at(i)!; + const right = this.#subnets.at(i + 1)!; + + if (!left.canMerge(right)) { + ++i; + continue; + } + + merged = true; + this.#subnets.splice(i, 2, left.merge(right)); + } + + if (merged) this.optimise(); + } +} diff --git a/src/index.ts b/src/index.ts index 148c709..0ae5179 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,8 +14,10 @@ * You should have received a copy of the GNU Lesser General Public License along with @cldn/ip. * If not, see . */ +export {IP} from "./IP.js"; export {IPAddress} from "./IPAddress.js"; export {IPv4} from "./IPv4.js"; export {IPv6} from "./IPv6.js"; -export {Subnet} from "./Subnet.js"; export {Network} from "./Network.js"; +export {Subnet} from "./Subnet.js"; +export {SubnetList} from "./SubnetList.js"; From 36649bb1c1e6ddf2e01717d57188890ab9adf3e8 Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 19 Jul 2025 18:32:24 +0300 Subject: [PATCH 2/7] Updated the tests --- .gitignore | 2 + package-lock.json | 2461 +++++++++++++++++++++++++++++--------- package.json | 9 +- test/IPv4.test.js | 85 -- test/IPv6.test.js | 97 -- test/Network.test.js | 111 -- test/Subnet.test.js | 125 -- tests/IPAddress.test.ts | 49 + tests/IPv4.test.ts | 150 +++ tests/IPv6.test.ts | 174 +++ tests/Subnet.test.ts | 363 ++++++ tests/SubnetList.test.ts | 239 ++++ tests/tsconfig.json | 9 + vite.config.ts | 17 + 14 files changed, 2901 insertions(+), 990 deletions(-) delete mode 100644 test/IPv4.test.js delete mode 100644 test/IPv6.test.js delete mode 100644 test/Network.test.js delete mode 100644 test/Subnet.test.js create mode 100644 tests/IPAddress.test.ts create mode 100644 tests/IPv4.test.ts create mode 100644 tests/IPv6.test.ts create mode 100644 tests/Subnet.test.ts create mode 100644 tests/SubnetList.test.ts create mode 100644 tests/tsconfig.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore index d42f42d..5266fa8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules/ dist/ docs/ +coverage/ +html/ diff --git a/package-lock.json b/package-lock.json index e7d2f2e..80c909b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,528 @@ "version": "0.0.0-dev", "license": "LGPL-3.0", "devDependencies": { - "chai": "^5.1.2", - "mocha": "^11.0.1", + "@vitest/coverage-v8": "^3.2.4", + "@vitest/ui": "^3.2.4", "typedoc": "^0.28.0", "typedoc-plugin-mdn-links": "^5.0.1", - "typescript": "^5.6.3" + "typescript": "^5.6.3", + "vitest": "^3.2.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz", + "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.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.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz", + "integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz", + "integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz", + "integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz", + "integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz", + "integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz", + "integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz", + "integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz", + "integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz", + "integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz", + "integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz", + "integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz", + "integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz", + "integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz", + "integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz", + "integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz", + "integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz", + "integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz", + "integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz", + "integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz", + "integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz", + "integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz", + "integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz", + "integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz", + "integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz", + "integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz", + "integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, "node_modules/@gerrit0/mini-shiki": { @@ -34,6 +551,7 @@ "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", @@ -46,83 +564,53 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "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, + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=8" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@isaacs/cliui/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/@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==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } + "license": "MIT" }, - "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==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "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" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@pkgjs/parseargs": { @@ -130,11 +618,299 @@ "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/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz", + "integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz", + "integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz", + "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz", + "integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz", + "integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz", + "integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz", + "integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz", + "integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz", + "integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz", + "integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz", + "integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz", + "integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz", + "integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz", + "integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz", + "integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz", + "integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz", + "integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz", + "integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz", + "integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz", + "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@shikijs/engine-oniguruma": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.7.0.tgz", @@ -151,70 +927,265 @@ "integrity": "sha512-1zYtdfXLr9xDKLTGy5kb7O0zDQsxXiIsw1iIBcNOO8Yi5/Y1qDbJ+0VsFoqTlzdmneO8Ij35g7QKF8kcLyznCQ==", "dev": true, "dependencies": { - "@shikijs/types": "3.7.0" + "@shikijs/types": "3.7.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.7.0.tgz", + "integrity": "sha512-VJx8497iZPy5zLiiCTSIaOChIcKQwR0FebwE9S3rcN0+J/GTWwQ1v/bqhTbpbY3zybPKeO8wdammqkpXc4NVjQ==", + "dev": true, + "dependencies": { + "@shikijs/types": "3.7.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.7.0.tgz", + "integrity": "sha512-MGaLeaRlSWpnP0XSAum3kP3a8vtcTsITqoEPYdt3lQG3YCdQH4DnEhodkYcNMcU0uW0RffhoD1O3e0vG5eSBBg==", + "dev": true, + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "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 + }, + "node_modules/@types/chai": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*" + } + }, + "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.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "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, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true + }, + "node_modules/@vitest/coverage-v8": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz", + "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "ast-v8-to-istanbul": "^0.3.3", + "debug": "^4.4.1", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.9.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.2.4", + "vitest": "3.2.4" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@shikijs/themes": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.7.0.tgz", - "integrity": "sha512-VJx8497iZPy5zLiiCTSIaOChIcKQwR0FebwE9S3rcN0+J/GTWwQ1v/bqhTbpbY3zybPKeO8wdammqkpXc4NVjQ==", + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "3.7.0" + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@shikijs/types": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.7.0.tgz", - "integrity": "sha512-MGaLeaRlSWpnP0XSAum3kP3a8vtcTsITqoEPYdt3lQG3YCdQH4DnEhodkYcNMcU0uW0RffhoD1O3e0vG5eSBBg==", + "node_modules/@vitest/ui": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-3.2.4.tgz", + "integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" + "@vitest/utils": "3.2.4", + "fflate": "^0.8.2", + "flatted": "^3.3.3", + "pathe": "^2.0.3", + "sirv": "^3.0.1", + "tinyglobby": "^0.2.14", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "3.2.4" } }, - "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 - }, - "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==", + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "*" + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "dev": true - }, "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==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "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==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -237,6 +1208,18 @@ "node": ">=12" } }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.3.tgz", + "integrity": "sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -254,24 +1237,14 @@ "balanced-match": "^1.0.0" } }, - "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, - "license": "ISC" - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/chai": { @@ -291,36 +1264,6 @@ "node": ">=18" } }, - "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/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/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", @@ -331,37 +1274,6 @@ "node": ">= 16" } }, - "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/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -387,6 +1299,7 @@ "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", @@ -397,9 +1310,9 @@ } }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -414,19 +1327,6 @@ } } }, - "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, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/deep-eql": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", @@ -437,26 +1337,17 @@ "node": ">=6" } }, - "node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "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 + "dev": true, + "license": "MIT" }, "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==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, "license": "MIT" }, @@ -473,63 +1364,112 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz", + "integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { - "node": ">=6" + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.6", + "@esbuild/android-arm": "0.25.6", + "@esbuild/android-arm64": "0.25.6", + "@esbuild/android-x64": "0.25.6", + "@esbuild/darwin-arm64": "0.25.6", + "@esbuild/darwin-x64": "0.25.6", + "@esbuild/freebsd-arm64": "0.25.6", + "@esbuild/freebsd-x64": "0.25.6", + "@esbuild/linux-arm": "0.25.6", + "@esbuild/linux-arm64": "0.25.6", + "@esbuild/linux-ia32": "0.25.6", + "@esbuild/linux-loong64": "0.25.6", + "@esbuild/linux-mips64el": "0.25.6", + "@esbuild/linux-ppc64": "0.25.6", + "@esbuild/linux-riscv64": "0.25.6", + "@esbuild/linux-s390x": "0.25.6", + "@esbuild/linux-x64": "0.25.6", + "@esbuild/netbsd-arm64": "0.25.6", + "@esbuild/netbsd-x64": "0.25.6", + "@esbuild/openbsd-arm64": "0.25.6", + "@esbuild/openbsd-x64": "0.25.6", + "@esbuild/openharmony-arm64": "0.25.6", + "@esbuild/sunos-x64": "0.25.6", + "@esbuild/win32-arm64": "0.25.6", + "@esbuild/win32-ia32": "0.25.6", + "@esbuild/win32-x64": "0.25.6" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" } }, - "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==", + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=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==", + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" + "peerDependencies": { + "picomatch": "^3 || ^4" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } + "license": "MIT" + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" }, "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "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.0", + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -539,14 +1479,19 @@ "url": "https://github.com/sponsors/isaacs" } }, - "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==", + "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, - "license": "ISC", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/glob": { @@ -554,6 +1499,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -579,15 +1525,12 @@ "node": ">=8" } }, - "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==", + "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, - "license": "MIT", - "bin": { - "he": "bin/he" - } + "license": "MIT" }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", @@ -599,40 +1542,73 @@ "node": ">=8" } }, - "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==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, - "license": "MIT", + "license": "ISC" + }, + "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/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==", + "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, - "license": "MIT", + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10" } }, - "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-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "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" }, @@ -643,54 +1619,74 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "uc.micro": "^2.0.0" } }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "node_modules/loupe": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.4.tgz", + "integrity": "sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==", + "dev": true, + "license": "MIT" + }, + "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/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { - "uc.micro": "^2.0.0" + "@jridgewell/sourcemap-codec": "^1.5.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==", + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" } }, - "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==", + "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, "license": "MIT", "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "semver": "^7.5.3" }, "engines": { "node": ">=10" @@ -699,26 +1695,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/loupe": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", - "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", - "dev": true, - "license": "MIT" - }, - "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 - }, - "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/markdown-it": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", @@ -765,43 +1741,19 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, - "node_modules/mocha": { - "version": "11.7.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.1.tgz", - "integrity": "sha512-5EK+Cty6KheMS/YLPPMJC64g5V61gIR25KsRItHw6x4hEKT6Njp1n9LOlH4gpevuwMVS66SXaBBpg+RWZkza4A==", + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, - "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", - "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" - }, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" } }, "node_modules/ms": { @@ -811,59 +1763,38 @@ "dev": true, "license": "MIT" }, - "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, - "license": "MIT", - "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==", + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" + "bin": { + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "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 - }, - "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, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "BlueOak-1.0.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, + "license": "MIT", "engines": { "node": ">=8" } @@ -873,6 +1804,7 @@ "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" @@ -884,6 +1816,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/pathval": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", @@ -901,6 +1840,48 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/punycode.js": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", @@ -911,187 +1892,355 @@ "node": ">=6" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/rollup": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz", + "integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.45.1", + "@rollup/rollup-android-arm64": "4.45.1", + "@rollup/rollup-darwin-arm64": "4.45.1", + "@rollup/rollup-darwin-x64": "4.45.1", + "@rollup/rollup-freebsd-arm64": "4.45.1", + "@rollup/rollup-freebsd-x64": "4.45.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.45.1", + "@rollup/rollup-linux-arm-musleabihf": "4.45.1", + "@rollup/rollup-linux-arm64-gnu": "4.45.1", + "@rollup/rollup-linux-arm64-musl": "4.45.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.45.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-musl": "4.45.1", + "@rollup/rollup-linux-s390x-gnu": "4.45.1", + "@rollup/rollup-linux-x64-gnu": "4.45.1", + "@rollup/rollup-linux-x64-musl": "4.45.1", + "@rollup/rollup-win32-arm64-msvc": "4.45.1", + "@rollup/rollup-win32-ia32-msvc": "4.45.1", + "@rollup/rollup-win32-x64-msvc": "4.45.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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, "license": "MIT", "dependencies": { - "safe-buffer": "^5.1.0" + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "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==", + "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, "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "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": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "url": "https://github.com/sponsors/isaacs" } }, - "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==", + "node_modules/sirv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", "dev": true, "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "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" - } - ], "license": "MIT" }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT" + }, + "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": { - "randombytes": "^2.1.0" + "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/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==", + "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/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, + "license": "MIT", + "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-cjs/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "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": { - "shebang-regex": "^3.0.0" + "ansi-regex": "^5.0.1" }, "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==", + "node_modules/strip-ansi-cjs/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, + "license": "MIT", "engines": { "node": ">=8" } }, - "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==", + "node_modules/strip-literal": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", + "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", "dev": true, - "engines": { - "node": ">=14" + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/antfu" } }, - "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==", + "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": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "has-flag": "^4.0.0" }, "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==", + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", "dev": true, + "license": "ISC", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "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==", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "fdir": "^6.4.4", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=8" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "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==", + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^18.0.0 || >=20.0.0" } }, - "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==", + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=14.0.0" } }, - "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==", + "node_modules/tinyspy": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", + "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=14.0.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" } }, "node_modules/typedoc": { @@ -1148,11 +2297,183 @@ "dev": true, "license": "MIT" }, + "node_modules/vite": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz", + "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.6", + "picomatch": "^4.0.2", + "postcss": "^8.5.6", + "rollup": "^4.40.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, "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, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -1163,26 +2484,36 @@ "node": ">= 8" } }, - "node_modules/workerpool": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.2.tgz", - "integrity": "sha512-Xz4Nm9c+LiBHhDR5bDLnNzmj6+5F+cyEAWPMkbs2awq/dYazR/efelZzUAjB/y3kNHL+uzkHvxVVpaOfGCPV7A==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, - "license": "Apache-2.0" + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } }, "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==", + "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": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -1194,6 +2525,7 @@ "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", @@ -1206,84 +2538,77 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/wrap-ansi-cjs/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, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "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, - "bin": { - "yaml": "bin.mjs" + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 14.6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/wrap-ansi-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/wrap-ansi-cjs/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, "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" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.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": ">=8" } }, - "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==", + "node_modules/wrap-ansi-cjs/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, "license": "MIT", "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=10" + "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==", + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "bin": { + "yaml": "bin.mjs" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 14.6" } } } diff --git a/package.json b/package.json index 25926f1..7468de2 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "scripts": { "build": "tsc", "docs": "typedoc src", - "test": "mocha" + "test": "vitest run --coverage" }, "repository": { "type": "git", @@ -35,10 +35,11 @@ }, "homepage": "https://github.com/cloudnode-pro/ip#readme", "devDependencies": { - "chai": "^5.1.2", - "mocha": "^11.0.1", + "@vitest/coverage-v8": "^3.2.4", + "@vitest/ui": "^3.2.4", "typedoc": "^0.28.0", "typedoc-plugin-mdn-links": "^5.0.1", - "typescript": "^5.6.3" + "typescript": "^5.6.3", + "vitest": "^3.2.4" } } diff --git a/test/IPv4.test.js b/test/IPv4.test.js deleted file mode 100644 index 2820f4f..0000000 --- a/test/IPv4.test.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright © 2024 Cloudnode OÜ. - * - * This file is part of @cldn/ip. - * - * @cldn/ip is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser - * General Public License as published by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * @cldn/ip is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with @cldn/ip. - * If not, see - */ -import { expect } from "chai"; -import {IPv4} from "../dist/index.js"; - -describe("IPv4", () => { - - describe("Constructor", () => { - it("should create an IPv4 address from a valid number", () => { - const ip = new IPv4(2130706433); - expect(ip.toString()).to.equal("127.0.0.1"); - }); - - it("should create an IPv4 address from a valid bigint", () => { - const ip = new IPv4(2130706433n); - expect(ip.toString()).to.equal("127.0.0.1"); - }); - - it("should throw TypeError for negative number", () => { - expect(() => new IPv4(-1)).to.throw(TypeError, /Expected 32-bit unsigned integer/); - }); - - it("should throw TypeError for number larger than 32 bits", () => { - expect(() => new IPv4(4294967296)).to.throw(TypeError, /Expected 32-bit unsigned integer/); - }); - }); - - describe("Static Methods", () => { - describe("fromBinary", () => { - it("should create an IPv4 address from valid octets", () => { - const ip = IPv4.fromBinary(new Uint8Array([127, 0, 0, 1])); - expect(ip.toString()).to.equal("127.0.0.1"); - }); - - it("should throw RangeError if octets length is not 4", () => { - expect(() => IPv4.fromBinary(new Uint8Array([127, 0, 0]))).to.throw(RangeError, /Expected 4 octets/); - expect(() => IPv4.fromBinary(new Uint8Array([127, 0, 0, 1, 1]))).to.throw(RangeError, /Expected 4 octets/); - }); - }); - - describe("fromString", () => { - it("should create an IPv4 address from a valid string", () => { - const ip = IPv4.fromString("127.0.0.1"); - expect(ip.toString()).to.equal("127.0.0.1"); - }); - - it("should throw RangeError for invalid IPv4 string", () => { - expect(() => IPv4.fromString("256.0.0.1")).to.throw(RangeError, /Expected valid IPv4 address/); - expect(() => IPv4.fromString("127.0.0")).to.throw(RangeError, /Expected 4 octets/); - expect(() => IPv4.fromString("invalid.ip")).to.throw(RangeError, /Expected valid IPv4 address/); - }); - }); - }); - - describe("Instance Methods", () => { - let ip; - - beforeEach(() => { - ip = new IPv4(2130706433); - }); - - it("should return binary representation of the IPv4 address", () => { - const binary = ip.binary(); - expect(binary).to.deep.equal(new Uint8Array([127, 0, 0, 1])); - }); - - it("should return string representation of the IPv4 address", () => { - expect(ip.toString()).to.equal("127.0.0.1"); - }); - }); -}); diff --git a/test/IPv6.test.js b/test/IPv6.test.js deleted file mode 100644 index 43c5804..0000000 --- a/test/IPv6.test.js +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright © 2024 Cloudnode OÜ. - * - * This file is part of @cldn/ip. - * - * @cldn/ip is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser - * General Public License as published by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * @cldn/ip is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with @cldn/ip. - * If not, see - */ -import {expect} from "chai"; -import {IPv6} from "../dist/index.js"; - -describe("IPv6", () => { - - describe("Constructor", () => { - it("should create an IPv6 address from a valid bigint", () => { - const ip = new IPv6(0x2001_0db8_0000_0000_0000_0000_0000_0001n); - expect(ip.toString()).to.equal("2001:db8::1"); - }); - - it("should throw TypeError for negative bigint", () => { - expect(() => new IPv6(-1n)).to.throw(TypeError, /Expected 128-bit unsigned integer/); - }); - - it("should throw TypeError for bigint larger than 128 bits", () => { - const bigInt = 1n << 128n; - expect(() => new IPv6(bigInt)).to.throw(TypeError, /Expected 128-bit unsigned integer/); - }); - }); - - describe("Static Methods", () => { - describe("fromBinary", () => { - it("should create an IPv6 address from valid hextets", () => { - const ip = IPv6.fromBinary(new Uint16Array([0x3fff, 0x636c, 0x6f75, 0x646e, 0x6f64, 0x65, 0x0, 0x0])); - expect(ip.toString()).to.equal("3fff:636c:6f75:646e:6f64:65::"); - }); - - it("should throw RangeError if hextets length is not 8", () => { - expect(() => IPv6.fromBinary(new Uint16Array([0, 0, 0, 0, 0, 0, 0]))).to.throw(RangeError, /Expected 8 hextets/); - expect(() => IPv6.fromBinary(new Uint16Array([0, 0, 0, 0, 0, 0, 0, 0, 0]))).to.throw(RangeError, /Expected 8 hextets/); - }); - }); - - describe("fromString", () => { - it("should create an IPv6 address from a valid string", () => { - const ip = IPv6.fromString("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); - expect(ip.toString()).to.equal("2001:db8:85a3::8a2e:370:7334"); - }); - - it("should create an IPv6 address from a compressed format", () => { - const ip = IPv6.fromString("2001:db8::ff00:42:8329"); - expect(ip.toString()).to.equal("2001:db8::ff00:42:8329"); - }); - - it("should throw RangeError for invalid IPv6 string", () => { - expect(() => IPv6.fromString("2001:db8:85a3:0:0:8a2e:370:7334:1234")).to.throw(RangeError, /Expected valid IPv6 address/); - expect(() => IPv6.fromString("invalid::address")).to.throw(RangeError, /Expected valid IPv6 address/); - }); - }); - }); - - describe("Instance Methods", () => { - let ip; - - beforeEach(() => { - //ip = new IPv6(0x0000_0000_0000_0000_0000_ffff_c633_642an); - //ip = IPv6.fromString("::ffff:198.51.100.42"); - ip = new IPv6(281474007000106n) - }); - - it("should return binary representation of the IPv6 address", () => { - const binary = ip.binary(); - expect(binary).to.deep.equal(new Uint16Array([0x0, 0x0, 0x0, 0x0, 0x0, 0xffff, 0xc633, 0x642a])); - }); - - it("should check for IPv4-mapped IPv6 address", () => { - expect(ip.hasMappedIPv4()).to.be.true; - }); - - it("should return the mapped IPv4 address from IPv6", () => { - const mappedIp = ip.getMappedIPv4(); - expect(mappedIp.toString()).to.equal("198.51.100.42"); - }); - - it("should return string representation of the IPv6 address", () => { - expect(ip.toString()).to.equal("::ffff:c633:642a"); - }); - }); -}); - diff --git a/test/Network.test.js b/test/Network.test.js deleted file mode 100644 index bc8bc51..0000000 --- a/test/Network.test.js +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright © 2024 Cloudnode OÜ. - * - * This file is part of @cldn/ip. - * - * @cldn/ip is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser - * General Public License as published by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * @cldn/ip is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with @cldn/ip. - * If not, see - */ -import {expect} from "chai"; -import {IPv4, IPv6, Network, Subnet} from "../dist/index.js"; - -describe("Network", () => { - let network; - - beforeEach(() => { - network = new Network(); - }); - - describe("Constructor", () => { - it("should create a network without subnets", () => { - expect(network.subnets().size).to.equal(0); - }); - - it("should create a network with initial subnets", () => { - const subnet1 = Subnet.fromCIDR("203.0.113.0/24"); - const subnet2 = Subnet.fromCIDR("169.254.0.0/16"); - const newNetwork = new Network([subnet1, subnet2]); - expect(newNetwork.subnets().size).to.equal(2); - expect(newNetwork.hasSubnet("203.0.113.0/24")).to.be.true; - expect(newNetwork.hasSubnet("169.254.0.0/16")).to.be.true; - }); - }); - - describe("Add Subnet", () => { - it("should add a subnet to the network", () => { - const subnet = Subnet.fromCIDR("169.254.0.0/16"); - network.add(subnet); - expect(network.hasSubnet("169.254.0.0/16")).to.be.true; - }); - - it("should not add duplicate subnets", () => { - const subnet = Subnet.fromCIDR("169.254.0.0/16"); - network.add(subnet); - network.add(subnet); - expect(network.subnets().size).to.equal(1); - }); - }); - - describe("Remove Subnet", () => { - it("should remove a subnet from the network", () => { - const subnet = Subnet.fromCIDR("169.254.0.0/16"); - network.add(subnet); - expect(network.hasSubnet("169.254.0.0/16")).to.be.true; - network.remove("169.254.0.0/16"); - expect(network.hasSubnet("169.254.0.0/16")).to.be.false; - }); - - it("should not throw error when removing non-existing subnet", () => { - expect(() => network.remove("169.254.0.0/16")).to.not.throw(); - }); - }); - - describe("Check Subnet Presence", () => { - it("should return true if the subnet exists", () => { - const subnet = Subnet.fromCIDR("169.254.0.0/16"); - network.add(subnet); - expect(network.hasSubnet("169.254.0.0/16")).to.be.true; - }); - - it("should return false if the subnet does not exist", () => { - expect(network.hasSubnet("169.254.0.0/16")).to.be.false; - }); - }); - - describe("Check IP Address Presence", () => { - let subnet; - - beforeEach(() => { - subnet = Subnet.fromCIDR("169.254.0.0/16"); - network.add(subnet); - }); - - it("should return true if an IP address is in the network", () => { - const ipInSubnet = IPv4.fromString("169.254.68.42"); - expect(network.has(ipInSubnet)).to.be.true; - }); - - it("should return false if an IP address is not in the network", () => { - const ipOutsideSubnet = IPv4.fromString("192.0.2.42"); - expect(network.has(ipOutsideSubnet)).to.be.false; - }); - }); - - describe("Get Size of Network", () => { - it("should return the total number of addresses in the network", () => { - const subnet1 = Subnet.fromCIDR("203.0.113.0/24"); - const subnet2 = Subnet.fromCIDR("169.254.0.0/16"); - network.add(subnet1); - network.add(subnet2); - expect(network.size()).to.equal(2n ** 8n + 2n ** 16n); - }); - }); -}); diff --git a/test/Subnet.test.js b/test/Subnet.test.js deleted file mode 100644 index 1709c8e..0000000 --- a/test/Subnet.test.js +++ /dev/null @@ -1,125 +0,0 @@ -import {expect} from "chai"; -import {IPv4, IPv6, Subnet} from "../dist/index.js"; - -describe("Subnet", () => { - describe("Constructor", () => { - it("should create a subnet with a valid IPv4 address and suffix", () => { - const subnet = new Subnet(new IPv4(3925606468), 24); - expect(subnet.address.toString()).to.equal("233.252.0.0"); - expect(subnet.suffix).to.equal(24); - }); - - it("should create a subnet with a valid IPv6 address and suffix", () => { - const subnet = new Subnet(new IPv6(0xFDCA_B50F_8DF4_C52C_1337_C0FF_EB4D_C0DEn), 64); - expect(subnet.address.toString()).to.equal("fdca:b50f:8df4:c52c::"); - expect(subnet.suffix).to.equal(64); - }); - - it("should throw RangeError if suffix is greater than the IP address family bit-length", () => { - expect(() => new Subnet(new IPv4(3925606468), 33)).to.throw(RangeError, /Expected suffix less than 32/); - expect(() => new Subnet(new IPv6(0xFDCA_B50F_8DF4_C52C_1337_C0FF_EB4D_C0DEn), 129)).to.throw(RangeError, /Expected suffix less than 128/); - }); - }); - - describe("Static Methods", () => { - describe("fromCIDR", () => { - it("should create a subnet from valid CIDR notation for IPv4", () => { - const subnet = Subnet.fromCIDR("233.252.0.68/24"); - expect(subnet.address.toString()).to.equal("233.252.0.0"); - expect(subnet.suffix).to.equal(24); - }); - - it("should create a subnet from valid CIDR notation for IPv6", () => { - const subnet = Subnet.fromCIDR("fdca:b50f::1337/32"); - expect(subnet.address.toString()).to.equal("fdca:b50f::"); - expect(subnet.suffix).to.equal(32); - }); - - it("should throw RangeError for invalid CIDR notation", () => { - expect(() => Subnet.fromCIDR("invalidCIDR")).to.throw(RangeError, /Expected CIDR notation/); - expect(() => Subnet.fromCIDR("233.252.0.68")).to.throw(RangeError, /Expected CIDR notation/); - }); - }); - }); - - describe("Instance Methods", () => { - let subnet4; - let subnet6; - - beforeEach(() => { - subnet4 = new Subnet(new IPv4(3925606468), 24); - subnet6 = new Subnet(new IPv6(0xFDCA_B50F_8DF4_C52C_1337_C0FF_EB4D_C0DEn), 64); - }); - - it("should calculate netmask for IPv4 subnet", () => { - expect(subnet4.netmask()).to.equal(0xFFFFFF00n); - }); - - it("should calculate wildcard for IPv4 subnet", () => { - expect(subnet4.wildcard()).to.equal(255n); - }); - - it("should calculate broadcast address for IPv4 subnet", () => { - expect(subnet4.broadcast().toString()).to.equal("233.252.0.255"); - }); - - it("should check if an IP address is in the subnet for IPv4", () => { - const addressInSubnet = new IPv4(3925606468); - const addressOutOfSubnet = new IPv4(3405803844); - expect(subnet4.has(addressInSubnet)).to.be.true; - expect(subnet4.has(addressOutOfSubnet)).to.be.false; - }); - - it("should calculate size of the IPv4 subnet", () => { - expect(subnet4.size()).to.equal(256n); - }); - - it("should iterate over all IP addresses in the IPv4 subnet", () => { - const addresses = Array.from(subnet4.iterate()).map(ip => ip.toString()); - expect(addresses).to.deep.equal(Array.from({length: 256}, (_, i) => `233.252.0.${i}`)); - }); - - it("should calculate netmask for IPv6 subnet", () => { - expect(subnet6.netmask()).to.equal(0xFFFFFFFFFFFFFFFF0000000000000000n); - }); - - it("should calculate wildcard for IPv6 subnet", () => { - expect(subnet6.wildcard()).to.equal(0xFFFFFFFFFFFFFFFFn); - }); - - it("should calculate broadcast address for IPv6 subnet", () => { - expect(subnet6.broadcast().toString()).to.equal("fdca:b50f:8df4:c52c:ffff:ffff:ffff:ffff"); - }); - - it("should check if an IP address is in the subnet for IPv6", () => { - const addressInSubnet = IPv6.fromString("fdca:b50f:8df4:c52c:1337:c0ff:eb4d:c0de"); - const addressOutOfSubnet = IPv6.fromString("fdca:b510::1"); - expect(subnet6.has(addressInSubnet)).to.be.true; - expect(subnet6.has(addressOutOfSubnet)).to.be.false; - }); - - it("should calculate size of the IPv6 subnet", () => { - expect(subnet6.size()).to.equal(2n ** 64n); - }); - }); - - describe("Iteration", () => { - it("should implement iterable interface", () => { - const subnet = new Subnet(new IPv4(3925606468), 30); - const addresses = [...subnet]; - expect(addresses.map(ip => ip.toString())).to.deep.equal(["233.252.0.68", "233.252.0.69", "233.252.0.70", "233.252.0.71"]); - }); - }); - - describe("String Representation", () => { - it("should return CIDR representation for IPv4", () => { - const subnet = new Subnet(new IPv4(3925606468), 24); - expect(subnet.toString()).to.equal("233.252.0.0/24"); - }); - - it("should return CIDR representation for IPv6", () => { - const subnet = new Subnet(new IPv6(0xFDCA_B50F_8DF4_C52C_1337_C0FF_EB4D_C0DEn), 64); - expect(subnet.toString()).to.equal("fdca:b50f:8df4:c52c::/64"); - }); - }); -}); diff --git a/tests/IPAddress.test.ts b/tests/IPAddress.test.ts new file mode 100644 index 0000000..5fb55b0 --- /dev/null +++ b/tests/IPAddress.test.ts @@ -0,0 +1,49 @@ +import {describe, expect, it} from "vitest"; +import {IPAddress, IPv4, IPv6} from "../src/index.js"; + +describe("IPAddress", () => { + describe("static fromString", () => { + it("creates IPv4 from IPv4 string", () => { + const ip = IPAddress.fromString("192.0.2.0"); + expect(ip).toBeInstanceOf(IPv4); + expect(ip.toString()).toBe("192.0.2.0"); + }); + + it("creates IPv6 from IPv6 string", () => { + const ip = IPAddress.fromString("2001:db8::"); + expect(ip).toBeInstanceOf(IPv6); + expect(ip.toString()).toBe("2001:db8::"); + }); + + it("creates IPv4 from IPv4 string with resolveMapped=false", () => { + const ip = IPAddress.fromString("192.0.2.0"); + expect(ip).toBeInstanceOf(IPv4); + expect(ip.toString()).toBe("192.0.2.0"); + }); + + it("creates IPv6 from IPv6 string with resolveMapped=true", () => { + const ip = IPAddress.fromString("2001:db8::", true); + expect(ip).toBeInstanceOf(IPv6); + expect(ip.toString()).toBe("2001:db8::"); + }); + + it("creates IPv4 from IPv4-mapped IPv6 string with resolveMapped=true", () => { + const ip = IPAddress.fromString("::ffff:192.0.2.0", true); + expect(ip).toBeInstanceOf(IPv4); + expect(ip.toString()).toBe("192.0.2.0"); + }); + + it("creates IPv6 from IPv4-mapped IPv6 string with resolveMapped=false", () => { + const ip = IPAddress.fromString("::ffff:192.0.2.0"); + expect(ip).toBeInstanceOf(IPv6); + expect(ip.toString()).toBe("::ffff:c000:200"); + }); + + it("throws RangeError for invalid string", () => { + expect(() => IPAddress.fromString("not an ip")).toThrow(RangeError); + expect(() => IPAddress.fromString("invalid:ip")).toThrow(RangeError); + expect(() => IPAddress.fromString("not.an.ip")).toThrow(RangeError); + expect(() => IPAddress.fromString("")).toThrow(RangeError); + }); + }); +}); diff --git a/tests/IPv4.test.ts b/tests/IPv4.test.ts new file mode 100644 index 0000000..9794135 --- /dev/null +++ b/tests/IPv4.test.ts @@ -0,0 +1,150 @@ +import {describe, expect, it} from "vitest"; +import {IPv4, IPv6} from "../src/index.js"; + +describe("IPv4", () => { + describe("static BIT_LENGTH", () => { + it("is 32", () => { + expect(IPv4.BIT_LENGTH).toBe(32); + }); + }); + + describe("constructor", () => { + it("constructs from a valid number", () => { + const ip = new IPv4(0xC0000200); + expect(ip.value).toBe(0xC0000200n); + expect(ip.toString()).toBe("192.0.2.0"); + }); + + it("constructs from a valid bigint", () => { + const ip = new IPv4(0xC6336410n); + expect(ip.value).toBe(0xC6336410n); + expect(ip.toString()).toBe("198.51.100.16"); + }); + + it("constructs from 0", () => { + const ip = new IPv4(0); + expect(ip.value).toBe(0n); + expect(ip.toString()).toBe("0.0.0.0"); + }); + + it("constructs from 2^32 - 1", () => { + const ip = new IPv4(2 ** 32 - 1); + expect(ip.value).toBe(2n ** 32n - 1n); + expect(ip.toString()).toBe("255.255.255.255"); + }); + + it("throws TypeError for value < 0", () => { + expect(() => new IPv4(-1)).toThrow(TypeError); + expect(() => new IPv4(-1n)).toThrow(TypeError); + }); + + it("throws TypeError for value > 2^32 - 1", () => { + expect(() => new IPv4(2 ** 32)).toThrow(TypeError); + expect(() => new IPv4(2n ** 32n)).toThrow(TypeError); + }); + }); + + describe("static fromBinary", () => { + it("creates IPv4 from 4-octet array", () => { + const ip = IPv4.fromBinary(new Uint8Array([192, 0, 2, 0])); + expect(ip.toString()).toBe("192.0.2.0"); + }); + + it("throws RangeError if array has less than 4 octets", () => { + expect(() => IPv4.fromBinary(new Uint8Array([192, 0, 2]))).toThrow(RangeError); + }); + + it("throws RangeError if array has more than 4 octets", () => { + expect(() => IPv4.fromBinary(new Uint8Array([192, 0, 2, 1, 0]))).toThrow(RangeError); + }); + }); + + describe("static fromString", () => { + it("creates IPv4 from valid string", () => { + const ip = IPv4.fromString("203.0.113.5"); + expect(ip.value).toBe(0xCB007105n); + }); + + it("throws RangeError for invalid IP string", () => { + expect(() => IPv4.fromString("256.0.0.0")).toThrow(RangeError); + expect(() => IPv4.fromString("10")).toThrow(RangeError); + expect(() => IPv4.fromString("invalid.ip.string")).toThrow(RangeError); + }); + }); + + describe("binary", () => { + it("returns correct 4-octet array", () => { + const ip = IPv4.fromString("192.0.2.5"); + expect(Array.from(ip.binary())).toEqual([192, 0, 2, 5]); + }); + }); + + describe("[Symbol.toPrimitive]", () => { + it("returns dotted-decimal string when hint is string", () => { + const ip = IPv4.fromString("192.0.2.0"); + expect(`${ip}`).toBe("192.0.2.0"); + }); + + it("returns number when hint is not string", () => { + const ip = IPv4.fromString("192.0.2.0"); + expect(1n + (ip as unknown as bigint)).toBe(0xC0000201n); + expect(BigInt(ip as unknown as bigint)).toBe(0xC0000200n); + }); + }); + + describe("toString", () => { + it("returns dotted-decimal string", () => { + const ip = IPv4.fromString("203.0.113.42"); + expect(ip.toString()).toBe("203.0.113.42"); + }); + }); + + describe("equals", () => { + it("returns true for two IPv4 instances with the same address", () => { + const a = IPv4.fromString("198.51.100.10"); + const b = IPv4.fromString("198.51.100.10"); + expect(a.equals(b)).toBe(true); + }); + + it("returns false for two IPv4 instances with different addresses", () => { + const a = IPv4.fromString("198.51.100.10"); + const b = IPv4.fromString("198.51.100.11"); + expect(a.equals(b)).toBe(false); + }); + + it("returns false when compared with a different IPAddress subclass", () => { + const a = IPv4.fromString("198.51.100.10"); + const b = IPv6.fromString("::c633:640a"); + + expect(a.equals(b)).toBe(false); + }); + }); + + describe("offset", () => { + it("offsets positively", () => { + const ip = IPv4.fromString("192.0.2.1"); + expect(ip.offset(1).toString()).toBe("192.0.2.2"); + expect(ip.offset(1n).toString()).toBe("192.0.2.2"); + expect(ip.offset(104030719).toString()).toBe("198.51.100.0"); + expect(ip.offset(104030719n).toString()).toBe("198.51.100.0"); + }); + + it("offsets negatively", () => { + const ip = IPv4.fromString("203.0.113.1"); + expect(ip.offset(-1).toString()).toBe("203.0.113.0"); + expect(ip.offset(-1n).toString()).toBe("203.0.113.0"); + expect(ip.offset(-80547073).toString()).toBe("198.51.100.0"); + expect(ip.offset(-80547073n).toString()).toBe("198.51.100.0"); + }); + + it("throws TypeError if offset IP < 0", () => { + const ip = IPv4.fromString("192.0.2.0"); + expect(() => ip.offset(-3221225985)).toThrow(TypeError); + }); + + it("throws TypeError if offset IP > 2^32 - 1", () => { + const ip = IPv4.fromString("203.0.113.0"); + expect(() => ip.offset(889163520)).toThrow(TypeError); + }); + }); +}); diff --git a/tests/IPv6.test.ts b/tests/IPv6.test.ts new file mode 100644 index 0000000..29c8a3f --- /dev/null +++ b/tests/IPv6.test.ts @@ -0,0 +1,174 @@ +import {describe, expect, it} from "vitest"; +import {IPv4, IPv6} from "../src/index.js"; + +describe("IPv6", () => { + describe("static BIT_LENGTH", () => { + it("is 128", () => { + expect(IPv6.BIT_LENGTH).toBe(128); + }); + }); + + describe("constructor", () => { + it("constructs from a valid 128-bit bigint", () => { + const ip = new IPv6(0x20010db8000000000000000000000001n); + expect(ip.value).toBe(0x20010db8000000000000000000000001n); + expect(ip.toString()).toBe("2001:db8::1"); + }); + + it("throws TypeError if value is negative", () => { + expect(() => new IPv6(-1n)).toThrow(TypeError); + }); + + it("throws TypeError if value > 2^128 - 1", () => { + expect(() => new IPv6(2n ** 128n)).toThrow(TypeError); + }); + }); + + describe("static fromBinary", () => { + it("creates IPv6 from 8 hextets", () => { + const ip = IPv6.fromBinary(new Uint16Array([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x1])); + expect(ip.toString()).toBe("2001:db8::1"); + }); + + it("throws RangeError if array has less than 8 hextets", () => { + expect(() => IPv6.fromBinary(new Uint16Array([0x2001, 0xdb8, 0, 0, 0, 0, 0x1]))).toThrow(RangeError); + }); + + it("throws RangeError if array has more than 8 hextets", () => { + expect(() => IPv6.fromBinary(new Uint16Array([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0, 0x1]))) + .toThrow(RangeError); + }); + }); + + describe("static fromString", () => { + it("creates IPv6 from valid compressed string", () => { + const ip = IPv6.fromString("2001:db8::5"); + expect(ip.toString()).toBe("2001:db8::5"); + }); + + it("creates IPv6 from valid full string", () => { + const ip = IPv6.fromString("2001:0db8:0000:0000:0000:0000:0000:0001"); + expect(ip.toString()).toBe("2001:db8::1"); + }); + + it("throws RangeError for invalid IPv6 string", () => { + expect(() => IPv6.fromString("invalid::ip")).toThrow(RangeError); + expect(() => IPv6.fromString("12345::")).toThrow(RangeError); + expect(() => IPv6.fromString("2001:0db8:0000:0000:0000:0000:0000:ffff2")).toThrow(RangeError); + expect(() => IPv6.fromString("2001:0db8:0000:0000:0000:0000:0001")).toThrow(RangeError); + }); + }); + + describe("binary", () => { + it("returns correct 8-hextet array", () => { + expect(Array.from(IPv6.fromString("2001:db8::").binary())).toEqual([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0]); + expect(Array.from(IPv6.fromString("2001:db8:dead:beef::1337:cafe").binary())) + .toEqual([0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0x1337, 0xcafe]); + }); + }); + + describe("hasMappedIPv4", () => { + it("returns true for ::ffff:192.0.2.0", () => { + const ip = IPv6.fromString("::ffff:192.0.2.0"); + expect(ip.hasMappedIPv4()).toBe(true); + }); + + it("returns true for ::ffff:c633:642a", () => { + const ip = IPv6.fromString("::ffff:c633:642a"); + expect(ip.hasMappedIPv4()).toBe(true); + }); + + it("returns false for non-mapped IPv6 address", () => { + const ip = IPv6.fromString("2001:db8::1"); + expect(ip.hasMappedIPv4()).toBe(false); + }); + }); + + describe("getMappedIPv4", () => { + it("returns the mapped IPv4 address from ::ffff:192.0.2.0", () => { + const ip = IPv6.fromString("::ffff:192.0.2.0"); + const mapped = ip.getMappedIPv4(); + expect(mapped.toString()).toBe("192.0.2.0"); + }); + it("returns the mapped IPv4 address from ::ffff:c633:642a", () => { + const ip = IPv6.fromString("::ffff:c633:642a"); + const mapped = ip.getMappedIPv4(); + expect(mapped.toString()).toBe("198.51.100.42"); + }); + }); + + describe("toString", () => { + it("returns canonical string form", () => { + const ip = IPv6.fromString("2001:0db8:0000:0000:0000:0000:0000:0001"); + expect(ip.toString()).toBe("2001:db8::1"); + }); + + it("returns full uncompressed IPv6 string when no zeros to compress", () => { + const ip = IPv6.fromString("2001:0db8:1234:5678:9abc:def:0123:4567"); + expect(ip.toString()).toBe("2001:db8:1234:5678:9abc:def:123:4567"); + }); + + it("collapses the first longest zero group", () => { + const hextets = new Uint16Array([0x2001, 0xdb8, 0, 0, 0x1, 0, 0, 0x1]); + const ip = IPv6.fromBinary(hextets); + expect(ip.toString()).toBe("2001:db8::1:0:0:1"); + }); + + it("does not compress a single zero hextet", () => { + const hextets = new Uint16Array([0x2001, 0xdb8, 0, 0x1, 0, 0x1234, 0xabcd, 0x5678]); + const ip = IPv6.fromBinary(hextets); + expect(ip.toString()).toBe("2001:db8:0:1:0:1234:abcd:5678"); + }); + + it("returns :: for the unspecified address", () => { + const ip = new IPv6(0n); + expect(ip.toString()).toBe("::"); + }); + }); + + describe("equals", () => { + it("returns true for two equal IPv6 addresses", () => { + const a = IPv6.fromString("2001:db8::5"); + const b = IPv6.fromString("2001:db8::5"); + expect(a.equals(b)).toBe(true); + }); + + it("returns false for different IPv6 addresses", () => { + const a = IPv6.fromString("2001:db8::1"); + const b = IPv6.fromString("2001:db8::2"); + expect(a.equals(b)).toBe(false); + }); + + it("returns false when compared with different IPAddress subclass", () => { + const a = IPv6.fromString("::cb00:71ff"); + const b = IPv4.fromString("203.0.113.255"); + expect(a.equals(b)).toBe(false); + }); + }); + + describe("offset", () => { + it("offsets positively", () => { + expect(IPv6.fromString("2001:db8::").offset(1).toString()).toBe("2001:db8::1"); + expect(IPv6.fromString("2001:db8::").offset(5634002667680789686395290983n).toString()) + .toBe("2001:db8:1234:5678:9abc:def:123:4567"); + }); + + it("offsets negatively", () => { + expect(IPv6.fromString("2001:db8::1").offset(-1).toString()).toBe("2001:db8::"); + expect(IPv6.fromString("2001:db8::cafe:babe").offset(-270593984n).toString()) + .toBe("2001:db8::badd:cafe"); + }); + + it("throws TypeError if offset IP < 0", () => { + expect(() => IPv6.fromString("::").offset(-1)).toThrow(TypeError); + expect(() => IPv6.fromString("2001:db8::cafe:babe") + .offset(-42540766411282592856903984955059518143n)).toThrow(TypeError); + }); + + it("throws TypeError if offset IP > 2^128 - 1", () => { + expect(() => new IPv6(2n ** 128n - 1n).offset(1)).toThrow(TypeError); + expect(() => IPv6.fromString("2001:db8::dead:beef") + .offset(297741600509655870606470622476378456337n)).toThrow(TypeError); + }); + }); +}); diff --git a/tests/Subnet.test.ts b/tests/Subnet.test.ts new file mode 100644 index 0000000..abeb00b --- /dev/null +++ b/tests/Subnet.test.ts @@ -0,0 +1,363 @@ +import {describe, expect, it} from "vitest"; +import {IPv4, IPv6, Subnet} from "../src/index.js"; + +describe("Subnet", () => { + describe("constructor", () => { + it("creates a subnet with valid IPv4 address and prefix", () => { + const addr = IPv4.fromString("192.0.2.0"); + const subnet = new Subnet(addr, 24); + expect(subnet.address.equals(addr)).toBe(true); + expect(subnet.prefix).toBe(24); + }); + + it("creates a subnet with misaligned address", () => { + const addr = IPv4.fromString("192.0.2.42"); + const subnet = new Subnet(addr, 24); + expect(subnet.address.equals(IPv4.fromString("192.0.2.0"))).toBe(true); + }); + + it("throws RangeError if prefix length exceeds IP bit length", () => { + expect(() => new Subnet(IPv4.fromString("192.0.2.0"), 33)).toThrow(RangeError); + expect(() => new Subnet(IPv6.fromString("2001:db8::"), 129)).toThrow(RangeError); + }); + + it("throws RangeError if prefix length is negative", () => { + expect(() => new Subnet(IPv4.fromString("192.0.2.0"), -1)).toThrow(RangeError); + }); + }); + + describe("static fromCIDR", () => { + it("creates subnet from valid IPv4 CIDR string", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/24"); + expect(subnet.address.toString()).toBe("192.0.2.0"); + expect(subnet.prefix).toBe(24); + }); + + it("throws RangeError on invalid CIDR string", () => { + expect(() => Subnet.fromCIDR("192.0.2.0/33")).toThrow(RangeError); + expect(() => Subnet.fromCIDR("192.0.2.0")).toThrow(RangeError); + expect(() => Subnet.fromCIDR("192.0.2.0/no")).toThrow(RangeError); + expect(() => Subnet.fromCIDR("10/8")).toThrow(RangeError); + expect(() => Subnet.fromCIDR("10.0/16")).toThrow(RangeError); + expect(() => Subnet.fromCIDR("invalid/cidr")).toThrow(RangeError); + }); + }); + + describe("static range", () => { + it("creates subnet from /24 IPv4 range", () => { + const subnets = Subnet.range( + IPv4.fromString("192.0.2.0"), + IPv4.fromString("192.0.2.255") + ); + expect(subnets.map(s => s.toString())).toEqual(["192.0.2.0/24"]); + }); + + it("creates subnet from misaligned IPv4 range", () => { + const subnets = Subnet.range( + IPv4.fromString("192.0.2.0"), + IPv4.fromString("198.51.100.255") + ); + + // from https://account.arin.net/public/cidrCalculator + expect(subnets.map(s => s.toString())).toEqual([ + "192.0.2.0/23", + "192.0.4.0/22", + "192.0.8.0/21", + "192.0.16.0/20", + "192.0.32.0/19", + "192.0.64.0/18", + "192.0.128.0/17", + "192.1.0.0/16", + "192.2.0.0/15", + "192.4.0.0/14", + "192.8.0.0/13", + "192.16.0.0/12", + "192.32.0.0/11", + "192.64.0.0/10", + "192.128.0.0/9", + "193.0.0.0/8", + "194.0.0.0/7", + "196.0.0.0/7", + "198.0.0.0/11", + "198.32.0.0/12", + "198.48.0.0/15", + "198.50.0.0/16", + "198.51.0.0/18", + "198.51.64.0/19", + "198.51.96.0/22", + "198.51.100.0/24", + ]); + }); + }); + + describe("netmask", () => { + it("returns correct netmask for IPv4 /24", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/24"); + expect(subnet.netmask()).toBe(0xffffff00n); + }); + }); + + describe("wildcard", () => { + it("returns correct wildcard for IPv4 /24", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/24"); + expect(subnet.wildcard()).toBe(0xffn); + }); + }); + + describe("size", () => { + it("returns correct size for IPv4 /24 subnet", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/24"); + expect(subnet.size()).toBe(256n); + }); + + it("returns correct size for IPv6 /32 subnet", () => { + const subnet = Subnet.fromCIDR("2001:db8::/32"); + expect(subnet.size()).toBe(2n ** 96n); + }); + }); + + describe("contains", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/24"); + + it("contains address inside subnet", () => { + const addr = IPv4.fromString("192.0.2.42"); + expect(subnet.contains(addr)).toBe(true); + }); + + it("does not contain address outside subnet", () => { + const addr = IPv4.fromString("198.51.100.10"); + expect(subnet.contains(addr)).toBe(false); + }); + }); + + describe("containsSubnet", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/24"); + + it("contains smaller subnet inside", () => { + const smaller = Subnet.fromCIDR("192.0.2.128/25"); + expect(subnet.containsSubnet(smaller)).toBe(true); + }); + + it("does not contain larger subnet", () => { + const larger = Subnet.fromCIDR("192.0.2.0/23"); + expect(subnet.containsSubnet(larger)).toBe(false); + }); + + it("does not contain adjacent subnet", () => { + const adjacent = Subnet.fromCIDR("192.0.3.0/25"); + expect(subnet.containsSubnet(adjacent)).toBe(false); + }); + }); + + describe("at", () => { + const subnet = Subnet.fromCIDR("192.0.2.4/30"); + + it("returns first address at index 0", () => { + expect(subnet.at(0).toString()).toBe("192.0.2.4"); + }); + + it("returns second address at index 1", () => { + expect(subnet.at(1)?.toString()).toBe("192.0.2.5"); + }); + + it("returns last address at index -1", () => { + expect(subnet.at(-1).toString()).toBe("192.0.2.7"); + }); + + it("returns penultimate address at index -2", () => { + expect(subnet.at(-2)?.toString()).toBe("192.0.2.6"); + }); + + it("returns undefined for out-of-range positive index", () => { + expect(subnet.at(4)).toBeUndefined(); + }); + + it("returns undefined for out-of-range negative index", () => { + expect(subnet.at(-5)).toBeUndefined(); + }); + }); + + describe("addresses", () => { + const subnet = Subnet.fromCIDR("192.0.2.8/30"); + + it("iterates over all addresses", () => { + const ips = Array.from(subnet.addresses()).map(ip => ip.toString()); + expect(ips).toEqual(["192.0.2.8", "192.0.2.9", "192.0.2.10", "192.0.2.11"]); + }); + }); + + describe("[Symbol.iterator]", () => { + const subnet = Subnet.fromCIDR("198.51.100.40/30"); + it("iterator works with for...of", () => { + const ips: string[] = []; + for (const ip of subnet) + ips.push(ip.toString()); + expect(ips).toEqual(["198.51.100.40", "198.51.100.41", "198.51.100.42", "198.51.100.43"]); + }); + }) + + describe("set", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/30"); + + it("creates a set of all addresses", () => { + const set = subnet.set(); + expect(set.size).toBe(4); + const arr = Array.from(set).map(ip => ip.toString()); + expect(arr).toEqual(["192.0.2.0", "192.0.2.1", "192.0.2.2", "192.0.2.3"]); + }); + }); + + describe("toString", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/24"); + + it("returns CIDR notation string", () => { + expect(subnet.toString()).toBe("192.0.2.0/24"); + }); + }); + + describe("isAdjacent", () => { + const subnet1 = Subnet.fromCIDR("192.0.2.0/25"); + const subnet2 = Subnet.fromCIDR("192.0.2.128/25"); + const subnet3 = Subnet.fromCIDR("198.51.100.0/25"); + + it("returns true for adjacent subnets", () => { + expect(subnet1.isAdjacent(subnet2)).toBe(true); + }); + + it("returns false for non-adjacent subnets", () => { + expect(subnet1.isAdjacent(subnet3)).toBe(false); + }); + + it("throws TypeError for different families", () => { + const ipv6Subnet = Subnet.fromCIDR("2001:db8::/64"); + expect(() => subnet1.isAdjacent(ipv6Subnet)).toThrow(TypeError); + }); + }); + + describe("canMerge", () => { + const subnet1 = Subnet.fromCIDR("192.0.2.0/25"); + const subnet2 = Subnet.fromCIDR("192.0.2.128/25"); + const subnet3 = Subnet.fromCIDR("192.0.2.0/26"); + + it("returns true for adjacent subnets of same size", () => { + expect(subnet1.canMerge(subnet2)).toBe(true); + }); + + it("returns false for subnets with different prefix length", () => { + expect(subnet1.canMerge(subnet3)).toBe(false); + }); + + it("returns false for different families", () => { + const ipv6Subnet = Subnet.fromCIDR("2001:db8::/25"); + expect(subnet1.canMerge(ipv6Subnet)).toBe(false); + }); + }); + + describe("merge", () => { + const subnet1 = Subnet.fromCIDR("192.0.2.0/25"); + const subnet2 = Subnet.fromCIDR("192.0.2.128/25"); + + it("merges adjacent subnets of same size", () => { + const merged = subnet1.merge(subnet2); + expect(merged.prefix).toBe(24); + expect(merged.address.toString()).toBe("192.0.2.0"); + }); + + it("merges when this is the upper neighbour", () => { + const merged = subnet2.merge(subnet1); + expect(merged.prefix).toBe(24); + expect(merged.address.toString()).toBe("192.0.2.0"); + }); + + it("throws TypeError for different families", () => { + const ipv6Subnet = Subnet.fromCIDR("2001:db8::/25"); + expect(() => subnet1.merge(ipv6Subnet)).toThrow(TypeError); + }); + + it("throws TypeError for different sizes", () => { + const subnet3 = Subnet.fromCIDR("192.0.2.128/26"); + expect(() => subnet1.merge(subnet3)).toThrow(TypeError); + }); + + it("throws RangeError for non-adjacent subnets", () => { + const subnet3 = Subnet.fromCIDR("198.51.100.0/25"); + expect(() => subnet1.merge(subnet3)).toThrow(RangeError); + }); + }); + + describe("split", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/24"); + + it("splits subnet into smaller subnets", () => { + const splits = subnet.split(26).map(s => s.toString()); + expect(splits).toEqual([ + "192.0.2.0/26", + "192.0.2.64/26", + "192.0.2.128/26", + "192.0.2.192/26", + ]); + }); + + it("throws RangeError if prefix length is smaller than current", () => { + expect(() => subnet.split(16)).toThrow(RangeError); + }); + + it("throws RangeError if prefix length exceeds IP bit length", () => { + expect(() => subnet.split(33)).toThrow(RangeError); + }); + }); + + describe("subtract", () => { + const subnet = Subnet.fromCIDR("192.0.2.0/24"); + + it("subtracts a subnet fully contained", () => { + const toSubtract = Subnet.fromCIDR("192.0.2.0/26"); + const result = subnet.subtract(toSubtract).map(s => s.toString()); + expect(result).toEqual([ + "192.0.2.64/26", + "192.0.2.128/25", + ]); + }); + + it("subtracts subnet not aligned with base address", () => { + const toSubtract = Subnet.fromCIDR("192.0.2.128/26"); + const result = subnet.subtract(toSubtract).map(s => s.toString()); + expect(result).toEqual([ + "192.0.2.0/25", + "192.0.2.192/26", + ]); + }); + + it("returns self when subtracting non-overlapping subnet", () => { + const toSubtract = Subnet.fromCIDR("198.51.100.0/25"); + const result = subnet.subtract(toSubtract); + expect(result).toEqual([subnet]); + }); + + it("returns empty array when fully covered", () => { + expect(subnet.subtract(Subnet.fromCIDR("192.0.2.0/24"))).toHaveLength(0); + expect(subnet.subtract(Subnet.fromCIDR("0.0.0.0/0"))).toHaveLength(0); + }); + + it("throws TypeError for different family", () => { + const ipv6Subnet = Subnet.fromCIDR("2001:db8::/64"); + expect(() => subnet.subtract(ipv6Subnet)).toThrow(TypeError); + }); + }); + + describe("equals", () => { + it("returns true for identical subnets", () => { + expect(Subnet.fromCIDR("192.0.2.0/24").equals(Subnet.fromCIDR("192.0.2.0/24"))) + .toBe(true); + expect(Subnet.fromCIDR("2001:db8::/64").equals(Subnet.fromCIDR("2001:db8::/64"))) + .toBe(true); + }); + + it("returns false for different subnets", () => { + expect(Subnet.fromCIDR("192.0.2.0/24").equals(Subnet.fromCIDR("192.0.2.0/25"))) + .toBe(false); + expect(Subnet.fromCIDR("192.0.2.0/24").equals(Subnet.fromCIDR("2001:db8::/64"))) + .toBe(false); + }); + }); +}); diff --git a/tests/SubnetList.test.ts b/tests/SubnetList.test.ts new file mode 100644 index 0000000..fa08f66 --- /dev/null +++ b/tests/SubnetList.test.ts @@ -0,0 +1,239 @@ +import {describe, expect, it} from "vitest"; +import {IPv4, IPv6, Subnet, SubnetList} from "../src/index.js"; + +describe("SubnetList", () => { + describe("constructor", () => { + it("creates empty SubnetList", () => { + const list = new SubnetList(); + expect(list.size()).toBe(0n); + expect(list.subnets()).toHaveLength(0); + }); + + it("initialises with provided subnets", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const s2 = Subnet.fromCIDR("192.0.2.128/25"); + const s3 = Subnet.fromCIDR("198.51.100.0/24"); + const list = new SubnetList([s2, s1, s3]); + expect(list.hasSubnet(s1)).toBe(true); + expect(list.hasSubnet(s2)).toBe(true); + expect(list.hasSubnet(s3)).toBe(true); + expect(list.size()).toBeLessThanOrEqual(s1.size() + s2.size() + s3.size()); + }); + + it("optimises subnets to minimise memory usage", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const s2 = Subnet.fromCIDR("192.0.2.128/25"); + const s3 = Subnet.fromCIDR("198.51.100.0/24"); + const list = new SubnetList([s1, s2, s3]); + expect(list.subnets().map(s => s.toString())).toEqual([ + "192.0.2.0/24", + "198.51.100.0/24", + ]); + }) + }); + + describe("add", () => { + it("adds a subnet and returns true if new", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const s2 = Subnet.fromCIDR("192.0.2.128/25"); + const s3 = Subnet.fromCIDR("198.51.100.0/24"); + const list = new SubnetList([s1, s2]); + const initialSize = list.size(); + expect(list.add(s3)).toBe(true); + expect(list.hasSubnet(s3)).toBe(true); + expect(list.size()).toBe(initialSize + s3.size()); + }); + + it("adds a subnet that expands an existing one and returns true", () => { + const s1 = Subnet.fromCIDR("192.0.2.128/25"); + const s2 = Subnet.fromCIDR("192.0.2.0/24"); + const list = new SubnetList([s1]); + expect(list.add(s2)).toBe(true); + expect(list.hasSubnet(s2)).toBe(true); + expect(list.size()).toBe(s2.size()); + }); + + it("returns false when adding a duplicate subnet", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const list = new SubnetList([s1]); + expect(list.add(s1)).toBe(false); + }); + + it("returns false when adding a subnet that is already contained", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/24"); + const s2 = Subnet.fromCIDR("192.0.2.128/25"); + const list = new SubnetList([s1]); + expect(list.add(s2)).toBe(false); + }); + + it("adds an IP address as a /32 subnet", () => { + const ip = IPv4.fromString("192.0.2.5"); + const list = new SubnetList(); + expect(list.add(ip)).toBe(true); + expect(list.subnets().map(s => s.toString())).toEqual(["192.0.2.5/32"]); + expect(list.contains(ip)).toBe(true); + }); + + it("returns false when adding duplicate IP address", () => { + const ip = IPv4.fromString("192.0.2.5"); + const list = new SubnetList([Subnet.fromCIDR("192.0.2.5/32")]); + expect(list.add(ip)).toBe(false); + }); + + it("adds all subnets from another SubnetList", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/24"); + const s2 = Subnet.fromCIDR("198.51.100.0/24"); + const other = new SubnetList([s1, s2]); + const list = new SubnetList(); + list.add(other); + expect(list.hasSubnet(s1)).toBe(true); + expect(list.hasSubnet(s2)).toBe(true); + expect(list.size()).toBeLessThanOrEqual(s1.size() + s2.size()); + }); + }); + + describe("remove", () => { + it("removes existing subnet and returns true", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const list = new SubnetList([s1]); + expect(list.remove(s1)).toBe(true); + expect(list.hasSubnet(s1)).toBe(false); + expect(list.size()).toBe(0n); + }); + + it("removes subnet partially covered by a larger one", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const s2 = Subnet.fromCIDR("192.0.2.128/25"); + const s3 = Subnet.fromCIDR("192.0.2.0/24"); + const list = new SubnetList([s3]); + expect(list.remove(s2)).toBe(true); + expect(list.hasSubnet(s1)).toBe(true); + expect(list.hasSubnet(s2)).toBe(false); + expect(list.size()).toBe(s1.size()); + }); + + it("returns false when removing subnet not present", () => { + const s1 = Subnet.fromCIDR("203.0.113.0/24"); + const list = new SubnetList(); + expect(list.remove(s1)).toBe(false); + }); + }); + + describe("hasSubnet", () => { + it("returns true if subnet is in the list", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const list = new SubnetList([s1]); + expect(list.hasSubnet(s1)).toBe(true); + }); + + it("returns true if subnet is part of a larger one contained in the list", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/24"); + const s2 = Subnet.fromCIDR("192.0.2.128/25"); + const list = new SubnetList([s1]); + expect(list.hasSubnet(s2)).toBe(true); + }); + + it("returns false if subnet is not in the list", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const list = new SubnetList([Subnet.fromCIDR("198.51.100.0/24")]); + expect(list.hasSubnet(s1)).toBe(false); + }); + }); + + describe("subnets", () => { + it("returns all subnets", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const s2 = Subnet.fromCIDR("192.0.2.128/25"); + const list = new SubnetList([s1, s2]); + const all = list.subnets(); + for (const s of [s1, s2]) { + const found = all.some(x => x.containsSubnet(s)); + expect(found).toBe(true); + } + const total = all.reduce((sum, s) => sum + s.size(), 0n); + expect(total).toBe(s1.size() + s2.size()); + }); + }); + + describe("contains", () => { + it("returns true for IPs within any subnet", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/24"); + const s2 = Subnet.fromCIDR("198.51.100.0/24"); + const list = new SubnetList([s1, s2]); + expect(list.contains(IPv4.fromString("192.0.2.78"))).toBe(true); + expect(list.contains(IPv4.fromString("198.51.100.69"))).toBe(true); + }); + + it("returns false for IPs outside all subnets", () => { + const ip = IPv4.fromString("198.51.100.1"); + const s = Subnet.fromCIDR("192.0.2.0/24"); + const list = new SubnetList([s]); + expect(list.contains(ip)).toBe(false); + }); + }); + + describe("size", () => { + it("returns sum of all subnet sizes", () => { + const s1 = Subnet.fromCIDR("192.0.2.0/25"); + const s2 = Subnet.fromCIDR("192.0.2.128/25"); + const s3 = Subnet.fromCIDR("203.0.113.0/24"); + const list = new SubnetList([s1, s2, s3]); + expect(list.size()).toBe(s1.size() + s2.size() + s3.size()); + }); + + it("returns 0 when empty", () => { + const list = new SubnetList(); + expect(list.size()).toBe(0n); + }); + }); + + describe("[Symbol.iterator]", () => { + it("iterates over all IPs in all subnets", () => { + const s1 = Subnet.fromCIDR("192.0.2.64/30"); + const s2 = Subnet.fromCIDR("192.0.2.24/30"); + const list = new SubnetList([s1, s2]); + const ips = Array.from(list).map(ip => ip.toString()); + expect(ips).toEqual([ + "192.0.2.24", + "192.0.2.25", + "192.0.2.26", + "192.0.2.27", + "192.0.2.64", + "192.0.2.65", + "192.0.2.66", + "192.0.2.67", + ]); + }); + + it("iterates zero times when empty", () => { + const list = new SubnetList(); + expect(Array.from(list)).toHaveLength(0); + }); + }); + + describe("static BOGON", () => { + it("is a SubnetList instance", () => { + expect(SubnetList.BOGON).toBeInstanceOf(SubnetList); + }); + + it("contains a common IPv4 bogon address", () => { + const ip = IPv4.fromString("192.0.2.42"); + expect(SubnetList.BOGON.contains(ip)).toBe(true); + }); + + it("contains a common IPv6 bogon address", () => { + const ip = IPv6.fromString("2001:db8::cafe:babe"); + expect(SubnetList.BOGON.contains(ip)).toBe(true); + }); + + it("does not contain a public IPv4 address", () => { + const ip = IPv4.fromString("1.1.1.1"); + expect(SubnetList.BOGON.contains(ip)).toBe(false); + }); + + it("does not contain a public IPv6 address", () => { + const ip = IPv6.fromString("2606:4700:4700::1111"); + expect(SubnetList.BOGON.contains(ip)).toBe(false); + }); + }); +}); diff --git a/tests/tsconfig.json b/tests/tsconfig.json new file mode 100644 index 0000000..43a00ee --- /dev/null +++ b/tests/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.json", + "include": [ + "**/*" + ], + "compilerOptions": { + "noEmit": true + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..418ca4b --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,17 @@ +import {defineConfig} from "vitest/config"; + +declare const process: {env: Record} + +export default defineConfig({ + test: { + reporters: process.env.GITHUB_ACTIONS ? "default" : ["default", "html"], + coverage: { + reporter: process.env.GITHUB_ACTIONS ? "text" : ["text", "html"], + include: ["src/**"], + all: true, + thresholds: { + 100: true, + }, + }, + }, +}); From 8f20c73b6683bb003d88f3eaac86290886d584e0 Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 19 Jul 2025 18:33:08 +0300 Subject: [PATCH 3/7] Add `ffff` to project dictionary --- .idea/dictionaries/project.xml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .idea/dictionaries/project.xml diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml new file mode 100644 index 0000000..d903933 --- /dev/null +++ b/.idea/dictionaries/project.xml @@ -0,0 +1,7 @@ + + + + ffff + + + \ No newline at end of file From 3d40e534ee5561066116247fb3fc3fe277785623 Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 19 Jul 2025 18:33:24 +0300 Subject: [PATCH 4/7] Use TypeScript compiler types from server --- .idea/compiler.xml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .idea/compiler.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..8ca546d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file From a10b11f3abe9d82e863f190f57c30f9399addfd1 Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 19 Jul 2025 18:38:00 +0300 Subject: [PATCH 5/7] Fixed punctuation in old copyright notices. --- src/IPAddress.ts | 2 +- src/IPv4.ts | 2 +- src/IPv6.ts | 2 +- src/Subnet.ts | 2 +- src/SubnetList.ts | 2 +- src/index.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/IPAddress.ts b/src/IPAddress.ts index 9266e56..fa59998 100644 --- a/src/IPAddress.ts +++ b/src/IPAddress.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024–2025 Cloudnode OÜ + * Copyright © 2024–2025 Cloudnode OÜ. * * This file is part of @cldn/ip. * diff --git a/src/IPv4.ts b/src/IPv4.ts index 34f6c9d..68e3bfa 100644 --- a/src/IPv4.ts +++ b/src/IPv4.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024–2025 Cloudnode OÜ + * Copyright © 2024–2025 Cloudnode OÜ. * * This file is part of @cldn/ip. * diff --git a/src/IPv6.ts b/src/IPv6.ts index 0a6ceaa..81e4363 100644 --- a/src/IPv6.ts +++ b/src/IPv6.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024–2025 Cloudnode OÜ + * Copyright © 2024–2025 Cloudnode OÜ. * * This file is part of @cldn/ip. * diff --git a/src/Subnet.ts b/src/Subnet.ts index 1649ef2..67ebc59 100644 --- a/src/Subnet.ts +++ b/src/Subnet.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024–2025 Cloudnode OÜ + * Copyright © 2024–2025 Cloudnode OÜ. * * This file is part of @cldn/ip. * diff --git a/src/SubnetList.ts b/src/SubnetList.ts index 16f6a68..c6bf622 100644 --- a/src/SubnetList.ts +++ b/src/SubnetList.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024–2025 Cloudnode OÜ + * Copyright © 2024–2025 Cloudnode OÜ. * * This file is part of @cldn/ip. * diff --git a/src/index.ts b/src/index.ts index 0ae5179..7d67d68 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Cloudnode OÜ + * Copyright © 2024 Cloudnode OÜ. * * This file is part of @cldn/ip. * From 28ac2f459ee9125d58fdbc7c1e80073276495bfb Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sun, 20 Jul 2025 17:00:06 +0300 Subject: [PATCH 6/7] New documentation --- .github/workflows/ci.yml | 4 +- .gitignore | 4 +- README.md | 96 +- docs/.vitepress/config.ts | 37 + docs/index.md | 26 + package-lock.json | 1943 ++++++++++++++++++++++++++++++++----- package.json | 15 +- typedoc.json | 18 +- 8 files changed, 1880 insertions(+), 263 deletions(-) create mode 100644 docs/.vitepress/config.ts create mode 100644 docs/index.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4b8b13..974ee5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,7 +136,7 @@ jobs: - name: Generate docs if: "!github.event.release.prerelease" - run: npm run docs + run: npm run docs:build - name: Set up GitHub pages if: "!github.event.release.prerelease" @@ -146,7 +146,7 @@ jobs: if: "!github.event.release.prerelease" uses: actions/upload-pages-artifact@v3 with: - path: docs + path: docs/.vitepress/dist - name: Deploy to GitHub Pages if: "!github.event.release.prerelease" diff --git a/.gitignore b/.gitignore index 5266fa8..e33a66e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ node_modules/ dist/ -docs/ +docs/api/ +docs/.vitepress/dist/ +docs/.vitepress/cache/ coverage/ html/ diff --git a/README.md b/README.md index 451fac4..bd63d22 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,92 @@ # @cldn/ip -IP address utility. +[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://ip.cldn.pro) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github)](https://github.com/cloudnode-pro/ip) +[![NPM](https://img.shields.io/npm/v/@cldn/ip.svg)](https://www.npmjs.com/package/@cldn/ip) +[![Downloads](https://img.shields.io/npm/d18m/@cldn/ip.svg)](https://www.npmjs.com/package/@cldn/ip) +[![Licence](https://img.shields.io/github/license/cloudnode-pro/ip)](https://github.com/cloudnode-pro/ip/blob/master/COPYING) +[![CI](https://github.com/cloudnode-pro/ip/actions/workflows/ci.yml/badge.svg)](https://github.com/cloudnode-pro/ip/actions/workflows/ci.yml) +![Coverage: 100%](https://img.shields.io/badge/coverage-100%25-brightgreen) -## Features +A modern, object-oriented TypeScript library for representing and performing arithmetic on IP addresses and subnets. + +[**Documentation — API Reference**](https://ip.cldn.pro) -- Works in the browser and in Node.js without any polyfills. (A bundler like Webpack or Vite is recommended for the - browser) -- IPv4 and IPv6 classes. -- Get IP address as BigInt, binary or string. -- Extract IPv4-mapped IPv6 addresses. -- Subnet class with methods to check IP membership, create netmask, list addresses, etc. -- Network class for working with multiple subnets. -- Written in TypeScript. +## Usage -See the [**Documentation**](https://ip.cldn.pro) +### Node.js -## Installation +Install with `npm`: ```sh npm install @cldn/ip ``` -## Usage +Import and use: ```ts import {IPv4, IPv6, Subnet} from "@cldn/ip"; +``` + +### Deno -const ipv6 = IPv4.fromString("::ffff:192.168.1.42"); -const ipv4 = ipv6.getMappedIPv4(); +Import the package from npm using the standard prefix: -const subnet = Subnet.fromString("192.168.0.0/16"); -subnet.has(ipv4); // true +```ts +import {IPv4, IPv6, Subnet} from "npm:@cldn/ip"; ``` -## Licence +### Browsers + +For browser usage, it is recommended to use a bundler like [Vite](https://vitejs.dev/), +or [Webpack](https://webpack.js.org/). If you are using a bundler, follow the same usage as for Node.js. + +Alternatively, you can import the library as +a [JavaScript module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) +from [ESM>CDN](https://esm.sh/): + +```html + + +``` -Copyright © 2024–2025 Cloudnode OÜ +## Features + +- Object-oriented representation of IPv4 and IPv6 addresses, and subnets. +- Comprehensive subnet arithmetic operations (e.g., containment, splitting, merging). +- Support for CIDR notation for defining and parsing subnets. +- Easy definition and manipulation of networks and collections of subnets. +- Support for IPv4-mapped IPv6 addresses. +- Fully documented, fully typed, and thoroughly tested with 100% coverage. +- Zero dependencies; compatible with frontend and backend environments without requiring polyfills. + +## Example + +```ts +import {IPv4, Subnet} from "@cldn/ip"; + +// Parse IPv4 address +const ip = IPv4.fromString("213.0.113.42"); +// Or use IPAddress.fromString("213.0.113.42") to parse either IPv4 or IPv6 + +// Create subnet from CIDR notation +const subnet = Subnet.fromCIDR("213.0.113.0/24"); -This file is part of @cldn/ip. +// Check if IP is within subnet +console.log(subnet.contains(ip)); // true +``` + +## Contact + +For bugs, or feature requests, please use [GitHub Issues](https://github.com/cloudnode-pro/ip/issues). + +For real-time chat or community discussions, join our Matrix +space: [#community\:cloudnode.pro](https://matrix.to/#/%23community:cloudnode.pro). + +## Licence -@cldn/ip is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General -Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any -later version. +Copyright © 2024–2025 Cloudnode OÜ. -@cldn/ip is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied -warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. +This project is licensed under the terms of the [LGPL-3.0](https://github.com/cloudnode-pro/ip/blob/master/COPYING) licence. diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 0000000..46b2be8 --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,37 @@ +import {defineConfig} from "vitepress"; +import typedocSidebar from "../api/typedoc-sidebar.json"; + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: "@cldn/ip", + description: "Documentation", + cleanUrls: true, + themeConfig: { + nav: [ + {text: "API Reference", link: "/api/"}, + ], + + sidebar: [ + { + text: "API", + items: typedocSidebar, + }, + ], + + outline: [2, 3], + + socialLinks: [ + {icon: "github", link: "https://github.com/cloudnode-pro/ip"}, + {icon: "matrix", link: "https://matrix.to/#/@cloudnode:matrix.org"}, + ], + + search: { + provider: "local", + }, + + footer: { + copyright: `Copyright © 2024–2025 Cloudnode OÜ.`, + message: `Released under the LGPL-3.0 licence.` + } + }, +}); diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..5321705 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,26 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "@cldn/ip" + text: "Documentation" + tagline: A modern, object-oriented TypeScript library for representing and performing arithmetic on IP addresses and subnets. + actions: + - theme: brand + text: API Reference + link: /api/ + +features: + - title: Unified IP Types + details: Object-oriented classes for IPv4 and IPv6, with full support for IPv4-mapped IPv6 addresses. + + - title: Subnet Logic + details: Perform checks, splits, merges, and other operations on CIDR-based subnets. + + - title: Network Modelling + details: Build and work with networks and subnet sets using simple, composable tools. + + - title: Typed and Minimal + details: Fully typed, thoroughly tested, and dependency-free. Works in any JS or TS environment. +--- diff --git a/package-lock.json b/package-lock.json index 80c909b..9e1c552 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,257 @@ "@vitest/coverage-v8": "^3.2.4", "@vitest/ui": "^3.2.4", "typedoc": "^0.28.0", + "typedoc-plugin-markdown": "^4.7.1", "typedoc-plugin-mdn-links": "^5.0.1", + "typedoc-vitepress-theme": "^1.1.2", "typescript": "^5.6.3", + "vitepress": "^1.6.3", + "vitepress-plugin-auto-sidebar": "^1.3.5", "vitest": "^3.2.4" } }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.34.0.tgz", + "integrity": "sha512-d6ardhDtQsnMpyr/rPrS3YuIE9NYpY4rftkC7Ap9tyuhZ/+V3E/LH+9uEewPguKzVqduApdwJzYq2k+vAXVEbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.34.0.tgz", + "integrity": "sha512-WXIByjHNA106JO1Dj6b4viSX/yMN3oIB4qXr2MmyEmNq0MgfuPfPw8ayLRIZPa9Dp27hvM3G8MWJ4RG978HYFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.34.0.tgz", + "integrity": "sha512-JeN1XJLZIkkv6yK0KT93CIXXk+cDPUGNg5xeH4fN9ZykYFDWYRyqgaDo+qvg4RXC3WWkdQ+hogQuuCk4Y3Eotw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.34.0.tgz", + "integrity": "sha512-gdFlcQa+TWXJUsihHDlreFWniKPFIQ15i5oynCY4m9K3DCex5g5cVj9VG4Hsquxf2t6Y0yv8w6MvVTGDO8oRLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.34.0.tgz", + "integrity": "sha512-g91NHhIZDkh1IUeNtsUd8V/ZxuBc2ByOfDqhCkoQY3Z/mZszhpn3Czn6AR5pE81fx793vMaiOZvQVB5QttArkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.34.0.tgz", + "integrity": "sha512-cvRApDfFrlJ3Vcn37U4Nd/7S6T8cx7FW3mVLJPqkkzixv8DQ/yV+x4VLirxOtGDdq3KohcIbIGWbg1QuyOZRvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.34.0.tgz", + "integrity": "sha512-m9tK4IqJmn+flEPRtuxuHgiHmrKV0su5fuVwVpq8/es4DMjWMgX1a7Lg1PktvO8AbKaTp9kTtBAPnwXpuCwmEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.34.0.tgz", + "integrity": "sha512-2rxy4XoeRtIpzxEh5u5UgDC5HY4XbNdjzNgFx1eDrfFkSHpEVjirtLhISMy2N5uSFqYu1uUby5/NC1Soq8J7iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.34.0.tgz", + "integrity": "sha512-OJiDhlJX8ZdWAndc50Z6aUEW/YmnhFK2ul3rahMw5/c9Damh7+oY9SufoK2LimJejy+65Qka06YPG29v2G/vww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.34.0.tgz", + "integrity": "sha512-fzNQZAdVxu/Gnbavy8KW5gurApwdYcPW6+pjO7Pw8V5drCR3eSqnOxSvp79rhscDX8ezwqMqqK4F3Hsq+KpRzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.34.0.tgz", + "integrity": "sha512-gEI0xjzA/xvMpEdYmgQnf6AQKllhgKRtnEWmwDrnct+YPIruEHlx1dd7nRJTy/33MiYcCxkB4khXpNrHuqgp3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.34.0.tgz", + "integrity": "sha512-5SwGOttpbACT4jXzfSJ3mnTcF46SVNSnZ1JjxC3qBa3qKi4U0CJGzuVVy3L798u8dG5H0SZ2MAB5v7180Gnqew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.34.0.tgz", + "integrity": "sha512-409XlyIyEXrxyGjWxd0q5RASizHSRVUU0AXPCEdqnbcGEzbCgL1n7oYI8YxzE/RqZLha+PNwWCcTVn7EE5tyyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -91,10 +337,61 @@ "node": ">=18" } }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz", + "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz", - "integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -105,13 +402,13 @@ "aix" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz", - "integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -122,13 +419,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz", - "integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -139,13 +436,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz", - "integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -156,13 +453,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz", - "integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -173,13 +470,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz", - "integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -190,13 +487,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz", - "integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -207,13 +504,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz", - "integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -224,13 +521,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz", - "integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -241,13 +538,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz", - "integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -258,13 +555,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz", - "integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -275,13 +572,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz", - "integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -292,13 +589,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz", - "integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -309,13 +606,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz", - "integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -326,13 +623,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz", - "integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -343,13 +640,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz", - "integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -360,13 +657,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz", - "integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -377,30 +674,13 @@ "linux" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz", - "integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz", - "integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -411,30 +691,13 @@ "netbsd" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz", - "integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz", - "integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -445,30 +708,13 @@ "openbsd" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz", - "integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz", - "integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -479,13 +725,13 @@ "sunos" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz", - "integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -496,13 +742,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz", - "integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -513,13 +759,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz", - "integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -530,7 +776,7 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@gerrit0/mini-shiki": { @@ -546,6 +792,23 @@ "@shikijs/vscode-textmate": "^10.0.2" } }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.44", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.44.tgz", + "integrity": "sha512-CdWgSPygwDlDbKtDWjvi3NtUefnkoepXv90n3dQxJerqzD9kI+nEJOiWUBM+eOyMYQKtxBpLWFBrgeotF0IZKw==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -911,37 +1174,119 @@ "win32" ] }, - "node_modules/@shikijs/engine-oniguruma": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.7.0.tgz", - "integrity": "sha512-5BxcD6LjVWsGu4xyaBC5bu8LdNgPCVBnAkWTtOCs/CZxcB22L8rcoWfv7Hh/3WooVjBZmFtyxhgvkQFedPGnFw==", + "node_modules/@shikijs/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", + "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "3.7.0", - "@shikijs/vscode-textmate": "^10.0.2" + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" } }, - "node_modules/@shikijs/langs": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.7.0.tgz", - "integrity": "sha512-1zYtdfXLr9xDKLTGy5kb7O0zDQsxXiIsw1iIBcNOO8Yi5/Y1qDbJ+0VsFoqTlzdmneO8Ij35g7QKF8kcLyznCQ==", + "node_modules/@shikijs/core/node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "3.7.0" + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" } }, - "node_modules/@shikijs/themes": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.7.0.tgz", - "integrity": "sha512-VJx8497iZPy5zLiiCTSIaOChIcKQwR0FebwE9S3rcN0+J/GTWwQ1v/bqhTbpbY3zybPKeO8wdammqkpXc4NVjQ==", + "node_modules/@shikijs/core/node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "3.7.0" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, - "node_modules/@shikijs/types": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.7.0.tgz", + "node_modules/@shikijs/engine-javascript": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz", + "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^3.1.0" + } + }, + "node_modules/@shikijs/engine-javascript/node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.7.0.tgz", + "integrity": "sha512-5BxcD6LjVWsGu4xyaBC5bu8LdNgPCVBnAkWTtOCs/CZxcB22L8rcoWfv7Hh/3WooVjBZmFtyxhgvkQFedPGnFw==", + "dev": true, + "dependencies": { + "@shikijs/types": "3.7.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.7.0.tgz", + "integrity": "sha512-1zYtdfXLr9xDKLTGy5kb7O0zDQsxXiIsw1iIBcNOO8Yi5/Y1qDbJ+0VsFoqTlzdmneO8Ij35g7QKF8kcLyznCQ==", + "dev": true, + "dependencies": { + "@shikijs/types": "3.7.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.7.0.tgz", + "integrity": "sha512-VJx8497iZPy5zLiiCTSIaOChIcKQwR0FebwE9S3rcN0+J/GTWwQ1v/bqhTbpbY3zybPKeO8wdammqkpXc4NVjQ==", + "dev": true, + "dependencies": { + "@shikijs/types": "3.7.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz", + "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/transformers/node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/types": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.7.0.tgz", "integrity": "sha512-MGaLeaRlSWpnP0XSAum3kP3a8vtcTsITqoEPYdt3lQG3YCdQH4DnEhodkYcNMcU0uW0RffhoD1O3e0vG5eSBBg==", "dev": true, "dependencies": { @@ -988,12 +1333,75 @@ "@types/unist": "*" } }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "dev": true }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, "node_modules/@vitest/coverage-v8": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz", @@ -1165,6 +1573,296 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vue/compiler-core": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.17.tgz", + "integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@vue/shared": "3.5.17", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz", + "integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz", + "integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@vue/compiler-core": "3.5.17", + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.17", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz", + "integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.7.tgz", + "integrity": "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.7" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz", + "integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.7", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz", + "integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.17.tgz", + "integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.17.tgz", + "integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz", + "integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.17", + "@vue/runtime-core": "3.5.17", + "@vue/shared": "3.5.17", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.17.tgz", + "integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17" + }, + "peerDependencies": { + "vue": "3.5.17" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.17.tgz", + "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz", + "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/integrations": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz", + "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vueuse/core": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/algoliasearch": { + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.34.0.tgz", + "integrity": "sha512-wioVnf/8uuG8Bmywhk5qKIQ3wzCCtmdvicPRb0fa3kKYGGoewfgDqLEaET1MV2NbTc3WGpPv+AgauLVBp1nB9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-abtesting": "5.34.0", + "@algolia/client-analytics": "5.34.0", + "@algolia/client-common": "5.34.0", + "@algolia/client-insights": "5.34.0", + "@algolia/client-personalization": "5.34.0", + "@algolia/client-query-suggestions": "5.34.0", + "@algolia/client-search": "5.34.0", + "@algolia/ingestion": "1.34.0", + "@algolia/monitoring": "1.34.0", + "@algolia/recommend": "5.34.0", + "@algolia/requester-browser-xhr": "5.34.0", + "@algolia/requester-fetch": "5.34.0", + "@algolia/requester-node-http": "5.34.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", @@ -1227,6 +1925,16 @@ "dev": true, "license": "MIT" }, + "node_modules/birpc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.5.0.tgz", + "integrity": "sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -1247,6 +1955,17 @@ "node": ">=8" } }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chai": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.1.tgz", @@ -1264,6 +1983,28 @@ "node": ">=18" } }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", @@ -1294,6 +2035,33 @@ "dev": true, "license": "MIT" }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1309,6 +2077,13 @@ "node": ">= 8" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -1337,6 +2112,30 @@ "node": ">=6" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1351,6 +2150,13 @@ "dev": true, "license": "MIT" }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -1372,9 +2178,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz", - "integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1382,35 +2188,46 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=18" + "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.6", - "@esbuild/android-arm": "0.25.6", - "@esbuild/android-arm64": "0.25.6", - "@esbuild/android-x64": "0.25.6", - "@esbuild/darwin-arm64": "0.25.6", - "@esbuild/darwin-x64": "0.25.6", - "@esbuild/freebsd-arm64": "0.25.6", - "@esbuild/freebsd-x64": "0.25.6", - "@esbuild/linux-arm": "0.25.6", - "@esbuild/linux-arm64": "0.25.6", - "@esbuild/linux-ia32": "0.25.6", - "@esbuild/linux-loong64": "0.25.6", - "@esbuild/linux-mips64el": "0.25.6", - "@esbuild/linux-ppc64": "0.25.6", - "@esbuild/linux-riscv64": "0.25.6", - "@esbuild/linux-s390x": "0.25.6", - "@esbuild/linux-x64": "0.25.6", - "@esbuild/netbsd-arm64": "0.25.6", - "@esbuild/netbsd-x64": "0.25.6", - "@esbuild/openbsd-arm64": "0.25.6", - "@esbuild/openbsd-x64": "0.25.6", - "@esbuild/openharmony-arm64": "0.25.6", - "@esbuild/sunos-x64": "0.25.6", - "@esbuild/win32-arm64": "0.25.6", - "@esbuild/win32-ia32": "0.25.6", - "@esbuild/win32-x64": "0.25.6" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" } }, "node_modules/estree-walker": { @@ -1462,6 +2279,16 @@ "dev": true, "license": "ISC" }, + "node_modules/focus-trap": { + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.5.tgz", + "integrity": "sha512-7Ke1jyybbbPZyZXFxEftUtxFGLMpE2n6A+z//m4CRDlj0hW+o3iYSmh8nFlYMurOiJVDmJRilUQtJr08KfIxlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tabbable": "^6.2.0" + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -1479,6 +2306,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1525,6 +2362,51 @@ "node": ">=8" } }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -1532,6 +2414,17 @@ "dev": true, "license": "MIT" }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "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", @@ -1542,6 +2435,19 @@ "node": ">=8" } }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1626,6 +2532,30 @@ "dev": true, "license": "MIT" }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", @@ -1695,6 +2625,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/markdown-it": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", @@ -1713,11 +2650,127 @@ "markdown-it": "bin/markdown-it.mjs" } }, - "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==", + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, "node_modules/minimatch": { @@ -1746,6 +2799,20 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minisearch": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.2.tgz", + "integrity": "sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -1782,6 +2849,18 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/oniguruma-to-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.1.tgz", + "integrity": "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, "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", @@ -1833,6 +2912,13 @@ "node": ">= 14.16" } }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1882,6 +2968,28 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/preact": { + "version": "10.26.9", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.9.tgz", + "integrity": "sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/punycode.js": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", @@ -1892,6 +3000,40 @@ "node": ">=6" } }, + "node_modules/regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", + "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rollup": { "version": "4.45.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz", @@ -1932,6 +3074,14 @@ "fsevents": "~2.3.2" } }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -1968,6 +3118,65 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz", + "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/langs": "2.5.0", + "@shikijs/themes": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/shiki/node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/shiki/node_modules/@shikijs/langs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz", + "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/shiki/node_modules/@shikijs/themes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz", + "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/shiki/node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -2013,6 +3222,34 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -2091,6 +3328,21 @@ "node": ">=8" } }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -2144,6 +3396,19 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/superjson": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", + "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2157,6 +3422,13 @@ "node": ">=8" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "dev": true, + "license": "MIT" + }, "node_modules/test-exclude": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", @@ -2243,6 +3515,17 @@ "node": ">=6" } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/typedoc": { "version": "0.28.7", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.7.tgz", @@ -2266,6 +3549,19 @@ "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" } }, + "node_modules/typedoc-plugin-markdown": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.7.1.tgz", + "integrity": "sha512-HN/fHLm2S6MD4HX8txfB4eWvVBzX/mEYy5U5s1KTAdh3E5uX5/lilswqTzZlPTT6fNZInAboAdFGpbAuBKnE4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typedoc": "0.28.x" + } + }, "node_modules/typedoc-plugin-mdn-links": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/typedoc-plugin-mdn-links/-/typedoc-plugin-mdn-links-5.0.4.tgz", @@ -2276,6 +3572,16 @@ "typedoc": "0.27.x || 0.28.x" } }, + "node_modules/typedoc-vitepress-theme": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/typedoc-vitepress-theme/-/typedoc-vitepress-theme-1.1.2.tgz", + "integrity": "sha512-hQvCZRr5uKDqY1bRuY1+eNTNn6d4TE4OP5pnw65Y7WGgajkJW9X1/lVJK2UJpcwCmwkdjw1QIO49H9JQlxWhhw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typedoc-plugin-markdown": ">=4.4.0" + } + }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -2297,25 +3603,125 @@ "dev": true, "license": "MIT" }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz", - "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==", + "version": "5.4.19", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", + "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.6", - "picomatch": "^4.0.2", - "postcss": "^8.5.6", - "rollup": "^4.40.0", - "tinyglobby": "^0.2.14" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -2324,25 +3730,19 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, - "jiti": { - "optional": true - }, "less": { "optional": true }, @@ -2363,12 +3763,6 @@ }, "terser": { "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true } } }, @@ -2395,6 +3789,72 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/vitepress": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.3.tgz", + "integrity": "sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "3.8.2", + "@docsearch/js": "3.8.2", + "@iconify-json/simple-icons": "^1.2.21", + "@shikijs/core": "^2.1.0", + "@shikijs/transformers": "^2.1.0", + "@shikijs/types": "^2.1.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^5.2.1", + "@vue/devtools-api": "^7.7.0", + "@vue/shared": "^3.5.13", + "@vueuse/core": "^12.4.0", + "@vueuse/integrations": "^12.4.0", + "focus-trap": "^7.6.4", + "mark.js": "8.11.1", + "minisearch": "^7.1.1", + "shiki": "^2.1.0", + "vite": "^5.4.14", + "vue": "^3.5.13" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vitepress-plugin-auto-sidebar": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/vitepress-plugin-auto-sidebar/-/vitepress-plugin-auto-sidebar-1.3.5.tgz", + "integrity": "sha512-drC4CuJlE1IQFP8mv8BRMKZpHLFjJTdBw9C9TJ2VWyl6BOvIs157HCaDvcP/xM8fviG+mjSe3MJ2Z+wrsV4E4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "front-matter": "^4.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitepress/node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/vitest": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", @@ -2468,6 +3928,28 @@ } } }, + "node_modules/vue": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.17.tgz", + "integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-sfc": "3.5.17", + "@vue/runtime-dom": "3.5.17", + "@vue/server-renderer": "3.5.17", + "@vue/shared": "3.5.17" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2610,6 +4092,17 @@ "engines": { "node": ">= 14.6" } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/package.json b/package.json index 7468de2..2b5f97b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@cldn/ip", "version": "0.0.0-dev", - "description": "IP address utility", + "description": "A modern, object-oriented TypeScript library for representing and performing arithmetic on IP addresses and subnets.", "main": "dist/index.js", "type": "module", "files": [ @@ -10,8 +10,13 @@ ], "scripts": { "build": "tsc", - "docs": "typedoc src", - "test": "vitest run --coverage" + "test": "vitest run --coverage", + "docs:gen": "typedoc && rm -rf docs/api && mv api docs/api", + "predocs:dev": "npm run docs:gen", + "docs:dev": "vitepress dev docs", + "predocs:build": "npm run docs:gen", + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" }, "repository": { "type": "git", @@ -38,8 +43,12 @@ "@vitest/coverage-v8": "^3.2.4", "@vitest/ui": "^3.2.4", "typedoc": "^0.28.0", + "typedoc-plugin-markdown": "^4.7.1", "typedoc-plugin-mdn-links": "^5.0.1", + "typedoc-vitepress-theme": "^1.1.2", "typescript": "^5.6.3", + "vitepress": "^1.6.3", + "vitepress-plugin-auto-sidebar": "^1.3.5", "vitest": "^3.2.4" } } diff --git a/typedoc.json b/typedoc.json index 8187ad7..624b579 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,10 +1,16 @@ { "$schema": "https://typedoc.org/schema.json", - "out": "docs", - "darkHighlightTheme": "aurora-x", - "lightHighlightTheme": "catppuccin-latte", - "plugin": ["typedoc-plugin-mdn-links"], + "entryPoints": ["src/index.ts"], + "out": "./api", + "plugin": [ + "typedoc-plugin-mdn-links", + "typedoc-plugin-markdown", + "typedoc-vitepress-theme" + ], "includeVersion": true, - "githubPages": true, - "customFooterHtml": "Copyright © 2024 Cloudnode OÜ. Licensed under the LGPL-3.0." + "readme": "none", + "hideBreadcrumbs": true, + "excludeInternal": true, + "excludePrivate": true, + "excludeProtected": false } From 6a6caa8644bc4d20b6c4e83618a1587c3efcbe06 Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sun, 20 Jul 2025 21:08:57 +0300 Subject: [PATCH 7/7] Updated the package.json tags & homepage --- package.json | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 2b5f97b..eca89d6 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,11 @@ "name": "@cldn/ip", "version": "0.0.0-dev", "description": "A modern, object-oriented TypeScript library for representing and performing arithmetic on IP addresses and subnets.", - "main": "dist/index.js", + "homepage": "https://ip.cldn.pro", + "author": "Cloudnode", + "license": "LGPL-3.0", "type": "module", + "main": "dist/index.js", "files": [ "dist/**.js", "dist/**.d.ts" @@ -22,23 +25,31 @@ "type": "git", "url": "git+https://github.com/cloudnode-pro/ip.git" }, + "bugs": { + "url": "https://github.com/cloudnode-pro/ip/issues" + }, "keywords": [ + "network", "ip", - "cidr", + "ipv4", + "ipv6", "subnet", - "network", - "net", - "ipcalc", + "cidr", "netmask", - "ipv4", - "ipv6" + "subnet-mask", + "cidr-range", + "cidr-ranges", + "cidr-subnet", + "cidr-list", + "cidr-calculator", + "subnet-calculator", + "ipcalc", + "ip-calc", + "ip-calculator", + "ip-address", + "net", + "library" ], - "author": "Cloudnode", - "license": "LGPL-3.0", - "bugs": { - "url": "https://github.com/cloudnode-pro/ip/issues" - }, - "homepage": "https://github.com/cloudnode-pro/ip#readme", "devDependencies": { "@vitest/coverage-v8": "^3.2.4", "@vitest/ui": "^3.2.4",