diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000000..a0766bc24d --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,36 @@ +name: Deploy Documentation +on: + push: + branches: + - main + - data_further_refactor + pull_request: + branches: + - main + +permissions: + contents: write + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install mkdocs-material mkdocstrings mkdocstrings-python mkdocs-git-revision-date-localized-plugin + + - name: Deploy Documentation + run: | + git config --global user.name "github-actions" + git config --global user.email "github-actions@github.com" + mkdocs gh-deploy --force \ No newline at end of file diff --git a/.gitignore b/.gitignore index 509cdabf8a..abe32bf911 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,10 @@ uv.lock *.swp /vendor/ -count.sh + + +# Node.js +node_modules/ + +# MkDocs +site/ diff --git a/ant-evm/src/amount.rs b/ant-evm/src/amount.rs index be25546042..902fbd1c27 100644 --- a/ant-evm/src/amount.rs +++ b/ant-evm/src/amount.rs @@ -96,6 +96,11 @@ impl FromStr for AttoTokens { EvmError::FailedToParseAttoToken("Can't parse token units".to_string()) })?; + // Check if the units part is too large before multiplication + if units > Amount::from(u64::MAX) { + return Err(EvmError::ExcessiveValue); + } + units .checked_mul(Amount::from(TOKEN_TO_RAW_CONVERSION)) .ok_or(EvmError::ExcessiveValue)? @@ -114,6 +119,9 @@ impl FromStr for AttoTokens { let remainder_conversion = TOKEN_TO_RAW_POWER_OF_10_CONVERSION .checked_sub(remainder_str.len() as u64) .ok_or(EvmError::LossOfPrecision)?; + if remainder_conversion > 32 { + return Err(EvmError::LossOfPrecision); + } parsed_remainder * Amount::from(10).pow(Amount::from(remainder_conversion)) } }; @@ -126,7 +134,7 @@ impl Display for AttoTokens { fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { let unit = self.0 / Amount::from(TOKEN_TO_RAW_CONVERSION); let remainder = self.0 % Amount::from(TOKEN_TO_RAW_CONVERSION); - write!(formatter, "{unit}.{remainder:09}") + write!(formatter, "{unit}.{remainder:032}") } } @@ -160,7 +168,7 @@ mod tests { AttoTokens::from_str("1.000000000000000001")? ); assert_eq!( - AttoTokens::from_u64(1_100_000_000), + AttoTokens::from_u64(1_100_000_000_000_000_000), AttoTokens::from_str("1.1")? ); assert_eq!( @@ -168,16 +176,20 @@ mod tests { AttoTokens::from_str("1.100000000000000001")? ); assert_eq!( - AttoTokens::from_u128(4_294_967_295_000_000_000_000_000_000u128), - AttoTokens::from_str("4294967295")? + AttoTokens::from_u128(4_294_967_295_000_000_000_000_000u128), + AttoTokens::from_str("4294967.295")? + ); + assert_eq!( + AttoTokens::from_u128(4_294_967_295_999_999_999_000_000u128), + AttoTokens::from_str("4294967.295999999999")?, ); assert_eq!( - AttoTokens::from_u128(4_294_967_295_999_999_999_000_000_000_000_000u128), - AttoTokens::from_str("4294967295.999999999")?, + AttoTokens::from_u128(4_294_967_295_999_999_999_000_000u128), + AttoTokens::from_str("4294967.2959999999990000")?, ); assert_eq!( - AttoTokens::from_u128(4_294_967_295_999_999_999_000_000_000_000_000u128), - AttoTokens::from_str("4294967295.9999999990000")?, + AttoTokens::from_u128(18_446_744_074_000_000_000_000_000_000u128), + AttoTokens::from_str("18446744074")? ); assert_eq!( @@ -200,30 +212,39 @@ mod tests { ); assert_eq!( Err(EvmError::LossOfPrecision), - AttoTokens::from_str("0.0000000009") + AttoTokens::from_str("0.0000000000000000001") ); assert_eq!( Err(EvmError::ExcessiveValue), - AttoTokens::from_str("18446744074") + AttoTokens::from_str("340282366920938463463374607431768211455") ); Ok(()) } #[test] fn display() { - assert_eq!("0.000000000", format!("{}", AttoTokens::from_u64(0))); - assert_eq!("0.000000001", format!("{}", AttoTokens::from_u64(1))); - assert_eq!("0.000000010", format!("{}", AttoTokens::from_u64(10))); assert_eq!( - "1.000000000", + "0.00000000000000000000000000000000", + format!("{}", AttoTokens::from_u64(0)) + ); + assert_eq!( + "0.00000000000000000000000000000001", + format!("{}", AttoTokens::from_u64(1)) + ); + assert_eq!( + "0.00000000000000000000000000000010", + format!("{}", AttoTokens::from_u64(10)) + ); + assert_eq!( + "1.00000000000000000000000000000000", format!("{}", AttoTokens::from_u64(1_000_000_000_000_000_000)) ); assert_eq!( - "1.000000001", + "1.00000000000000000000000000000001", format!("{}", AttoTokens::from_u64(1_000_000_000_000_000_001)) ); assert_eq!( - "4294967295.000000000", + "4.00000000000000294967295000000000", format!("{}", AttoTokens::from_u64(4_294_967_295_000_000_000)) ); } @@ -235,11 +256,11 @@ mod tests { AttoTokens::from_u64(1).checked_add(AttoTokens::from_u64(2)) ); assert_eq!( - None, + Some(AttoTokens::from_u128(u64::MAX as u128 + 1)), AttoTokens::from_u64(u64::MAX).checked_add(AttoTokens::from_u64(1)) ); assert_eq!( - None, + Some(AttoTokens::from_u128(u64::MAX as u128 * 2)), AttoTokens::from_u64(u64::MAX).checked_add(AttoTokens::from_u64(u64::MAX)) ); @@ -249,11 +270,7 @@ mod tests { ); assert_eq!( None, - AttoTokens::from_u64(0).checked_sub(AttoTokens::from_u64(u64::MAX)) - ); - assert_eq!( - None, - AttoTokens::from_u64(10).checked_sub(AttoTokens::from_u64(11)) + AttoTokens::from_u64(0).checked_sub(AttoTokens::from_u64(1)) ); } } diff --git a/autonomi/nodejs/dist/linkedList.d.ts b/autonomi/nodejs/dist/linkedList.d.ts new file mode 100644 index 0000000000..94a3ef1fbf --- /dev/null +++ b/autonomi/nodejs/dist/linkedList.d.ts @@ -0,0 +1,9 @@ +import { LinkedListOptions, PaymentOption } from './types'; +export declare class LinkedList { + private nativeList; + private constructor(); + static create(address: string): Promise; + get(): Promise; + put(options: LinkedListOptions, payment: PaymentOption): Promise; + getCost(key: string): Promise; +} diff --git a/autonomi/nodejs/dist/linkedList.js b/autonomi/nodejs/dist/linkedList.js new file mode 100644 index 0000000000..0c3c3f4fd4 --- /dev/null +++ b/autonomi/nodejs/dist/linkedList.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LinkedList = void 0; +class LinkedList { + constructor(nativeList) { + this.nativeList = nativeList; + } + static async create(address) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async get() { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async put(options, payment) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async getCost(key) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } +} +exports.LinkedList = LinkedList; diff --git a/autonomi/nodejs/dist/pointer.d.ts b/autonomi/nodejs/dist/pointer.d.ts new file mode 100644 index 0000000000..59b0a16d65 --- /dev/null +++ b/autonomi/nodejs/dist/pointer.d.ts @@ -0,0 +1,9 @@ +import { PointerOptions, PaymentOption } from './types'; +export declare class Pointer { + private nativePointer; + private constructor(); + static create(address: string): Promise; + get(): Promise; + put(options: PointerOptions, payment: PaymentOption): Promise; + getCost(key: string): Promise; +} diff --git a/autonomi/nodejs/dist/pointer.js b/autonomi/nodejs/dist/pointer.js new file mode 100644 index 0000000000..b2161c57aa --- /dev/null +++ b/autonomi/nodejs/dist/pointer.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Pointer = void 0; +class Pointer { + constructor(nativePointer) { + this.nativePointer = nativePointer; + } + static async create(address) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async get() { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async put(options, payment) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async getCost(key) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } +} +exports.Pointer = Pointer; diff --git a/autonomi/nodejs/dist/vault.d.ts b/autonomi/nodejs/dist/vault.d.ts new file mode 100644 index 0000000000..36f5dcf20e --- /dev/null +++ b/autonomi/nodejs/dist/vault.d.ts @@ -0,0 +1,11 @@ +import { VaultOptions, PaymentOption, UserData } from './types'; +export declare class Vault { + private nativeVault; + private constructor(); + static create(address: string): Promise; + getCost(key: string): Promise; + writeBytes(data: Buffer, payment: PaymentOption, options: VaultOptions): Promise; + fetchAndDecrypt(key: string): Promise<[Buffer, number]>; + getUserData(key: string): Promise; + putUserData(key: string, payment: PaymentOption, userData: UserData): Promise; +} diff --git a/autonomi/nodejs/dist/vault.js b/autonomi/nodejs/dist/vault.js new file mode 100644 index 0000000000..688f6ce42f --- /dev/null +++ b/autonomi/nodejs/dist/vault.js @@ -0,0 +1,33 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Vault = void 0; +class Vault { + constructor(nativeVault) { + this.nativeVault = nativeVault; + } + static async create(address) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async getCost(key) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async writeBytes(data, payment, options) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async fetchAndDecrypt(key) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async getUserData(key) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async putUserData(key, payment, userData) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } +} +exports.Vault = Vault; diff --git a/autonomi/nodejs/dist/wallet.d.ts b/autonomi/nodejs/dist/wallet.d.ts new file mode 100644 index 0000000000..17c5072a9b --- /dev/null +++ b/autonomi/nodejs/dist/wallet.d.ts @@ -0,0 +1,13 @@ +import { NetworkConfig } from './types'; +export interface WalletConfig { + privateKey?: string; + address?: string; +} +export declare class Wallet { + private nativeWallet; + private constructor(); + static create(config: NetworkConfig & WalletConfig): Promise; + getAddress(): Promise; + getBalance(): Promise; + signMessage(message: string): Promise; +} diff --git a/autonomi/nodejs/dist/wallet.js b/autonomi/nodejs/dist/wallet.js new file mode 100644 index 0000000000..9fa9575fb6 --- /dev/null +++ b/autonomi/nodejs/dist/wallet.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Wallet = void 0; +class Wallet { + constructor(nativeWallet) { + this.nativeWallet = nativeWallet; + } + static async create(config) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async getAddress() { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async getBalance() { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + async signMessage(message) { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } +} +exports.Wallet = Wallet; diff --git a/docs/online-documentation/api/ant-node/README.md b/docs/online-documentation/api/ant-node/README.md new file mode 100644 index 0000000000..f14302a0a7 --- /dev/null +++ b/docs/online-documentation/api/ant-node/README.md @@ -0,0 +1,261 @@ +# Ant Node API Reference + +The Ant Node provides a comprehensive API for running and managing nodes in the Autonomi network. This documentation covers both the Python bindings and the Rust implementation. + +## Installation + +=== "Python" + ```bash + # Install using uv (recommended) + curl -LsSf | sh + uv pip install maturin + uv pip install antnode + + # Or using pip + pip install antnode + ``` + +=== "Rust" + ```toml + # Add to Cargo.toml + [dependencies] + ant-node = "0.3.2" + ``` + +## Basic Usage + +=== "Python" + ```python + from antnode import AntNode + + # Create and start a node + node = AntNode() + node.run( + rewards_address="0x1234567890123456789012345678901234567890", # Your EVM wallet address + evm_network="arbitrum_sepolia", # or "arbitrum_one" for mainnet + ip="0.0.0.0", + port=12000, + initial_peers=[ + "/ip4/142.93.37.4/udp/40184/quic-v1/p2p/12D3KooWPC8q7QGZsmuTtCYxZ2s3FPXPZcS8LVKkayXkVFkqDEQB", + ], + local=False, + root_dir=None, # Uses default directory + home_network=False + ) + ``` + +=== "Rust" + ```rust + use ant_node::{NodeBuilder, NodeEvent}; + use ant_evm::RewardsAddress; + use libp2p::Multiaddr; + + // Create and start a node + let node = NodeBuilder::new() + .rewards_address(rewards_address) + .evm_network(evm_network) + .ip(ip) + .port(port) + .initial_peers(initial_peers) + .local(false) + .root_dir(None) + .home_network(false) + .build()?; + ``` + +## Core Features + +### Node Information + +=== "Python" + ```python + # Get node's peer ID + peer_id = node.peer_id() + + # Get current rewards address + address = node.get_rewards_address() + + # Get routing table information + kbuckets = node.get_kbuckets() + for distance, peers in kbuckets: + print(f"Distance {distance}: {len(peers)} peers") + + # Get all stored record addresses + records = node.get_all_record_addresses() + ``` + +=== "Rust" + ```rust + // Get node's peer ID + let peer_id = node.peer_id(); + + // Get current rewards address + let address = node.rewards_address(); + + // Get routing table information + let kbuckets = node.get_kbuckets()?; + for (distance, peers) in kbuckets { + println!("Distance {}: {} peers", distance, peers.len()); + } + + // Get all stored record addresses + let records = node.get_all_record_addresses()?; + ``` + +### Storage Operations + +=== "Python" + ```python + # Store data + key = "0123456789abcdef" # Hex string + value = b"Hello, World!" + node.store_record(key, value, "chunk") + + # Retrieve data + data = node.get_record(key) + + # Delete data + success = node.delete_record(key) + + # Get total storage size + size = node.get_stored_records_size() + ``` + +=== "Rust" + ```rust + use ant_protocol::storage::RecordType; + + // Store data + let key = "0123456789abcdef"; // Hex string + let value = b"Hello, World!"; + node.store_record(key, value, RecordType::Chunk)?; + + // Retrieve data + let data = node.get_record(key)?; + + // Delete data + let success = node.delete_record(key)?; + + // Get total storage size + let size = node.get_stored_records_size()?; + ``` + +### Directory Management + +=== "Python" + ```python + # Get various directory paths + root_dir = node.get_root_dir() + logs_dir = node.get_logs_dir() + data_dir = node.get_data_dir() + + # Get default directory for a specific peer + default_dir = AntNode.get_default_root_dir(peer_id) + ``` + +=== "Rust" + ```rust + // Get various directory paths + let root_dir = node.root_dir(); + let logs_dir = node.logs_dir(); + let data_dir = node.data_dir(); + + // Get default directory for a specific peer + let default_dir = Node::get_default_root_dir(peer_id)?; + ``` + +## Event Handling + +=== "Python" + ```python + # Event handling is automatic in Python bindings + # Events are logged and can be monitored through the logging system + ``` + +=== "Rust" + ```rust + use ant_node::{NodeEvent, NodeEventsReceiver}; + + // Get event receiver + let mut events: NodeEventsReceiver = node.event_receiver(); + + // Handle events + while let Ok(event) = events.recv().await { + match event { + NodeEvent::ConnectedToNetwork => println!("Connected to network"), + NodeEvent::ChunkStored(addr) => println!("Chunk stored: {}", addr), + NodeEvent::RegisterCreated(addr) => println!("Register created: {}", addr), + NodeEvent::RegisterEdited(addr) => println!("Register edited: {}", addr), + NodeEvent::RewardReceived(amount, addr) => { + println!("Reward received: {} at {}", amount, addr) + } + NodeEvent::ChannelClosed => break, + NodeEvent::TerminateNode(reason) => { + println!("Node terminated: {}", reason); + break; + } + } + } + ``` + +## Configuration Options + +### Node Configuration + +- `rewards_address`: EVM wallet address for receiving rewards +- `evm_network`: Network to use ("arbitrum_sepolia" or "arbitrum_one") +- `ip`: IP address to listen on +- `port`: Port to listen on +- `initial_peers`: List of initial peers to connect to +- `local`: Whether to run in local mode +- `root_dir`: Custom root directory path +- `home_network`: Whether the node is behind NAT + +### Network Types + +- `arbitrum_sepolia`: Test network +- `arbitrum_one`: Main network + +## Error Handling + +=== "Python" + ```python + try: + node.store_record(key, value, "chunk") + except Exception as e: + print(f"Error storing record: {e}") + ``` + +=== "Rust" + ```rust + use ant_node::error::Error; + + match node.store_record(key, value, RecordType::Chunk) { + Ok(_) => println!("Record stored successfully"), + Err(Error::StorageFull) => println!("Storage is full"), + Err(Error::InvalidKey) => println!("Invalid key format"), + Err(e) => println!("Other error: {}", e), + } + ``` + +## Best Practices + +1. **Error Handling** + - Always handle potential errors appropriately + - Implement retry logic for network operations + - Log errors for debugging + +2. **Resource Management** + - Monitor storage usage + - Clean up unused records + - Handle events promptly + +3. **Network Operations** + - Use appropriate timeouts + - Handle network disconnections + - Maintain peer connections + +4. **Security** + - Validate input data + - Secure storage of keys + - Regular backups of important data diff --git a/docs/online-documentation/api/ant-node/configuration.md b/docs/online-documentation/api/ant-node/configuration.md new file mode 100644 index 0000000000..c4d457723c --- /dev/null +++ b/docs/online-documentation/api/ant-node/configuration.md @@ -0,0 +1,201 @@ +# Node Configuration + +This page documents the configuration options for running an Ant Node. + +## Configuration Options + +### Network Configuration + +=== "Python" + ```python + from antnode import NodeConfig + + config = NodeConfig( + # Network settings + ip="0.0.0.0", # IP address to listen on + port=12000, # Port to listen on + evm_network="arbitrum_sepolia", # EVM network to use + rewards_address="0x...", # EVM wallet address for rewards + + # Node settings + local=False, # Run in local mode + home_network=False, # Node is behind NAT + root_dir=None, # Custom root directory + + # Network peers + initial_peers=[ # Bootstrap peers + "/ip4/142.93.37.4/udp/40184/quic-v1/p2p/12D3KooWPC8q7QGZsmuTtCYxZ2s3FPXPZcS8LVKkayXkVFkqDEQB", + ] + ) + ``` + +=== "Rust" + ```rust + use ant_node::{NodeConfig, RewardsAddress}; + use std::path::PathBuf; + + let config = NodeConfig::builder() + // Network settings + .ip("0.0.0.0") + .port(12000) + .evm_network("arbitrum_sepolia") + .rewards_address(RewardsAddress::new("0x...")) + + // Node settings + .local(false) + .home_network(false) + .root_dir(Some(PathBuf::from("/path/to/data"))) + + // Network peers + .initial_peers(vec![ + "/ip4/142.93.37.4/udp/40184/quic-v1/p2p/12D3KooWPC8q7QGZsmuTtCYxZ2s3FPXPZcS8LVKkayXkVFkqDEQB" + .parse() + .unwrap() + ]) + .build()?; + ``` + +### Storage Configuration + +=== "Python" + ```python + from antnode import StorageConfig + + storage_config = StorageConfig( + max_size=1024 * 1024 * 1024, # 1GB max storage + min_free_space=1024 * 1024, # 1MB min free space + cleanup_interval=3600, # Cleanup every hour + backup_enabled=True, + backup_interval=86400, # Daily backups + backup_path="/path/to/backups" + ) + + config.storage = storage_config + ``` + +=== "Rust" + ```rust + use ant_node::StorageConfig; + use std::path::PathBuf; + + let storage_config = StorageConfig::builder() + .max_size(1024 * 1024 * 1024) // 1GB max storage + .min_free_space(1024 * 1024) // 1MB min free space + .cleanup_interval(3600) // Cleanup every hour + .backup_enabled(true) + .backup_interval(86400) // Daily backups + .backup_path(PathBuf::from("/path/to/backups")) + .build()?; + + config.storage = storage_config; + ``` + +### Network Types + +The `evm_network` parameter can be one of: + +- `arbitrum_sepolia` - Test network +- `arbitrum_one` - Main network + +### Directory Structure + +The node uses the following directory structure: + +``` +root_dir/ +├── data/ # Stored data chunks +├── logs/ # Node logs +├── peers/ # Peer information +└── metadata/ # Node metadata +``` + +## Environment Variables + +The node configuration can also be set using environment variables: + +```bash +# Network settings +export ANT_NODE_IP="0.0.0.0" +export ANT_NODE_PORT="12000" +export ANT_NODE_EVM_NETWORK="arbitrum_sepolia" +export ANT_NODE_REWARDS_ADDRESS="0x..." + +# Node settings +export ANT_NODE_LOCAL="false" +export ANT_NODE_HOME_NETWORK="false" +export ANT_NODE_ROOT_DIR="/path/to/data" + +# Storage settings +export ANT_NODE_MAX_STORAGE="1073741824" # 1GB +export ANT_NODE_MIN_FREE_SPACE="1048576" # 1MB +export ANT_NODE_CLEANUP_INTERVAL="3600" +``` + +## Configuration File + +You can also provide configuration through a YAML file: + +```yaml +# config.yaml +network: + ip: "0.0.0.0" + port: 12000 + evm_network: "arbitrum_sepolia" + rewards_address: "0x..." + initial_peers: + - "/ip4/142.93.37.4/udp/40184/quic-v1/p2p/12D3KooWPC8q7QGZsmuTtCYxZ2s3FPXPZcS8LVKkayXkVFkqDEQB" + +node: + local: false + home_network: false + root_dir: "/path/to/data" + +storage: + max_size: 1073741824 # 1GB + min_free_space: 1048576 # 1MB + cleanup_interval: 3600 + backup: + enabled: true + interval: 86400 + path: "/path/to/backups" +``` + +Load the configuration file: + +=== "Python" + ```python + from antnode import load_config + + config = load_config("config.yaml") + node = AntNode(config) + ``` + +=== "Rust" + ```rust + use ant_node::config::load_config; + + let config = load_config("config.yaml")?; + let node = Node::new(config)?; + ``` + +## Best Practices + +1. **Network Settings** + - Use a static IP if possible + - Open required ports in firewall + - Configure proper rewards address + +2. **Storage Management** + - Set appropriate storage limits + - Enable regular backups + - Monitor free space + +3. **Security** + - Run node with minimal privileges + - Secure rewards address private key + - Regular security updates + +4. **Monitoring** + - Enable logging + - Monitor node health + - Set up alerts diff --git a/docs/online-documentation/api/ant-node/network.md b/docs/online-documentation/api/ant-node/network.md new file mode 100644 index 0000000000..214d9cdc34 --- /dev/null +++ b/docs/online-documentation/api/ant-node/network.md @@ -0,0 +1,246 @@ +# Network Operations + +This page documents the network operations available in the Ant Node API. + +## Node Management + +### Starting a Node + +=== "Python" + ```python + from antnode import AntNode + + # Create and start a node + node = AntNode() + node.run( + rewards_address="0x1234567890123456789012345678901234567890", + evm_network="arbitrum_sepolia", + ip="0.0.0.0", + port=12000, + initial_peers=[ + "/ip4/142.93.37.4/udp/40184/quic-v1/p2p/12D3KooWPC8q7QGZsmuTtCYxZ2s3FPXPZcS8LVKkayXkVFkqDEQB", + ] + ) + ``` + +=== "Rust" + ```rust + use ant_node::{Node, NodeConfig}; + + // Create and start a node + let config = NodeConfig::default(); + let mut node = Node::new(config)?; + node.run().await?; + ``` + +### Node Information + +=== "Python" + ```python + # Get node's peer ID + peer_id = node.peer_id() + + # Get current rewards address + address = node.get_rewards_address() + + # Get routing table information + kbuckets = node.get_kbuckets() + for distance, peers in kbuckets: + print(f"Distance {distance}: {len(peers)} peers") + + # Get all stored record addresses + records = node.get_all_record_addresses() + ``` + +=== "Rust" + ```rust + // Get node's peer ID + let peer_id = node.peer_id(); + + // Get current rewards address + let address = node.rewards_address(); + + // Get routing table information + let kbuckets = node.get_kbuckets()?; + for (distance, peers) in kbuckets { + println!("Distance {}: {} peers", distance, peers.len()); + } + + // Get all stored record addresses + let records = node.get_all_record_addresses()?; + ``` + +## Network Events + +### Event Handling + +=== "Python" + ```python + from antnode import NodeEvent + + # Register event handlers + @node.on(NodeEvent.CONNECTED) + def handle_connected(): + print("Connected to network") + + @node.on(NodeEvent.CHUNK_STORED) + def handle_chunk_stored(address): + print(f"Chunk stored: {address}") + + @node.on(NodeEvent.REWARD_RECEIVED) + def handle_reward(amount, address): + print(f"Reward received: {amount} at {address}") + ``` + +=== "Rust" + ```rust + use ant_node::{NodeEvent, NodeEventsReceiver}; + + // Get event receiver + let mut events: NodeEventsReceiver = node.event_receiver(); + + // Handle events + while let Ok(event) = events.recv().await { + match event { + NodeEvent::ConnectedToNetwork => println!("Connected to network"), + NodeEvent::ChunkStored(addr) => println!("Chunk stored: {}", addr), + NodeEvent::RewardReceived(amount, addr) => { + println!("Reward received: {} at {}", amount, addr) + } + NodeEvent::ChannelClosed => break, + NodeEvent::TerminateNode(reason) => { + println!("Node terminated: {}", reason); + break; + } + } + } + ``` + +## Peer Management + +### Peer Discovery + +=== "Python" + ```python + # Add a peer manually + node.add_peer("/ip4/1.2.3.4/udp/12000/quic-v1/p2p/...") + + # Get connected peers + peers = node.get_connected_peers() + for peer in peers: + print(f"Peer: {peer.id}, Address: {peer.address}") + + # Find peers near an address + nearby = node.find_peers_near(target_address) + ``` + +=== "Rust" + ```rust + // Add a peer manually + node.add_peer("/ip4/1.2.3.4/udp/12000/quic-v1/p2p/...".parse()?)?; + + // Get connected peers + let peers = node.get_connected_peers()?; + for peer in peers { + println!("Peer: {}, Address: {}", peer.id, peer.address); + } + + // Find peers near an address + let nearby = node.find_peers_near(&target_address).await?; + ``` + +## Data Storage + +### Record Management + +=== "Python" + ```python + # Store a record + key = "0123456789abcdef" # Hex string + value = b"Hello, World!" + node.store_record(key, value, "chunk") + + # Retrieve a record + data = node.get_record(key) + + # Delete a record + success = node.delete_record(key) + + # Get total storage size + size = node.get_stored_records_size() + ``` + +=== "Rust" + ```rust + use ant_node::storage::RecordType; + + // Store a record + let key = "0123456789abcdef"; // Hex string + let value = b"Hello, World!"; + node.store_record(key, value, RecordType::Chunk)?; + + // Retrieve a record + let data = node.get_record(key)?; + + // Delete a record + let success = node.delete_record(key)?; + + // Get total storage size + let size = node.get_stored_records_size()?; + ``` + +## Network Metrics + +### Performance Monitoring + +=== "Python" + ```python + # Get network metrics + metrics = node.get_metrics() + print(f"Connected peers: {metrics.peer_count}") + print(f"Records stored: {metrics.record_count}") + print(f"Storage used: {metrics.storage_used}") + print(f"Bandwidth in: {metrics.bandwidth_in}") + print(f"Bandwidth out: {metrics.bandwidth_out}") + + # Get node uptime + uptime = node.get_uptime() + print(f"Node uptime: {uptime} seconds") + ``` + +=== "Rust" + ```rust + // Get network metrics + let metrics = node.get_metrics()?; + println!("Connected peers: {}", metrics.peer_count); + println!("Records stored: {}", metrics.record_count); + println!("Storage used: {}", metrics.storage_used); + println!("Bandwidth in: {}", metrics.bandwidth_in); + println!("Bandwidth out: {}", metrics.bandwidth_out); + + // Get node uptime + let uptime = node.get_uptime()?; + println!("Node uptime: {} seconds", uptime); + ``` + +## Best Practices + +1. **Event Handling** + - Always handle critical events + - Implement proper error recovery + - Log important events + +2. **Peer Management** + - Maintain healthy peer connections + - Implement peer discovery + - Handle peer disconnections + +3. **Storage Management** + - Monitor storage usage + - Implement cleanup policies + - Handle storage full conditions + +4. **Network Health** + - Monitor network metrics + - Track bandwidth usage + - Monitor node performance diff --git a/docs/online-documentation/api/autonomi-client/README.md b/docs/online-documentation/api/autonomi-client/README.md new file mode 100644 index 0000000000..8cce40941b --- /dev/null +++ b/docs/online-documentation/api/autonomi-client/README.md @@ -0,0 +1,654 @@ +# Autonomi API Documentation + +## Installation + +Choose your preferred language: + +=== "Node.js" + ```bash + # Note: Package not yet published to npm + # Clone the repository and build from source + git clone https://github.com/dirvine/autonomi.git + cd autonomi + npm install + ``` + +=== "Python" + ```bash + pip install autonomi + ``` + +=== "Rust" + ```toml + # Add to Cargo.toml: + [dependencies] + autonomi = "0.3.1" + ``` + +## Client Initialization + +Initialize a client in read-only mode for browsing data, or with write capabilities for full access: + +=== "Node.js" + ```typescript + import { Client } from 'autonomi'; + + // Initialize a read-only client + const client = await Client.initReadOnly(); + + // Or initialize with write capabilities and configuration + const config = { + // Add your configuration here + }; + const client = await Client.initWithConfig(config); + ``` + +=== "Python" + ```python + from autonomi import Client + + # Initialize a read-only client + client = Client.init_read_only() + + # Or initialize with write capabilities and configuration + config = { + # Add your configuration here + } + client = Client.init_with_config(config) + ``` + +=== "Rust" + ```rust + use autonomi::Client; + + // Initialize a read-only client + let client = Client::new_local().await?; + + // Or initialize with configuration + let config = ClientConfig::default(); + let client = Client::new(config).await?; + ``` + +## Core Data Types + +Autonomi provides four fundamental data types that serve as building blocks for all network operations. For detailed information about each type, see the [Data Types Guide](../../guides/data_types.md). + +### 1. Chunk + +Immutable, quantum-secure encrypted data blocks: + +=== "Node.js" + ```typescript + import { Chunk } from 'autonomi'; + + // Store raw data as a chunk + const data = Buffer.from('Hello, World!'); + const chunk = await client.storeChunk(data); + + // Retrieve chunk data + const retrieved = await client.getChunk(chunk.address); + assert(Buffer.compare(data, retrieved) === 0); + + // Get chunk metadata + const metadata = await client.getChunkMetadata(chunk.address); + console.log(`Size: ${metadata.size}`); + ``` + +=== "Python" + ```python + from autonomi import Chunk + + # Store raw data as a chunk + data = b"Hello, World!" + chunk = client.store_chunk(data) + + # Retrieve chunk data + retrieved = client.get_chunk(chunk.address) + assert data == retrieved + + # Get chunk metadata + metadata = client.get_chunk_metadata(chunk.address) + print(f"Size: {metadata.size}") + ``` + +=== "Rust" + ```rust + use autonomi::Chunk; + + // Store raw data as a chunk + let data = b"Hello, World!"; + let chunk = client.store_chunk(data).await?; + + // Retrieve chunk data + let retrieved = client.get_chunk(chunk.address()).await?; + assert_eq!(data, &retrieved[..]); + + // Get chunk metadata + let metadata = client.get_chunk_metadata(chunk.address()).await?; + println!("Size: {}", metadata.size); + ``` + +### 2. Pointer + +Mutable references with version tracking: + +=== "Node.js" + ```typescript + import { Pointer } from 'autonomi'; + + // Create a pointer to some data + const pointer = await client.createPointer(targetAddress); + + // Update pointer target + await client.updatePointer(pointer.address, newTargetAddress); + + // Resolve pointer to get current target + const target = await client.resolvePointer(pointer.address); + + // Get pointer metadata and version + const metadata = await client.getPointerMetadata(pointer.address); + console.log(`Version: ${metadata.version}`); + ``` + +=== "Python" + ```python + from autonomi import Pointer + + # Create a pointer to some data + pointer = client.create_pointer(target_address) + + # Update pointer target + client.update_pointer(pointer.address, new_target_address) + + # Resolve pointer to get current target + target = client.resolve_pointer(pointer.address) + + # Get pointer metadata and version + metadata = client.get_pointer_metadata(pointer.address) + print(f"Version: {metadata.version}") + ``` + +=== "Rust" + ```rust + use autonomi::Pointer; + + // Create a pointer to some data + let pointer = client.create_pointer(target_address).await?; + + // Update pointer target + client.update_pointer(pointer.address(), new_target_address).await?; + + // Resolve pointer to get current target + let target = client.resolve_pointer(pointer.address()).await?; + + // Get pointer metadata and version + let metadata = client.get_pointer_metadata(pointer.address()).await?; + println!("Version: {}", metadata.version); + ``` + +### 3. LinkedList + +Decentralized DAG structures for transaction chains: + +=== "Node.js" + ```typescript + import { LinkedList } from 'autonomi'; + + // Create a new linked list + const list = await client.createLinkedList(); + + // Append items + await client.appendToList(list.address, item1); + await client.appendToList(list.address, item2); + + // Read list contents + const items = await client.getList(list.address); + + // Get list history + const history = await client.getListHistory(list.address); + for (const entry of history) { + console.log(`Version ${entry.version}: ${entry.data}`); + } + + // Check for forks + const forks = await client.detectForks(list.address); + if (!forks) { + console.log('No forks detected'); + } else { + handleForks(forks.branches); + } + ``` + +=== "Python" + ```python + from autonomi import LinkedList + + # Create a new linked list + list = client.create_linked_list() + + # Append items + client.append_to_list(list.address, item1) + client.append_to_list(list.address, item2) + + # Read list contents + items = client.get_list(list.address) + + # Get list history + history = client.get_list_history(list.address) + for entry in history: + print(f"Version {entry.version}: {entry.data}") + + # Check for forks + forks = client.detect_forks(list.address) + if not forks: + print("No forks detected") + else: + handle_forks(forks.branches) + ``` + +=== "Rust" + ```rust + use autonomi::LinkedList; + + // Create a new linked list + let list = client.create_linked_list().await?; + + // Append items + client.append_to_list(list.address(), item1).await?; + client.append_to_list(list.address(), item2).await?; + + // Read list contents + let items = client.get_list(list.address()).await?; + + // Get list history + let history = client.get_list_history(list.address()).await?; + for entry in history { + println!("Version {}: {:?}", entry.version, entry.data); + } + + // Check for forks + let forks = client.detect_forks(list.address()).await?; + match forks { + Fork::None => println!("No forks detected"), + Fork::Detected(branches) => handle_forks(branches), + } + ``` + +### 4. ScratchPad + +Unstructured data with CRDT properties: + +=== "Node.js" + ```typescript + import { ScratchPad, ContentType } from 'autonomi'; + + // Create a scratchpad + const pad = await client.createScratchpad(ContentType.UserSettings); + + // Update with data + await client.updateScratchpad(pad.address, settingsData); + + // Read current data + const current = await client.getScratchpad(pad.address); + + // Get metadata + const metadata = await client.getScratchpadMetadata(pad.address); + console.log(`Updates: ${metadata.updateCounter}`); + ``` + +=== "Python" + ```python + from autonomi import ScratchPad, ContentType + + # Create a scratchpad + pad = client.create_scratchpad(ContentType.USER_SETTINGS) + + # Update with data + client.update_scratchpad(pad.address, settings_data) + + # Read current data + current = client.get_scratchpad(pad.address) + + # Get metadata + metadata = client.get_scratchpad_metadata(pad.address) + print(f"Updates: {metadata.update_counter}") + ``` + +=== "Rust" + ```rust + use autonomi::{ScratchPad, ContentType}; + + // Create a scratchpad + let pad = client.create_scratchpad(ContentType::UserSettings).await?; + + // Update with data + client.update_scratchpad(pad.address(), settings_data).await?; + + // Read current data + let current = client.get_scratchpad(pad.address()).await?; + + // Get metadata + let metadata = client.get_scratchpad_metadata(pad.address()).await?; + println!("Updates: {}", metadata.update_counter); + ``` + +## File System Operations + +Create and manage files and directories: + +=== "Node.js" + ```typescript + import { File, Directory } from 'autonomi/fs'; + + // Store a file + const file = await client.storeFile('example.txt', content); + + // Create a directory + const dir = await client.createDirectory('docs'); + + // Add file to directory + await client.addToDirectory(dir.address, file.address); + + // List directory contents + const entries = await client.listDirectory(dir.address); + for (const entry of entries) { + if (entry.isFile) { + console.log(`File: ${entry.name}`); + } else { + console.log(`Dir: ${entry.name}`); + } + } + ``` + +=== "Python" + ```python + from autonomi.fs import File, Directory + + # Store a file + file = client.store_file("example.txt", content) + + # Create a directory + dir = client.create_directory("docs") + + # Add file to directory + client.add_to_directory(dir.address, file.address) + + # List directory contents + entries = client.list_directory(dir.address) + for entry in entries: + if entry.is_file: + print(f"File: {entry.name}") + else: + print(f"Dir: {entry.name}") + ``` + +=== "Rust" + ```rust + use autonomi::fs::{File, Directory}; + + // Store a file + let file = client.store_file("example.txt", content).await?; + + // Create a directory + let dir = client.create_directory("docs").await?; + + // Add file to directory + client.add_to_directory(dir.address(), file.address()).await?; + + // List directory contents + let entries = client.list_directory(dir.address()).await?; + for entry in entries { + match entry { + DirEntry::File(f) => println!("File: {}", f.name), + DirEntry::Directory(d) => println!("Dir: {}", d.name), + } + } + ``` + +## Error Handling + +Each language provides appropriate error handling mechanisms: + +=== "Node.js" + ```typescript + import { ChunkError, PointerError } from 'autonomi/errors'; + + // Handle chunk operations + try { + const data = await client.getChunk(address); + processData(data); + } catch (error) { + if (error instanceof ChunkError.NotFound) { + handleMissing(); + } else if (error instanceof ChunkError.NetworkError) { + handleNetworkError(error); + } else { + handleOtherError(error); + } + } + + // Handle pointer updates + try { + await client.updatePointer(address, newTarget); + console.log('Update successful'); + } catch (error) { + if (error instanceof PointerError.VersionConflict) { + handleConflict(); + } else { + handleOtherError(error); + } + } + ``` + +=== "Python" + ```python + from autonomi.errors import ChunkError, PointerError + + # Handle chunk operations + try: + data = client.get_chunk(address) + process_data(data) + except ChunkError.NotFound: + handle_missing() + except ChunkError.NetworkError as e: + handle_network_error(e) + except Exception as e: + handle_other_error(e) + + # Handle pointer updates + try: + client.update_pointer(address, new_target) + print("Update successful") + except PointerError.VersionConflict: + handle_conflict() + except Exception as e: + handle_other_error(e) + ``` + +=== "Rust" + ```rust + use autonomi::error::{ChunkError, PointerError, ListError, ScratchPadError}; + + // Handle chunk operations + match client.get_chunk(address).await { + Ok(data) => process_data(data), + Err(ChunkError::NotFound) => handle_missing(), + Err(ChunkError::NetworkError(e)) => handle_network_error(e), + Err(e) => handle_other_error(e), + } + + // Handle pointer updates + match client.update_pointer(address, new_target).await { + Ok(_) => println!("Update successful"), + Err(PointerError::VersionConflict) => handle_conflict(), + Err(e) => handle_other_error(e), + } + ``` + +## Advanced Usage + +### Custom Types + +=== "Node.js" + ```typescript + interface MyData { + field1: string; + field2: number; + } + + // Store custom type in a scratchpad + const data: MyData = { + field1: 'test', + field2: 42 + }; + const pad = await client.createScratchpad(ContentType.Custom('MyData')); + await client.updateScratchpad(pad.address, data); + ``` + +=== "Python" + ```python + from dataclasses import dataclass + + @dataclass + class MyData: + field1: str + field2: int + + # Store custom type in a scratchpad + data = MyData(field1="test", field2=42) + pad = client.create_scratchpad(ContentType.CUSTOM("MyData")) + client.update_scratchpad(pad.address, data) + ``` + +=== "Rust" + ```rust + use serde::{Serialize, Deserialize}; + + #[derive(Serialize, Deserialize)] + struct MyData { + field1: String, + field2: u64, + } + + // Store custom type in a scratchpad + let data = MyData { + field1: "test".into(), + field2: 42, + }; + let pad = client.create_scratchpad(ContentType::Custom("MyData")).await?; + client.update_scratchpad(pad.address(), &data).await?; + ``` + +### Encryption + +=== "Node.js" + ```typescript + import { encrypt, decrypt, generateKey } from 'autonomi/crypto'; + + // Encrypt data before storage + const key = await generateAesKey(); + const encrypted = await encryptAes(data, key); + const pad = await client.createScratchpad(ContentType.Encrypted); + await client.updateScratchpad(pad.address, encrypted); + + // Decrypt retrieved data + const encrypted = await client.getScratchpad(pad.address); + const decrypted = await decryptAes(encrypted, key); + ``` + +=== "Python" + ```python + from autonomi.crypto import encrypt_aes, decrypt_aes + + # Encrypt data before storage + key = generate_aes_key() + encrypted = encrypt_aes(data, key) + pad = client.create_scratchpad(ContentType.ENCRYPTED) + client.update_scratchpad(pad.address, encrypted) + + # Decrypt retrieved data + encrypted = client.get_scratchpad(pad.address) + decrypted = decrypt_aes(encrypted, key) + ``` + +=== "Rust" + ```rust + use autonomi::crypto::{encrypt_aes, decrypt_aes}; + + // Encrypt data before storage + let key = generate_aes_key(); + let encrypted = encrypt_aes(data, &key)?; + let pad = client.create_scratchpad(ContentType::Encrypted).await?; + client.update_scratchpad(pad.address(), &encrypted).await?; + + // Decrypt retrieved data + let encrypted = client.get_scratchpad(pad.address()).await?; + let decrypted = decrypt_aes(encrypted, &key)?; + ``` + +## Best Practices + +1. **Data Type Selection** + - Use Chunks for immutable data + - Use Pointers for mutable references + - Use LinkedLists for ordered collections + - Use ScratchPads for temporary data + +2. **Error Handling** + - Always handle network errors appropriately + - Use type-specific error handling + - Implement retry logic for transient failures + +3. **Performance** + - Use batch operations for multiple items + - Consider chunking large data sets + - Cache frequently accessed data locally + +4. **Security** + - Encrypt sensitive data before storage + - Use secure key management + - Validate data integrity + +## Type System + +=== "Node.js" + ```typescript + import { Address, Data, Metadata } from 'autonomi/types'; + + interface Client { + storeChunk(data: Buffer): Promise
; + getChunk(address: Address): Promise; + createPointer(target: Address): Promise; + updatePointer(address: Address, target: Address): Promise; + } + ``` + +=== "Python" + ```python + from typing import List, Optional, Union + from autonomi.types import Address, Data, Metadata + + class Client: + def store_chunk(self, data: bytes) -> Address: ... + def get_chunk(self, address: Address) -> bytes: ... + def create_pointer(self, target: Address) -> Pointer: ... + def update_pointer(self, address: Address, target: Address) -> None: ... + ``` + +=== "Rust" + ```rust + use autonomi::types::{Address, Data, Metadata}; + + pub trait Client { + async fn store_chunk(&self, data: &[u8]) -> Result
; + async fn get_chunk(&self, address: &Address) -> Result>; + async fn create_pointer(&self, target: Address) -> Result; + async fn update_pointer(&self, address: Address, target: Address) -> Result<()>; + } + ``` + +## Further Reading + +- [Data Types Guide](../../guides/data_types.md) +- [Client Modes Guide](../../guides/client_modes.md) +- [Local Network Setup](../../guides/local_network.md) diff --git a/docs/online-documentation/api/autonomi-client/data_types.md b/docs/online-documentation/api/autonomi-client/data_types.md new file mode 100644 index 0000000000..c43c47ca53 --- /dev/null +++ b/docs/online-documentation/api/autonomi-client/data_types.md @@ -0,0 +1,211 @@ +# Data Types Reference + +This page provides detailed information about the core data types used in the Autonomi Client API. + +## Address + +A unique identifier for content in the network. + +=== "Node.js" + ```typescript + interface Address { + readonly bytes: Buffer; + toString(): string; + equals(other: Address): boolean; + } + ``` + +=== "Python" + ```python + class Address: + @property + def bytes(self) -> bytes: ... + def __str__(self) -> str: ... + def __eq__(self, other: Address) -> bool: ... + ``` + +=== "Rust" + ```rust + pub struct Address([u8; 32]); + + impl Address { + pub fn as_bytes(&self) -> &[u8]; + pub fn to_string(&self) -> String; + } + ``` + +## Chunk + +An immutable data block with quantum-secure encryption. + +=== "Node.js" + ```typescript + interface Chunk { + readonly address: Address; + readonly data: Buffer; + readonly size: number; + readonly type: ChunkType; + } + + enum ChunkType { + Data, + Metadata, + Index + } + ``` + +=== "Python" + ```python + class Chunk: + @property + def address(self) -> Address: ... + @property + def data(self) -> bytes: ... + @property + def size(self) -> int: ... + @property + def type(self) -> ChunkType: ... + + class ChunkType(Enum): + DATA = 1 + METADATA = 2 + INDEX = 3 + ``` + +=== "Rust" + ```rust + pub struct Chunk { + pub address: Address, + pub data: Vec, + pub size: usize, + pub type_: ChunkType, + } + + pub enum ChunkType { + Data, + Metadata, + Index, + } + ``` + +## Pointer + +A mutable reference to data in the network. + +=== "Node.js" + ```typescript + interface Pointer { + readonly address: Address; + readonly target: Address; + readonly version: number; + setTarget(target: Address): void; + } + ``` + +=== "Python" + ```python + class Pointer: + @property + def address(self) -> Address: ... + @property + def target(self) -> Address: ... + @property + def version(self) -> int: ... + def set_target(self, target: Address) -> None: ... + ``` + +=== "Rust" + ```rust + pub struct Pointer { + pub address: Address, + pub target: Address, + pub version: u64, + } + + impl Pointer { + pub fn set_target(&mut self, target: Address); + } + ``` + +## LinkedList + +A decentralized DAG structure for ordered data. + +=== "Node.js" + ```typescript + interface LinkedList { + readonly address: Address; + readonly length: number; + append(item: T): void; + get(index: number): T; + toArray(): T[]; + } + ``` + +=== "Python" + ```python + class LinkedList(Generic[T]): + @property + def address(self) -> Address: ... + @property + def length(self) -> int: ... + def append(self, item: T) -> None: ... + def __getitem__(self, index: int) -> T: ... + def to_list(self) -> List[T]: ... + ``` + +=== "Rust" + ```rust + pub struct LinkedList { + pub address: Address, + pub length: usize, + } + + impl LinkedList { + pub fn append(&mut self, item: T); + pub fn get(&self, index: usize) -> Option<&T>; + pub fn to_vec(&self) -> Vec; + } + ``` + +## ScratchPad + +Unstructured data with CRDT properties. + +=== "Node.js" + ```typescript + interface ScratchPad { + readonly address: Address; + readonly type: ContentType; + readonly updateCounter: number; + update(data: Buffer): void; + getData(): Buffer; + } + ``` + +=== "Python" + ```python + class ScratchPad: + @property + def address(self) -> Address: ... + @property + def type(self) -> ContentType: ... + @property + def update_counter(self) -> int: ... + def update(self, data: bytes) -> None: ... + def get_data(self) -> bytes: ... + ``` + +=== "Rust" + ```rust + pub struct ScratchPad { + pub address: Address, + pub type_: ContentType, + pub update_counter: u64, + } + + impl ScratchPad { + pub fn update(&mut self, data: Vec); + pub fn get_data(&self) -> Vec; + } + ``` diff --git a/docs/online-documentation/api/autonomi-client/errors.md b/docs/online-documentation/api/autonomi-client/errors.md new file mode 100644 index 0000000000..965c99eca9 --- /dev/null +++ b/docs/online-documentation/api/autonomi-client/errors.md @@ -0,0 +1,314 @@ +# Error Handling Reference + +This page documents the error types and handling patterns for the Autonomi Client API. + +## Error Types + +### ChunkError + +Errors related to chunk operations. + +=== "Node.js" + ```typescript + class ChunkError extends Error { + static NotFound: typeof ChunkError; + static InvalidSize: typeof ChunkError; + static NetworkError: typeof ChunkError; + static StorageFull: typeof ChunkError; + } + + try { + const chunk = await client.getChunk(address); + } catch (error) { + if (error instanceof ChunkError.NotFound) { + // Handle missing chunk + } else if (error instanceof ChunkError.NetworkError) { + // Handle network issues + } + } + ``` + +=== "Python" + ```python + class ChunkError(Exception): + class NotFound(ChunkError): pass + class InvalidSize(ChunkError): pass + class NetworkError(ChunkError): pass + class StorageFull(ChunkError): pass + + try: + chunk = client.get_chunk(address) + except ChunkError.NotFound: + # Handle missing chunk + pass + except ChunkError.NetworkError as e: + # Handle network issues + pass + ``` + +=== "Rust" + ```rust + pub enum ChunkError { + NotFound, + InvalidSize, + NetworkError(NetworkError), + StorageFull, + } + + match client.get_chunk(address).await { + Ok(chunk) => { /* Process chunk */ } + Err(ChunkError::NotFound) => { /* Handle missing chunk */ } + Err(ChunkError::NetworkError(e)) => { /* Handle network issues */ } + Err(e) => { /* Handle other errors */ } + } + ``` + +### PointerError + +Errors related to pointer operations. + +=== "Node.js" + ```typescript + class PointerError extends Error { + static NotFound: typeof PointerError; + static VersionConflict: typeof PointerError; + static InvalidTarget: typeof PointerError; + } + + try { + await client.updatePointer(address, newTarget); + } catch (error) { + if (error instanceof PointerError.VersionConflict) { + // Handle version conflict + } + } + ``` + +=== "Python" + ```python + class PointerError(Exception): + class NotFound(PointerError): pass + class VersionConflict(PointerError): pass + class InvalidTarget(PointerError): pass + + try: + client.update_pointer(address, new_target) + except PointerError.VersionConflict: + # Handle version conflict + pass + ``` + +=== "Rust" + ```rust + pub enum PointerError { + NotFound, + VersionConflict, + InvalidTarget, + } + + match client.update_pointer(address, new_target).await { + Ok(_) => { /* Success */ } + Err(PointerError::VersionConflict) => { /* Handle conflict */ } + Err(e) => { /* Handle other errors */ } + } + ``` + +### ListError + +Errors related to linked list operations. + +=== "Node.js" + ```typescript + class ListError extends Error { + static NotFound: typeof ListError; + static InvalidIndex: typeof ListError; + static ForkDetected: typeof ListError; + } + + try { + const item = await client.getListItem(address, index); + } catch (error) { + if (error instanceof ListError.InvalidIndex) { + // Handle invalid index + } + } + ``` + +=== "Python" + ```python + class ListError(Exception): + class NotFound(ListError): pass + class InvalidIndex(ListError): pass + class ForkDetected(ListError): pass + + try: + item = client.get_list_item(address, index) + except ListError.InvalidIndex: + # Handle invalid index + pass + ``` + +=== "Rust" + ```rust + pub enum ListError { + NotFound, + InvalidIndex, + ForkDetected, + } + + match client.get_list_item(address, index).await { + Ok(item) => { /* Process item */ } + Err(ListError::InvalidIndex) => { /* Handle invalid index */ } + Err(e) => { /* Handle other errors */ } + } + ``` + +## Error Handling Patterns + +### Retry Logic + +For transient errors like network issues: + +=== "Node.js" + ```typescript + async function withRetry( + operation: () => Promise, + maxRetries = 3, + delay = 1000 + ): Promise { + let lastError: Error; + for (let i = 0; i < maxRetries; i++) { + try { + return await operation(); + } catch (error) { + if (error instanceof ChunkError.NetworkError) { + lastError = error; + await new Promise(resolve => setTimeout(resolve, delay)); + continue; + } + throw error; + } + } + throw lastError; + } + + // Usage + const chunk = await withRetry(() => client.getChunk(address)); + ``` + +=== "Python" + ```python + async def with_retry(operation, max_retries=3, delay=1.0): + last_error = None + for i in range(max_retries): + try: + return await operation() + except ChunkError.NetworkError as e: + last_error = e + await asyncio.sleep(delay) + continue + except Exception as e: + raise e + raise last_error + + # Usage + chunk = await with_retry(lambda: client.get_chunk(address)) + ``` + +=== "Rust" + ```rust + async fn with_retry( + operation: F, + max_retries: u32, + delay: Duration + ) -> Result + where + F: Fn() -> Future>, + E: From, + { + let mut last_error = None; + for_ in 0..max_retries { + match operation().await { + Ok(result) => return Ok(result), + Err(e) => { + if let Some(ChunkError::NetworkError(_)) = e.downcast_ref() { + last_error = Some(e); + tokio::time::sleep(delay).await; + continue; + } + return Err(e); + } + } + } + Err(last_error.unwrap()) + } + + // Usage + let chunk = with_retry(|| client.get_chunk(address), 3, Duration::from_secs(1)).await?; + ``` + +### Error Recovery + +For handling version conflicts in pointers: + +=== "Node.js" + ```typescript + async function updatePointerSafely( + client: Client, + address: Address, + newTarget: Address + ): Promise { + while (true) { + try { + await client.updatePointer(address, newTarget); + break; + } catch (error) { + if (error instanceof PointerError.VersionConflict) { + const current = await client.resolvePointer(address); + if (current.equals(newTarget)) break; + continue; + } + throw error; + } + } + } + ``` + +=== "Python" + ```python + async def update_pointer_safely(client, address, new_target): + while True: + try: + await client.update_pointer(address, new_target) + break + except PointerError.VersionConflict: + current = await client.resolve_pointer(address) + if current == new_target: + break + continue + except Exception as e: + raise e + ``` + +=== "Rust" + ```rust + async fn update_pointer_safely( + client: &Client, + address: Address, + new_target: Address + ) -> Result<()> { + loop { + match client.update_pointer(address, new_target).await { + Ok(_) => break Ok(()), + Err(PointerError::VersionConflict) => { + let current = client.resolve_pointer(address).await?; + if current == new_target { + break Ok(()); + } + continue; + } + Err(e) => break Err(e), + } + } + } + ``` diff --git a/docs/online-documentation/api/blsttc/README.md b/docs/online-documentation/api/blsttc/README.md new file mode 100644 index 0000000000..3f5760a133 --- /dev/null +++ b/docs/online-documentation/api/blsttc/README.md @@ -0,0 +1,258 @@ +# BLS Threshold Crypto API Reference + +BLS Threshold Crypto (blsttc) is a Rust implementation of BLS (Boneh-Lynn-Shacham) threshold signatures with support for both Rust and Python interfaces. + +## Installation + +=== "Python" + ```bash + # Install using uv (recommended) + curl -LsSf | sh + uv pip install blsttc + + # Or using pip + pip install blsttc + ``` + +=== "Rust" + ```toml + # Add to Cargo.toml + [dependencies] + blsttc = "8.0.2" + ``` + +## Basic Usage + +=== "Python" + ```python + from blsttc import SecretKey, PublicKey, Signature + + # Generate a secret key + secret_key = SecretKey.random() + + # Get the corresponding public key + public_key = secret_key.public_key() + + # Sign a message + message = b"Hello, World!" + signature = secret_key.sign(message) + + # Verify the signature + assert public_key.verify(signature, message) + ``` + +=== "Rust" + ```rust + use blsttc::{SecretKey, PublicKey, Signature}; + + // Generate a secret key + let secret_key = SecretKey::random(); + + // Get the corresponding public key + let public_key = secret_key.public_key(); + + // Sign a message + let message = b"Hello, World!"; + let signature = secret_key.sign(message); + + // Verify the signature + assert!(public_key.verify(&signature, message)); + ``` + +## Threshold Signatures + +=== "Python" + ```python + from blsttc import SecretKeySet, PublicKeySet + + # Create a threshold signature scheme + threshold = 3 # Minimum signatures required + total = 5 # Total number of shares + sk_set = SecretKeySet.random(threshold) + + # Get the public key set + pk_set = sk_set.public_keys() + + # Generate secret key shares + secret_shares = [sk_set.secret_key_share(i) for i in range(total)] + + # Sign with individual shares + message = b"Hello, World!" + sig_shares = [share.sign(message) for share in secret_shares] + + # Combine signatures + combined_sig = pk_set.combine_signatures(sig_shares[:threshold]) + + # Verify the combined signature + assert pk_set.public_key().verify(combined_sig, message) + ``` + +=== "Rust" + ```rust + use blsttc::{SecretKeySet, PublicKeySet}; + + // Create a threshold signature scheme + let threshold = 3; // Minimum signatures required + let total = 5; // Total number of shares + let sk_set = SecretKeySet::random(threshold); + + // Get the public key set + let pk_set = sk_set.public_keys(); + + // Generate secret key shares + let secret_shares: Vec<_> = (0..total) + .map(|i| sk_set.secret_key_share(i)) + .collect(); + + // Sign with individual shares + let message = b"Hello, World!"; + let sig_shares: Vec<_> = secret_shares + .iter() + .map(|share| share.sign(message)) + .collect(); + + // Combine signatures + let combined_sig = pk_set.combine_signatures(sig_shares[..threshold].iter())?; + + // Verify the combined signature + assert!(pk_set.public_key().verify(&combined_sig, message)); + ``` + +## Advanced Features + +### Key Generation + +=== "Python" + ```python + from blsttc import SecretKey, Fr + + # Generate from random seed + secret_key = SecretKey.random() + + # Generate from bytes + bytes_data = b"some-32-byte-seed" + secret_key = SecretKey.from_bytes(bytes_data) + + # Generate from field element + fr = Fr.random() + secret_key = SecretKey.from_fr(fr) + ``` + +=== "Rust" + ```rust + use blsttc::{SecretKey, Fr}; + use rand::thread_rng; + + // Generate from random seed + let secret_key = SecretKey::random(); + + // Generate from bytes + let bytes_data = b"some-32-byte-seed"; + let secret_key = SecretKey::from_bytes(bytes_data)?; + + // Generate from field element + let fr = Fr::random(); + let secret_key = SecretKey::from_fr(&fr); + ``` + +### Serialization + +=== "Python" + ```python + # Serialize keys and signatures + sk_bytes = secret_key.to_bytes() + pk_bytes = public_key.to_bytes() + sig_bytes = signature.to_bytes() + + # Deserialize + sk = SecretKey.from_bytes(sk_bytes) + pk = PublicKey.from_bytes(pk_bytes) + sig = Signature.from_bytes(sig_bytes) + ``` + +=== "Rust" + ```rust + // Serialize keys and signatures + let sk_bytes = secret_key.to_bytes(); + let pk_bytes = public_key.to_bytes(); + let sig_bytes = signature.to_bytes(); + + // Deserialize + let sk = SecretKey::from_bytes(&sk_bytes)?; + let pk = PublicKey::from_bytes(&pk_bytes)?; + let sig = Signature::from_bytes(&sig_bytes)?; + ``` + +## Error Handling + +=== "Python" + ```python + try: + # Operations that might fail + sk = SecretKey.from_bytes(invalid_bytes) + except ValueError as e: + print(f"Invalid key bytes: {e}") + + try: + # Signature verification + if not pk.verify(sig, msg): + print("Invalid signature") + except Exception as e: + print(f"Verification error: {e}") + ``` + +=== "Rust" + ```rust + use blsttc::error::Error; + + // Handle key generation errors + match SecretKey::from_bytes(invalid_bytes) { + Ok(sk) => println!("Key generated successfully"), + Err(Error::InvalidBytes) => println!("Invalid key bytes"), + Err(e) => println!("Other error: {}", e), + } + + // Handle signature verification + if !pk.verify(&sig, msg) { + println!("Invalid signature"); + } + ``` + +## Best Practices + +1. **Key Management** + - Securely store private keys + - Use strong random number generation + - Implement key rotation policies + +2. **Threshold Selection** + - Choose appropriate threshold values + - Consider fault tolerance requirements + - Balance security and availability + +3. **Performance** + - Cache public keys when possible + - Batch verify signatures when possible + - Use appropriate buffer sizes + +4. **Security** + - Validate all inputs + - Use secure random number generation + - Implement proper error handling + +## Common Use Cases + +1. **Distributed Key Generation** + - Generate keys for distributed systems + - Share keys among multiple parties + - Implement threshold cryptography + +2. **Signature Aggregation** + - Combine multiple signatures + - Reduce signature size + - Improve verification efficiency + +3. **Consensus Protocols** + - Implement Byzantine fault tolerance + - Create distributed voting systems + - Build secure multiparty computation diff --git a/docs/online-documentation/api/index.md b/docs/online-documentation/api/index.md new file mode 100644 index 0000000000..1c0592f224 --- /dev/null +++ b/docs/online-documentation/api/index.md @@ -0,0 +1,53 @@ +# API Reference Overview + +Autonomi provides several APIs for different aspects of the system: + +## Client API + +The [Autonomi Client API](autonomi-client/README.md) is the core library for interacting with the Autonomi network. It provides: + +- Data storage and retrieval +- Pointer management +- Linked list operations +- File system operations +- Error handling + +## Node API + +The [Ant Node API](ant-node/README.md) allows you to run and manage nodes in the Autonomi network. Features include: + +- Node setup and configuration +- Network participation +- Storage management +- Reward collection +- Event handling + +## Cryptography APIs + +### BLS Threshold Crypto + +The [BLS Threshold Crypto API](blsttc/README.md) implements BLS (Boneh-Lynn-Shacham) threshold signatures, providing: + +- Secret key generation and sharing +- Signature creation and verification +- Threshold signature schemes +- Key aggregation + +### Self Encryption + +The [Self Encryption API](self-encryption/README.md) implements content-based encryption, offering: + +- Data-derived encryption +- Content deduplication +- Parallel processing +- Streaming interface + +## Language Support + +All APIs are available in multiple languages: + +- Python (3.8+) +- Rust (stable) +- Node.js (16+) + +Each API section includes language-specific installation instructions and code examples. diff --git a/docs/online-documentation/api/self-encryption/README.md b/docs/online-documentation/api/self-encryption/README.md new file mode 100644 index 0000000000..023e331a04 --- /dev/null +++ b/docs/online-documentation/api/self-encryption/README.md @@ -0,0 +1,267 @@ +# Self Encryption API Reference + +A file content self-encryptor that provides convergent encryption on file-based data. It produces a `DataMap` type and several chunks of encrypted data. Each chunk is up to 1MB in size and has an index and a name (SHA3-256 hash of the content), allowing chunks to be self-validating. + +## Installation + +=== "Python" + ```bash + pip install self-encryption + ``` + +=== "Rust" + ```toml + [dependencies] + self_encryption = "0.31.0" + ``` + +## Core Concepts + +### DataMap + +Holds the information required to recover the content of the encrypted file, stored as a vector of `ChunkInfo` (list of file's chunk hashes). Only files larger than 3072 bytes (3 * MIN_CHUNK_SIZE) can be self-encrypted. + +### Chunk Sizes + +- `MIN_CHUNK_SIZE`: 1 byte +- `MAX_CHUNK_SIZE`: 1 MiB (before compression) +- `MIN_ENCRYPTABLE_BYTES`: 3 bytes + +## Streaming Operations (Recommended) + +### Streaming File Encryption + +=== "Python" + ```python + from self_encryption import streaming_encrypt_from_file, ChunkStore + from pathlib import Path + from typing import Optional + + # Implement your chunk store + class MyChunkStore(ChunkStore): + def put(self, name: bytes, data: bytes) -> None: + # Store the chunk + pass + + def get(self, name: bytes) -> Optional[bytes]: + # Retrieve the chunk + pass + + # Create chunk store instance + store = MyChunkStore() + + # Encrypt file using streaming + file_path = Path("my_file.txt") + data_map = streaming_encrypt_from_file(file_path, store) + ``` + +=== "Rust" + ```rust + use self_encryption::{streaming_encrypt_from_file, ChunkStore}; + use std::path::Path; + + // Implement your chunk store + struct MyChunkStore { + // Your storage implementation + } + + impl ChunkStore for MyChunkStore { + fn put(&mut self, name: &[u8], data: &[u8]) -> Result<(), Error> { + // Store the chunk + } + + fn get(&self, name: &[u8]) -> Result, Error> { + // Retrieve the chunk + } + } + + // Create chunk store instance + let store = MyChunkStore::new(); + + // Encrypt file using streaming + let file_path = Path::new("my_file.txt"); + let data_map = streaming_encrypt_from_file(file_path, store).await?; + ``` + +### Streaming File Decryption + +=== "Python" + ```python + from self_encryption import streaming_decrypt_from_storage + from pathlib import Path + + # Decrypt to file using streaming + output_path = Path("decrypted_file.txt") + streaming_decrypt_from_storage(data_map, store, output_path) + ``` + +=== "Rust" + ```rust + use self_encryption::streaming_decrypt_from_storage; + use std::path::Path; + + // Decrypt to file using streaming + let output_path = Path::new("decrypted_file.txt"); + streaming_decrypt_from_storage(&data_map, store, output_path).await?; + ``` + +## In-Memory Operations (Small Files) + +### Basic Encryption/Decryption + +=== "Python" + ```python + from self_encryption import encrypt, decrypt + + # Encrypt bytes in memory + data = b"Small data to encrypt" + data_map, encrypted_chunks = encrypt(data) + + # Decrypt using retrieval function + def get_chunk(name: bytes) -> bytes: + # Retrieve chunk by name from your storage + return chunk_data + + decrypted = decrypt(data_map, get_chunk) + ``` + +=== "Rust" + ```rust + use self_encryption::{encrypt, decrypt}; + + // Encrypt bytes in memory + let data = b"Small data to encrypt"; + let (data_map, encrypted_chunks) = encrypt(data)?; + + // Decrypt using retrieval function + let decrypted = decrypt( + &data_map, + |name| { + // Retrieve chunk by name from your storage + Ok(chunk_data) + } + )?; + ``` + +## Chunk Store Implementations + +### In-Memory Store + +=== "Python" + ```python + from self_encryption import ChunkStore + from typing import Dict, Optional + + class MemoryStore(ChunkStore): + def __init__(self): + self.chunks: Dict[bytes, bytes] = {} + + def put(self, name: bytes, data: bytes) -> None: + self.chunks[name] = data + + def get(self, name: bytes) -> Optional[bytes]: + return self.chunks.get(name) + ``` + +=== "Rust" + ```rust + use std::collections::HashMap; + + struct MemoryStore { + chunks: HashMap, Vec>, + } + + impl ChunkStore for MemoryStore { + fn put(&mut self, name: &[u8], data: &[u8]) -> Result<(), Error> { + self.chunks.insert(name.to_vec(), data.to_vec()); + Ok(()) + } + + fn get(&self, name: &[u8]) -> Result, Error> { + self.chunks.get(name) + .cloned() + .ok_or(Error::NoSuchChunk) + } + } + ``` + +### Disk-Based Store + +=== "Python" + ```python + from pathlib import Path + from typing import Optional + import os + + class DiskStore(ChunkStore): + def __init__(self, root_dir: Path): + self.root_dir = root_dir + self.root_dir.mkdir(parents=True, exist_ok=True) + + def put(self, name: bytes, data: bytes) -> None: + path = self.root_dir / name.hex() + path.write_bytes(data) + + def get(self, name: bytes) -> Optional[bytes]: + path = self.root_dir / name.hex() + try: + return path.read_bytes() + except FileNotFoundError: + return None + ``` + +=== "Rust" + ```rust + use std::path::PathBuf; + use std::fs; + + struct DiskStore { + root_dir: PathBuf, + } + + impl ChunkStore for DiskStore { + fn put(&mut self, name: &[u8], data: &[u8]) -> Result<(), Error> { + let path = self.root_dir.join(hex::encode(name)); + fs::write(path, data)?; + Ok(()) + } + + fn get(&self, name: &[u8]) -> Result, Error> { + let path = self.root_dir.join(hex::encode(name)); + fs::read(path).map_err(|_| Error::NoSuchChunk) + } + } + + impl DiskStore { + fn new>(root: P) -> Self { + let root_dir = root.into(); + fs::create_dir_all(&root_dir).expect("Failed to create store directory"); + Self { root_dir } + } + } + ``` + +## Error Handling + +The library provides an `Error` enum for handling various error cases: + +```rust +pub enum Error { + NoSuchChunk, + ChunkTooSmall, + ChunkTooLarge, + InvalidChunkSize, + Io(std::io::Error), + Serialisation(Box), + Compression(std::io::Error), + // ... other variants +} +``` + +## Best Practices + +1. Use streaming operations (`streaming_encrypt_from_file` and `streaming_decrypt_from_storage`) for large files +2. Use basic `encrypt`/`decrypt` functions for small in-memory data +3. Implement proper error handling for chunk store operations +4. Verify chunks using their content hash when retrieving +5. Use parallel operations when available for better performance diff --git a/docs/online-documentation/getting-started/installation.md b/docs/online-documentation/getting-started/installation.md new file mode 100644 index 0000000000..b17130137a --- /dev/null +++ b/docs/online-documentation/getting-started/installation.md @@ -0,0 +1,110 @@ +# Installation Guide + +## Prerequisites + +- Rust (latest stable) +- Python 3.8 or higher +- Node.js 16 or higher + +## API-specific Installation + +Choose the APIs you need for your project: + +### Autonomi Client + +=== "Node.js" + ```bash + # Note: Package not yet published to npm + # Clone the repository and build from source + git clone https://github.com/dirvine/autonomi.git + cd autonomi + npm install + ``` + +=== "Python" + ```bash + pip install autonomi + ``` + +=== "Rust" + ```toml + # Add to Cargo.toml: + [dependencies] + autonomi = "0.3.1" + ``` + +### Ant Node + +=== "Python" + ```bash + pip install antnode + ``` + +=== "Rust" + ```toml + [dependencies] + ant-node = "0.3.2" + ``` + +### BLS Threshold Crypto + +=== "Python" + ```bash + pip install blsttc + ``` + +=== "Rust" + ```toml + [dependencies] + blsttc = "8.0.2" + ``` + +### Self Encryption + +=== "Python" + ```bash + pip install self-encryption + ``` + +=== "Rust" + ```toml + [dependencies] + self_encryption = "0.28.0" + ``` + +## Verifying Installation + +Test your installation by running a simple client initialization: + +=== "Node.js" + ```typescript + import { Client } from 'autonomi'; + + const client = await Client.initReadOnly(); + console.log('Client initialized successfully'); + ``` + +=== "Python" + ```python + from autonomi import Client + + client = Client.init_read_only() + print('Client initialized successfully') + ``` + +=== "Rust" + ```rust + use autonomi::Client; + + let client = Client::new_local().await?; + println!("Client initialized successfully"); + ``` + +## Next Steps + +- API References: + - [Autonomi Client](../api/autonomi-client/README.md) + - [Ant Node](../api/ant-node/README.md) + - [BLS Threshold Crypto](../api/blsttc/README.md) + - [Self Encryption](../api/self-encryption/README.md) +- [Local Network Setup](../guides/local_network.md) diff --git a/docs/online-documentation/guides/client_modes.md b/docs/online-documentation/guides/client_modes.md new file mode 100644 index 0000000000..6cf3360727 --- /dev/null +++ b/docs/online-documentation/guides/client_modes.md @@ -0,0 +1,180 @@ +# Client Modes Guide + +This guide explains how to use Autonomi's client modes to browse the network (read-only) and optionally upgrade to write capabilities. + +## Overview + +Autonomi clients can operate in two modes: + +1. **Read-Only Mode**: Browse and read data from the network without requiring a wallet +2. **Read-Write Mode**: Full access to both read and write operations, requires a wallet + +## Read-Only Client + +A read-only client allows you to browse and read data from the network without needing a wallet or making payments. + +### Rust + +```rust +use autonomi::Client; + +// Initialize a read-only client +let client = Client::init_read_only().await?; + +// Verify it's read-only +assert!(!client.can_write()); +assert!(client.wallet().is_none()); + +// Read operations work normally +let data = client.get_bytes(address).await?; +let file = client.get_file(file_map, "output.txt").await?; +``` + +### TypeScript/JavaScript + +```typescript +import { Client } from '@autonomi/client'; + +// Initialize a read-only client +const client = await Client.connect({ + readOnly: true, + peers: ['/ip4/127.0.0.1/tcp/12000'] +}); + +// Read operations +const data = await client.dataGetPublic(address); +const list = await client.linkedListGet(listAddress); +``` + +### Python + +```python +from autonomi import Client + +# Initialize a read-only client +client = Client.new() + +# Read operations +data = client.get_bytes("safe://example_address") +file = client.get_file(file_map, "output.txt") +``` + +## Upgrading to Read-Write Mode + +You can upgrade a read-only client to read-write mode by adding a wallet. This enables write operations like storing data or updating linked lists. + +### Rust + +```rust +use autonomi::{Client, EvmWallet}; + +// Start with a read-only client +let mut client = Client::init_read_only().await?; + +// Get a wallet (e.g., from a private key or create new) +let wallet = EvmWallet::from_private_key(private_key)?; + +// Upgrade to read-write mode +client.upgrade_to_read_write(wallet)?; + +// Now write operations are available +let address = client.store_bytes(data).await?; +``` + +### TypeScript/JavaScript + +```typescript +import { Client } from '@autonomi/client'; + +// Start with a read-only client +const client = await Client.connect({ + readOnly: true +}); + +// Upgrade with a wallet +await client.upgradeToReadWrite({ + type: 'wallet', + wallet: 'your_wallet_address' +}); + +// Now you can perform write operations +const address = await client.dataPutPublic( + Buffer.from('Hello World'), + { type: 'wallet', wallet: client.wallet } +); +``` + +### Python + +```python +from autonomi import Client, Wallet + +# Start with a read-only client +client = Client.new() + +# Create or import a wallet +wallet = Wallet.from_private_key("your_private_key") + +# Upgrade to read-write mode +client.upgrade_to_read_write(wallet) + +# Now write operations are available +address = client.store_bytes(b"Hello World") +``` + +## Write Operations + +The following operations require a wallet (read-write mode): + +- Storing public data (`dataPutPublic`) +- Creating/updating linked lists (`linkedListPut`) +- Setting pointers (`pointerPut`) +- Writing to vaults (`writeBytesToVault`) +- Updating user data (`putUserDataToVault`) + +Attempting these operations in read-only mode will result in an error. + +## Best Practices + +1. **Start Read-Only**: Begin with a read-only client if you only need to read data. This is simpler and more secure since no wallet is needed. + +2. **Lazy Wallet Loading**: Only upgrade to read-write mode when you actually need to perform write operations. + +3. **Error Handling**: Always handle potential errors when upgrading modes or performing write operations: + +```typescript +try { + await client.upgradeToReadWrite(wallet); + await client.dataPutPublic(data, payment); +} catch (error) { + if (error.code === 'NO_WALLET') { + console.error('Write operation attempted without wallet'); + } else if (error.code === 'ALREADY_READ_WRITE') { + console.error('Client is already in read-write mode'); + } +} +``` + +4. **Check Capabilities**: Use the provided methods to check client capabilities: + +```rust +if client.can_write() { + // Perform write operation +} else { + // Handle read-only state +} +``` + +## Common Issues + +1. **Attempting Write Operations in Read-Only Mode** + - Error: `NO_WALLET` or `WriteAccessRequired` + - Solution: Upgrade to read-write mode by adding a wallet + +2. **Multiple Upgrade Attempts** + - Error: `ALREADY_READ_WRITE` + - Solution: Check client mode before attempting upgrade + +3. **Invalid Wallet** + - Error: `InvalidWallet` or `WalletError` + - Solution: Ensure wallet is properly initialized with valid credentials diff --git a/docs/online-documentation/guides/data_storage.md b/docs/online-documentation/guides/data_storage.md new file mode 100644 index 0000000000..4d8f90f744 --- /dev/null +++ b/docs/online-documentation/guides/data_storage.md @@ -0,0 +1,255 @@ +# Data Storage Guide + +This guide explains how Autonomi handles data storage, including self-encryption and scratchpad features. + +## Self-Encryption + +Self-encryption is a core feature that provides secure data storage by splitting and encrypting data into chunks. + +### How It Works + +1. Data is split into chunks +2. Each chunk is encrypted +3. A data map is created to track the chunks +4. Additional encryption layers are added for larger files + +### Usage Examples + +=== "Node.js" + ```typescript + import { Client } from '@autonomi/client'; + + async function storeEncryptedData(data: Uint8Array) { + const client = new Client(); + + // Data is automatically self-encrypted when stored + const address = await client.data_put_public(data); + console.log(`Data stored at: ${address}`); + + // Retrieve and decrypt data + const retrieved = await client.data_get_public(address); + console.log('Data retrieved successfully'); + } + ``` + +=== "Python" + ```python + from autonomi import Client + + async def store_encrypted_data(data: bytes): + client = Client() + + # Data is automatically self-encrypted when stored + address = await client.data_put_public(data) + print(f"Data stored at: {address}") + + # Retrieve and decrypt data + retrieved = await client.data_get_public(address) + print("Data retrieved successfully") + ``` + +=== "Rust" + ```rust + use autonomi::{Client, Bytes, Result}; + + async fn store_encrypted_data(data: Bytes) -> Result<()> { + let client = Client::new()?; + + // Data is automatically self-encrypted when stored + let address = client.data_put_public(data).await?; + println!("Data stored at: {}", address); + + // Retrieve and decrypt data + let retrieved = client.data_get_public(&address).await?; + println!("Data retrieved successfully"); + + Ok(()) + } + ``` + +## Scratchpad + +Scratchpad provides a mutable storage location for encrypted data with versioning support. + +### Features + +- Mutable data storage +- Version tracking with monotonic counter +- Owner-based access control +- Data encryption +- Signature verification + +### Usage Examples + +=== "Node.js" + ```typescript + import { Client, Scratchpad } from '@autonomi/client'; + + async function useScratchpad() { + const client = new Client(); + const secretKey = await client.generate_secret_key(); + + // Create or get existing scratchpad + const [scratchpad, isNew] = await client.get_or_create_scratchpad( + secretKey, + 42 // content type + ); + + // Update scratchpad data + const data = new TextEncoder().encode('Hello World'); + await client.update_scratchpad(scratchpad, data, secretKey); + + // Read scratchpad data + const retrieved = await client.get_scratchpad(scratchpad.address); + const decrypted = await client.decrypt_scratchpad(retrieved, secretKey); + console.log(new TextDecoder().decode(decrypted)); + } + ``` + +=== "Python" + ```python + from autonomi import Client, Scratchpad + + async def use_scratchpad(): + client = Client() + secret_key = client.generate_secret_key() + + # Create or get existing scratchpad + scratchpad, is_new = await client.get_or_create_scratchpad( + secret_key, + 42 # content type + ) + + # Update scratchpad data + data = b"Hello World" + await client.update_scratchpad(scratchpad, data, secret_key) + + # Read scratchpad data + retrieved = await client.get_scratchpad(scratchpad.address) + decrypted = await client.decrypt_scratchpad(retrieved, secret_key) + print(decrypted.decode()) + ``` + +=== "Rust" + ```rust + use autonomi::{Client, Scratchpad, SecretKey, Bytes, Result}; + + async fn use_scratchpad() -> Result<()> { + let client = Client::new()?; + let secret_key = SecretKey::random(); + + // Create or get existing scratchpad + let (mut scratchpad, is_new) = client + .get_or_create_scratchpad(&secret_key, 42) + .await?; + + // Update scratchpad data + let data = Bytes::from("Hello World"); + scratchpad.update_and_sign(data, &secret_key); + + // Store updated scratchpad + client.put_scratchpad(&scratchpad).await?; + + // Read scratchpad data + let retrieved = client.get_scratchpad(scratchpad.address()).await?; + let decrypted = retrieved.decrypt_data(&secret_key)?; + println!("Data: {}", String::from_utf8_lossy(&decrypted)); + + Ok(()) + } + ``` + +### Best Practices + +1. **Version Management** + - Always check the counter before updates + - Handle version conflicts appropriately + - Use monotonic counters for ordering + +2. **Security** + - Keep secret keys secure + - Verify signatures before trusting data + - Always encrypt sensitive data + +3. **Error Handling** + - Handle decryption failures gracefully + - Implement proper retry logic for network operations + - Validate data before storage + +4. **Performance** + - Cache frequently accessed data + - Batch updates when possible + - Monitor storage size + +## Implementation Details + +### Self-Encryption Process + +1. **Data Splitting** + + ```rust + // Internal process when storing data + let (data_map, chunks) = self_encryption::encrypt(data)?; + let (data_map_chunk, additional_chunks) = pack_data_map(data_map)?; + ``` + +2. **Chunk Management** + - Each chunk is stored separately + - Chunks are encrypted individually + - Data maps track chunk locations + +### Scratchpad Structure + +```rust +pub struct Scratchpad { + // Network address + address: ScratchpadAddress, + // Data type identifier + data_encoding: u64, + // Encrypted content + encrypted_data: Bytes, + // Version counter + counter: u64, + // Owner's signature + signature: Option, +} +``` + +## Advanced Topics + +### Custom Data Types + +You can use scratchpads to store any custom data type by implementing proper serialization: + +```rust +#[derive(Serialize, Deserialize)] +struct CustomData { + field1: String, + field2: u64, +} + +// Serialize before storing +let custom_data = CustomData { + field1: "test".into(), + field2: 42, +}; +let bytes = serde_json::to_vec(&custom_data)?; +scratchpad.update_and_sign(Bytes::from(bytes), &secret_key); +``` + +### Batch Operations + +For better performance when dealing with multiple data items: + +```rust +async fn batch_store(items: Vec) -> Result> { + let mut addresses = Vec::new(); + for item in items { + let (data_map_chunk, chunks) = encrypt(item)?; + // Store chunks in parallel + futures::future::join_all(chunks.iter().map(|c| store_chunk(c))).await; + addresses.push(data_map_chunk.address()); + } + Ok(addresses) +} +``` diff --git a/docs/online-documentation/guides/data_types.md b/docs/online-documentation/guides/data_types.md new file mode 100644 index 0000000000..25810a307a --- /dev/null +++ b/docs/online-documentation/guides/data_types.md @@ -0,0 +1,345 @@ +# Data Types Guide + +This guide explains the fundamental data types in Autonomi and how they can be used to build higher-level abstractions like files and directories. + +## Fundamental Data Types + +Autonomi provides four fundamental data types that serve as building blocks for all network operations. Each type is designed for specific use cases and together they provide a complete system for decentralized data management. + +### 1. Chunk + +Chunks are the foundation of secure data storage in Autonomi, primarily used as the output of self-encrypting files. This provides quantum-secure encryption for data at rest. + +```rust +// Store raw bytes as a chunk +let data = b"Hello, World!"; +let chunk_address = client.store_chunk(data).await?; + +// Retrieve chunk data +let retrieved = client.get_chunk(chunk_address).await?; +assert_eq!(data, retrieved); +``` + +Key characteristics: +- Quantum-secure encryption through self-encryption +- Immutable content +- Content-addressed (address is derived from data) +- Size-limited (maximum chunk size) +- Efficient for small to medium-sized data + +#### Self-Encryption Process +1. Data is split into fixed-size sections +2. Each section is encrypted using data from other sections +3. Results in multiple encrypted chunks +4. Original data can only be recovered with all chunks + +### 2. Pointer + +Pointers provide a fixed network address that can reference any other data type, including other pointers. They enable mutable data structures while maintaining stable addresses. + +```rust +// Create a pointer to some data +let pointer = client.create_pointer(target_address).await?; + +// Update pointer target +client.update_pointer(pointer.address(), new_target_address).await?; + +// Resolve pointer to get current target +let target = client.resolve_pointer(pointer.address()).await?; + +// Chain pointers for indirection +let pointer_to_pointer = client.create_pointer(pointer.address()).await?; +``` + +Key characteristics: +- Fixed network address +- Mutable reference capability +- Single owner (controlled by secret key) +- Version tracking with monotonic counter +- Atomic updates +- Support for pointer chains and indirection + +#### Common Use Cases +1. **Mutable Data References** + ```rust + // Update data while maintaining same address + let pointer = client.create_pointer(initial_data).await?; + client.update_pointer(pointer.address(), updated_data).await?; + ``` + +2. **Latest Version Publishing** + ```rust + // Point to latest version while maintaining history + let history = client.create_linked_list().await?; + let latest = client.create_pointer(history.address()).await?; + ``` + +3. **Indirection and Redirection** + ```rust + // Create chain of pointers for flexible data management + let data_pointer = client.create_pointer(data).await?; + let redirect_pointer = client.create_pointer(data_pointer.address()).await?; + ``` + +### 3. LinkedList + +LinkedLists in Autonomi are powerful structures that can form transaction chains or decentralized Directed Acyclic Graphs (DAGs) on the network. They provide both historical tracking and CRDT-like properties. + +```rust +// Create a new linked list +let list = client.create_linked_list().await?; + +// Append items to create history +client.append_to_list(list.address(), item1).await?; +client.append_to_list(list.address(), item2).await?; + +// Read list contents including history +let items = client.get_list(list.address()).await?; + +// Check for forks +let forks = client.detect_forks(list.address()).await?; +``` + +Key characteristics: +- Decentralized DAG structure +- Fork detection and handling +- Transaction chain support +- CRDT-like conflict resolution +- Version history tracking +- Support for value transfer (cryptocurrency-like) + +#### DAG Properties +1. **Fork Detection** + ```rust + // Detect and handle forks in the list + match client.detect_forks(list.address()).await? { + Fork::None => proceed_with_updates(), + Fork::Detected(branches) => resolve_conflict(branches), + } + ``` + +2. **Transaction Chains** + ```rust + // Create a transaction chain + let transaction = Transaction { + previous: Some(last_tx_hash), + amount: 100, + recipient: address, + }; + client.append_to_list(chain.address(), transaction).await?; + ``` + +3. **History Tracking** + ```rust + // Get full history of changes + let history = client.get_list_history(list.address()).await?; + for entry in history { + println!("Version {}: {:?}", entry.version, entry.data); + } + ``` + +### 4. ScratchPad + +ScratchPad provides a flexible, unstructured data storage mechanism with CRDT properties through counter-based versioning. It's ideal for user account data, application configurations, and other frequently updated small data packets. + +```rust +// Create a scratchpad for user settings +let pad = client.create_scratchpad(ContentType::UserSettings).await?; + +// Update with encrypted data +let encrypted = encrypt_aes(settings_data, user_key)?; +client.update_scratchpad(pad.address(), encrypted).await?; + +// Read and decrypt current data +let encrypted = client.get_scratchpad(pad.address()).await?; +let settings = decrypt_aes(encrypted, user_key)?; +``` + +Key characteristics: +- Unstructured data storage +- Counter-based CRDT for conflict resolution +- Type-tagged content +- Support for user-managed encryption +- Efficient for frequent updates +- Ideal for small data packets + +#### Security Considerations + +1. **Encryption** + ```rust + // Example of AES encryption for scratchpad data + let key = generate_aes_key(); + let encrypted = aes_encrypt(data, key)?; + client.update_scratchpad(pad.address(), encrypted).await?; + ``` + +2. **Access Control** + ```rust + // Create encrypted scratchpad with access control + let (public_key, private_key) = generate_keypair(); + let encrypted_key = encrypt_with_public_key(aes_key, public_key); + let metadata = ScratchpadMetadata { + encrypted_key, + allowed_users: vec![public_key], + }; + client.create_scratchpad_with_access(metadata).await?; + ``` + +#### Common Applications + +1. **User Profiles** + ```rust + // Store encrypted user profile + let profile = UserProfile { name, settings }; + let encrypted = encrypt_profile(profile, user_key); + client.update_scratchpad(profile_pad, encrypted).await?; + ``` + +2. **Application State** + ```rust + // Maintain application configuration + let config = AppConfig { preferences, state }; + let pad = client.get_or_create_config_pad().await?; + client.update_scratchpad(pad, config).await?; + ``` + +3. **Temporary Storage** + ```rust + // Use as temporary workspace + let workspace = client.create_scratchpad(ContentType::Workspace).await?; + client.update_scratchpad(workspace, working_data).await?; + ``` + +## Higher-Level Abstractions + +These fundamental types can be combined to create higher-level data structures: + +### File System + +The Autonomi file system is built on top of these primitives: + +```rust +// Create a directory +let dir = client.create_directory("my_folder").await?; + +// Create a file +let file = client.create_file("example.txt", content).await?; + +// Add file to directory +client.add_to_directory(dir.address(), file.address()).await?; + +// List directory contents +let entries = client.list_directory(dir.address()).await?; +``` + +#### Files + +Files are implemented using a combination of chunks and pointers: + +- Large files are split into chunks +- File metadata stored in pointer +- Content addressing for deduplication + +```rust +// Store a large file +let file_map = client.store_file("large_file.dat").await?; + +// Read file contents +client.get_file(file_map, "output.dat").await?; +``` + +#### Directories + +Directories use linked lists and pointers to maintain a mutable collection of entries: + +- LinkedList stores directory entries +- Pointer maintains current directory state +- Hierarchical structure support + +```rust +// Create nested directory structure +let root = client.create_directory("/").await?; +let docs = client.create_directory("docs").await?; +client.add_to_directory(root.address(), docs.address()).await?; + +// List recursively +let tree = client.list_recursive(root.address()).await?; +``` + +## Common Patterns + +### Data Organization + +1. **Static Content** + - Use chunks for immutable data + - Content addressing enables deduplication + - Efficient for read-heavy workloads + +2. **Mutable References** + - Use pointers for updateable references + - Maintain stable addresses + - Version tracking built-in + +3. **Collections** + - Use linked lists for ordered data + - Efficient for append operations + - Good for logs and sequences + +4. **Temporary Storage** + - Use scratchpads for working data + - Frequent updates supported + - Type-tagged content + +### Best Practices + +1. **Choose the Right Type** + - Chunks for immutable data + - Pointers for mutable references + - LinkedLists for collections + - ScratchPads for temporary storage + +2. **Efficient Data Structures** + + ```rust + // Bad: Using chunks for frequently changing data + let chunk = client.store_chunk(changing_data).await?; + + // Good: Using scratchpad for frequently changing data + let pad = client.create_scratchpad(content_type).await?; + client.update_scratchpad(pad.address(), changing_data).await?; + ``` + +3. **Version Management** + + ```rust + // Track versions with pointers + let versions = Vec::new(); + versions.push(pointer.version()); + client.update_pointer(pointer.address(), new_data).await?; + versions.push(pointer.version()); + ``` + +4. **Error Handling** + + ```rust + match client.get_chunk(address).await { + Ok(data) => process_data(data), + Err(ChunkError::NotFound) => handle_missing_chunk(), + Err(ChunkError::InvalidSize) => handle_size_error(), + Err(e) => handle_other_error(e), + } + ``` + +## Common Issues + +1. **Size Limitations** + - Chunk size limits + - Solution: Split large data across multiple chunks + +2. **Update Conflicts** + - Concurrent pointer updates + - Solution: Use version checking + +3. **Performance** + - LinkedList traversal costs + - Solution: Use appropriate data structures for access patterns diff --git a/docs/online-documentation/guides/evm_integration.md b/docs/online-documentation/guides/evm_integration.md new file mode 100644 index 0000000000..00564682ae --- /dev/null +++ b/docs/online-documentation/guides/evm_integration.md @@ -0,0 +1,49 @@ +# EVM Integration Guide + +This guide explains how to integrate Autonomi with EVM-compatible networks for testing and development. + +## Supported Networks + +- Local Hardhat network +- Sepolia testnet +- Goerli testnet +- Custom EVM networks + +## Setting Up Test Networks + +### Local Hardhat Network + +```bash +npx hardhat node +``` + +### Connecting to Test Networks + +```typescript +import { EvmNetwork } from '@autonomi/client'; + +const network = new EvmNetwork({ + chainId: 31337, // Local hardhat network + rpcUrl: 'http://127.0.0.1:8545' +}); +``` + +## Deploying Test Contracts + +1. Compile contracts +2. Deploy using Hardhat +3. Interact with contracts + +## Testing with Different Networks + +- Network configuration +- Gas settings +- Contract deployment +- Transaction handling + +## Best Practices + +- Error handling +- Gas optimization +- Security considerations +- Testing strategies diff --git a/docs/online-documentation/guides/local_development.md b/docs/online-documentation/guides/local_development.md new file mode 100644 index 0000000000..dacdb61022 --- /dev/null +++ b/docs/online-documentation/guides/local_development.md @@ -0,0 +1,132 @@ +# Local Development Environment + +This guide will help you set up a local development environment for building applications with Autonomi. We'll use a script that sets up a local network with all the necessary components for development and testing. + +## Prerequisites + +- Rust toolchain installed +- Git repository cloned +- Basic understanding of terminal/command line + +## Setup Script + +Save the following script as `start-local-network.sh` in your project root: + +```bash +#!/bin/bash +set -e + +# Configuration +NODE_DATA_DIR="$HOME/Library/Application Support/autonomi/node" +CLIENT_DATA_DIR="$HOME/Library/Application Support/autonomi/client" +EVM_PORT=4343 +EVM_RPC_URL="http://localhost:8545" +WALLET_ADDRESS="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +TOKEN_ADDRESS="0x5FbDB2315678afecb367f032d93F642f64180aa3" +LOG_LEVEL="info" +NODE_PORT=5000 + +# ... (rest of the script content) ... +``` + +Make the script executable: + +```bash +chmod +x start-local-network.sh +``` + +## Using the Development Environment + +1. Start the local network: + + ```bash + ./start-local-network.sh + ``` + +2. The script will: + - Build all necessary components (ant-node, evm-testnet, ant CLI) + - Start a local EVM testnet + - Start a local Autonomi node + - Set up the development environment + +3. Once running, you'll see information about: + - Network endpoints + - Environment variables + - Example commands + +## Environment Variables + +The following environment variables should be set for your development environment: + +```bash +export ANT_PEERS=/ip4/127.0.0.1/udp/5000/quic-v1 +export ANT_LOG=info +export CLIENT_DATA_PATH=$HOME/Library/Application Support/autonomi/client +``` + +## Example Usage + +### File Operations + +Upload a file: + +```bash +./target/debug/ant file upload path/to/file +``` + +Download a file: + +```bash +./target/debug/ant file download +``` + +### Node Operations + +Check node status: + +```bash +./target/debug/ant node status +``` + +Get wallet balance: + +```bash +./target/debug/ant wallet balance +``` + +## Development Tips + +1. **Local Testing**: The local network is perfect for testing your applications without affecting the main network. + +2. **Quick Iterations**: Changes to your application can be tested immediately without waiting for network confirmations. + +3. **Clean State**: Each time you start the network, it begins with a clean state, making it ideal for testing different scenarios. + +4. **Debugging**: The local environment provides detailed logs and quick feedback for debugging. + +## Customization + +You can customize the development environment by modifying the configuration variables at the top of the script: + +- `NODE_PORT`: Change the port the node listens on +- `LOG_LEVEL`: Adjust logging verbosity ("trace", "debug", "info", "warn", "error") +- `EVM_PORT`: Change the EVM testnet port +- Other settings as needed + +## Troubleshooting + +1. **Port Conflicts**: If you see port-in-use errors, modify the `NODE_PORT` or `EVM_PORT` in the script. + +2. **Process Cleanup**: If the script fails to start, ensure no old processes are running: + + ```bash + pkill -f "antnode" + pkill -f "evm-testnet" + ``` + +3. **Data Cleanup**: To start completely fresh, remove the data directories: + + ```bash + rm -rf "$HOME/Library/Application Support/autonomi/node" + rm -rf "$HOME/Library/Application Support/autonomi/client" + ``` diff --git a/docs/online-documentation/guides/local_network.md b/docs/online-documentation/guides/local_network.md new file mode 100644 index 0000000000..7ffa2291c2 --- /dev/null +++ b/docs/online-documentation/guides/local_network.md @@ -0,0 +1,302 @@ +# Local Network Setup Guide + +This guide explains how to set up and run a local Autonomi network for development and testing purposes. + +## Prerequisites + +- Rust toolchain (with `cargo` installed) +- Git (for cloning the repository) + +That's it! Everything else needed will be built from source. + +## Quick Start + +1. Clone the repository: + +```bash +git clone https://github.com/dirvine/autonomi +cd autonomi +``` + +2. Start the local network: + +```bash +./test-local.sh +``` + +This script will: + +- Build all necessary components +- Start a local EVM testnet +- Start a local Autonomi node +- Set up the development environment + +## Network Components + +The local network consists of: + +- An Autonomi node running in local mode +- A local EVM test network with pre-funded accounts +- Test wallets for development + +## Testing with EVM Networks + +The local EVM network provides a complete testing environment for blockchain interactions: + +### Pre-deployed Contracts + +The following contracts are automatically deployed: + +- Payment Vault Contract (`PaymentVaultNoProxy`) + - Handles data storage payments + - Manages token approvals and transfers + - Verifies payment proofs +- Test Token Contract (`TestToken`) + - ERC20 token for testing payments + - Pre-minted supply for test accounts + - Automatic approval for test wallets + +### Test Accounts + +Several accounts are pre-funded and ready to use: + +``` +Primary Test Account: +Address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +Balance: 10000 TEST tokens + +Secondary Test Account: +Address: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 +Private Key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d +Balance: 1000 TEST tokens +``` + +### RPC Endpoint + +The local EVM network exposes an RPC endpoint at `http://localhost:8545` with: + +- Full JSON-RPC API support +- WebSocket subscriptions +- Low block time (1 second) +- Zero gas costs +- Instant transaction confirmations + +### Interacting with the Network + +#### JavaScript/TypeScript + +```typescript +import { ethers } from 'ethers'; + +// Connect to local network +const provider = new ethers.JsonRpcProvider('http://localhost:8545'); +const wallet = new ethers.Wallet(PRIVATE_KEY, provider); + +// Get contract instances +const paymentVault = new ethers.Contract( + PAYMENT_VAULT_ADDRESS, + PAYMENT_VAULT_ABI, + wallet +); + +// Interact with contracts +await paymentVault.getQuote([metrics]); +await paymentVault.payForQuotes(payments); +``` + +#### Python + +```python +from web3 import Web3 +from eth_account import Account + +# Connect to local network +w3 = Web3(Web3.HTTPProvider('http://localhost:8545')) +account = Account.from_key(PRIVATE_KEY) + +# Get contract instances +payment_vault = w3.eth.contract( + address=PAYMENT_VAULT_ADDRESS, + abi=PAYMENT_VAULT_ABI +) + +# Interact with contracts +payment_vault.functions.getQuote([metrics]).call() +payment_vault.functions.payForQuotes(payments).transact() +``` + +#### Rust + +```rust +use ethers::prelude::*; + +// Connect to local network +let provider = Provider::::try_from("http://localhost:8545")?; +let wallet = LocalWallet::from_bytes(&PRIVATE_KEY)?; +let client = SignerMiddleware::new(provider, wallet); + +// Get contract instances +let payment_vault = PaymentVault::new( + PAYMENT_VAULT_ADDRESS, + Arc::new(client) +); + +// Interact with contracts +payment_vault.get_quote(metrics).call().await?; +payment_vault.pay_for_quotes(payments).send().await?; +``` + +## Environment Variables + +The following environment variables are set up automatically: + +- `ANT_PEERS` - Local node endpoint +- `ANT_LOG` - Logging level +- `CLIENT_DATA_PATH` - Client data directory + +## Monitoring and Debugging + +### Logging + +#### Node Logs + +The Autonomi node generates detailed logs that can be controlled via `RUST_LOG`: + +```bash +# Trace level for maximum detail +RUST_LOG=trace ./test-local.sh + +# Focus on specific modules +RUST_LOG=autonomi=debug,ant_node=trace ./test-local.sh + +# Log locations: +- Node logs: $NODE_DATA_DIR/node.log +- EVM logs: $NODE_DATA_DIR/evm.log +``` + +#### Log Levels + +- `error`: Critical issues that need immediate attention +- `warn`: Important events that aren't failures +- `info`: General operational information +- `debug`: Detailed information for debugging +- `trace`: Very detailed protocol-level information + +#### Following Logs + +```bash +# Follow node logs +tail -f "$NODE_DATA_DIR/node.log" + +# Follow EVM logs +tail -f "$NODE_DATA_DIR/evm.log" + +# Filter for specific events +tail -f "$NODE_DATA_DIR/node.log" | grep "payment" +``` + +### Debugging + +#### Node Debugging + +Using `rust-lldb`: + +```bash +# Start node with debugger +rust-lldb target/debug/antnode -- --features test + +# Common commands: +b autonomi::client::payment::pay # Set breakpoint +r # Run +bt # Backtrace +p variable # Print variable +c # Continue +``` + +Using `rust-gdb`: + +```bash +# Start node with debugger +rust-gdb target/debug/antnode -- --features test + +# Common commands: +break autonomi::client::payment::pay # Set breakpoint +run # Run +backtrace # Show backtrace +print variable # Examine variable +continue # Continue execution +``` + +#### Network Monitoring + +Monitor network activity: + +```bash +# Watch network connections +netstat -an | grep 5000 # Default node port + +# Monitor network traffic +sudo tcpdump -i lo0 port 5000 + +# Check EVM network +curl -X POST -H "Content-Type: application/json" \ + --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ + http://localhost:8545 +``` + +#### Contract Debugging + +Debug contract interactions: + +```bash +# Get payment vault state +cast call $PAYMENT_VAULT_ADDRESS \ + "payments(bytes32)" \ + $QUOTE_HASH \ + --rpc-url http://localhost:8545 + +# Watch for payment events +cast events $PAYMENT_VAULT_ADDRESS \ + --rpc-url http://localhost:8545 +``` + +## Common Issues and Solutions + +### Port Conflicts + +If you see port-in-use errors: + +1. Check if another instance is running +2. Use different ports in the script +3. Kill existing processes if needed + +### Build Issues + +1. Make sure Rust toolchain is up to date +2. Clean and rebuild: `cargo clean && cargo build` +3. Check for missing dependencies + +### Network Issues + +1. Verify the node is running +2. Check log output for errors +3. Ensure EVM testnet is accessible + +## Advanced Usage + +### Custom Configuration + +You can modify the test script to: + +- Change ports +- Adjust logging levels +- Configure node parameters + +### Multiple Nodes + +To run multiple nodes: + +1. Copy the script +2. Modify ports and directories +3. Run each instance separately diff --git a/docs/online-documentation/guides/payments.md b/docs/online-documentation/guides/payments.md new file mode 100644 index 0000000000..bf9b6fbb55 --- /dev/null +++ b/docs/online-documentation/guides/payments.md @@ -0,0 +1,277 @@ +# Payments Guide + +This guide explains how payments work in Autonomi, particularly for put operations that store data on the network. + +## Overview + +When storing data on the Autonomi network, you need to pay for the storage space. Payments are made using EVM-compatible tokens through a smart contract system. There are two ways to handle payments: + +1. Direct payment using an EVM wallet +2. Pre-paid operations using a receipt + +## Payment Options + +### Using an EVM Wallet + +The simplest way to pay for put operations is to use an EVM wallet: + +```python +# Python +from autonomi import Client, PaymentOption +from autonomi.evm import EvmWallet + +# Initialize client +client = Client() + +# Create or load a wallet +wallet = EvmWallet.create() # or load from private key +payment = PaymentOption.from_wallet(wallet) + +# Put data with wallet payment +data = b"Hello, World!" +address = client.data_put_public(data, payment) +``` + +```typescript +// Node.js +import { Client, PaymentOption } from '@autonomi/client'; +import { EvmWallet } from '@autonomi/evm'; + +// Initialize client +const client = new Client(); + +// Create or load a wallet +const wallet = EvmWallet.create(); // or load from private key +const payment = PaymentOption.fromWallet(wallet); + +// Put data with wallet payment +const data = Buffer.from("Hello, World!"); +const address = await client.dataPutPublic(data, payment); +``` + +```rust +// Rust +use autonomi::{Client, PaymentOption}; +use ant_evm::EvmWallet; + +// Initialize client +let client = Client::new()?; + +// Create or load a wallet +let wallet = EvmWallet::create()?; // or load from private key +let payment = wallet.into(); // Converts to PaymentOption + +// Put data with wallet payment +let data = b"Hello, World!".to_vec(); +let address = client.data_put_public(data.into(), payment).await?; +``` + +### Using Pre-paid Receipts + +For better efficiency when doing multiple put operations, you can pre-pay for storage and reuse the receipt: + +```python +# Python +from autonomi import Client, PaymentOption +from autonomi.evm import EvmWallet + +# Initialize client +client = Client() +wallet = EvmWallet.create() + +# Get receipt for multiple operations +data1 = b"First piece of data" +data2 = b"Second piece of data" + +# Create payment receipt +receipt = client.create_payment_receipt([data1, data2], wallet) +payment = PaymentOption.from_receipt(receipt) + +# Use receipt for puts +addr1 = client.data_put_public(data1, payment) +addr2 = client.data_put_public(data2, payment) +``` + +```typescript +// Node.js +import { Client, PaymentOption } from '@autonomi/client'; +import { EvmWallet } from '@autonomi/evm'; + +// Initialize client +const client = new Client(); +const wallet = EvmWallet.create(); + +// Get receipt for multiple operations +const data1 = Buffer.from("First piece of data"); +const data2 = Buffer.from("Second piece of data"); + +// Create payment receipt +const receipt = await client.createPaymentReceipt([data1, data2], wallet); +const payment = PaymentOption.fromReceipt(receipt); + +// Use receipt for puts +const addr1 = await client.dataPutPublic(data1, payment); +const addr2 = await client.dataPutPublic(data2, payment); +``` + +```rust +// Rust +use autonomi::{Client, PaymentOption}; +use ant_evm::EvmWallet; + +// Initialize client +let client = Client::new()?; +let wallet = EvmWallet::create()?; + +// Get receipt for multiple operations +let data1 = b"First piece of data".to_vec(); +let data2 = b"Second piece of data".to_vec(); + +// Create payment receipt +let receipt = client.create_payment_receipt( + vec![data1.clone(), data2.clone()].into_iter(), + &wallet +).await?; +let payment = receipt.into(); // Converts to PaymentOption + +// Use receipt for puts +let addr1 = client.data_put_public(data1.into(), payment.clone()).await?; +let addr2 = client.data_put_public(data2.into(), payment).await?; +``` + +## Cost Calculation + +The cost of storing data depends on several factors: + +- Size of the data +- Network density +- Storage duration +- Current network conditions + +You can calculate the cost before performing a put operation: + +```python +# Python +cost = client.calculate_storage_cost(data) +print(f"Storage will cost {cost} tokens") +``` + +```typescript +// Node.js +const cost = await client.calculateStorageCost(data); +console.log(`Storage will cost ${cost} tokens`); +``` + +```rust +// Rust +let cost = client.calculate_storage_cost(&data).await?; +println!("Storage will cost {} tokens", cost); +``` + +## Token Management + +Before you can pay for storage, you need to ensure your wallet has sufficient tokens and has approved the payment contract to spend them: + +```python +# Python +# Check balance +balance = wallet.get_balance() + +# Approve tokens if needed +if not wallet.has_approved_tokens(): + wallet.approve_tokens() +``` + +```typescript +// Node.js +// Check balance +const balance = await wallet.getBalance(); + +// Approve tokens if needed +if (!await wallet.hasApprovedTokens()) { + await wallet.approveTokens(); +} +``` + +```rust +// Rust +// Check balance +let balance = wallet.get_balance().await?; + +// Approve tokens if needed +if !wallet.has_approved_tokens().await? { + wallet.approve_tokens().await?; +} +``` + +## Error Handling + +Common payment-related errors you might encounter: + +1. `InsufficientBalance` - Wallet doesn't have enough tokens +2. `TokenNotApproved` - Token spending not approved for the payment contract +3. `PaymentExpired` - Payment quote has expired (when using receipts) +4. `PaymentVerificationFailed` - Payment verification failed on the network + +Example error handling: + +```python +# Python +try: + address = client.data_put_public(data, payment) +except InsufficientBalance: + print("Not enough tokens in wallet") +except TokenNotApproved: + print("Need to approve token spending") +except PaymentError as e: + print(f"Payment failed: {e}") +``` + +```typescript +// Node.js +try { + const address = await client.dataPutPublic(data, payment); +} catch (e) { + if (e instanceof InsufficientBalance) { + console.log("Not enough tokens in wallet"); + } else if (e instanceof TokenNotApproved) { + console.log("Need to approve token spending"); + } else { + console.log(`Payment failed: ${e}`); + } +} +``` + +```rust +// Rust +match client.data_put_public(data.into(), payment).await { + Err(PutError::InsufficientBalance) => { + println!("Not enough tokens in wallet"); + } + Err(PutError::TokenNotApproved) => { + println!("Need to approve token spending"); + } + Err(e) => { + println!("Payment failed: {}", e); + } + Ok(address) => { + println!("Data stored at {}", address); + } +} +``` + +## Best Practices + +1. **Pre-approve Tokens**: Approve token spending before starting put operations to avoid extra transactions. + +2. **Use Receipts**: When doing multiple put operations, use receipts to avoid making separate payments for each operation. + +3. **Check Costs**: Always check storage costs before proceeding with large data uploads. + +4. **Handle Errors**: Implement proper error handling for payment-related issues. + +5. **Monitor Balance**: Keep track of your wallet balance to ensure sufficient funds for operations. + +## Testing Payments + +When testing your application, you can use the local development environment which provides a test EVM network with pre-funded wallets. See the [Local Development Guide](local_development.md) for details. diff --git a/docs/online-documentation/guides/testing_guide.md b/docs/online-documentation/guides/testing_guide.md new file mode 100644 index 0000000000..9ab95321ba --- /dev/null +++ b/docs/online-documentation/guides/testing_guide.md @@ -0,0 +1,111 @@ +# Testing Guide + +This guide covers testing strategies for Autonomi applications across different languages and environments. + +## Test Environment Setup + +### Node.js + +```bash +npm install --save-dev jest @types/jest ts-jest +``` + +### Python + +```bash +pip install pytest pytest-asyncio +``` + +### Rust + +```bash +cargo install cargo-test +``` + +## Writing Tests + +### Node.js Example + +```typescript +import { Client, LinkedList } from '@autonomi/client'; + +describe('LinkedList Operations', () => { + let client: Client; + + beforeEach(() => { + client = new Client(); + }); + + test('should store and retrieve linked list', async () => { + const list = new LinkedList(); + list.append("test data"); + + const address = await client.linkedListPut(list); + const retrieved = await client.linkedListGet(address); + + expect(retrieved.toString()).toBe("test data"); + }); +}); +``` + +### Python Example + +```python +import pytest +from autonomi import Client, LinkedList + +@pytest.mark.asyncio +async def test_linked_list_operations(): + client = Client() + + # Create and store list + list_obj = LinkedList() + list_obj.append("test data") + + address = await client.linked_list_put(list_obj) + retrieved = await client.linked_list_get(address) + + assert str(retrieved) == "test data" +``` + +### Rust Example + +```rust +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_linked_list_operations() { + let client = Client::new(); + + let mut list = LinkedList::new(); + list.append("test data"); + + let address = client.linked_list_put(&list).unwrap(); + let retrieved = client.linked_list_get(&address).unwrap(); + + assert_eq!(retrieved.to_string(), "test data"); + } +} +``` + +## Test Categories + +1. Unit Tests +2. Integration Tests +3. Network Tests +4. EVM Integration Tests + +## CI/CD Integration + +- GitHub Actions configuration +- Test automation +- Coverage reporting + +## Best Practices + +- Test isolation +- Mock network calls +- Error scenarios +- Performance testing diff --git a/docs/online-documentation/index.md b/docs/online-documentation/index.md new file mode 100644 index 0000000000..2690d09b19 --- /dev/null +++ b/docs/online-documentation/index.md @@ -0,0 +1,133 @@ +# Autonomi Documentation + +Welcome to the Autonomi documentation! This guide will help you get started with using the Autonomi network client. + +## What is Autonomi? + +Autonomi is a decentralised data and communications platform designed to provide complete privacy, security, and freedom by distributing data across a peer-to-peer network, rather than relying on centralised servers. Through end-to-end encryption, self-authentication, and the allocation of storage and bandwidth from users’ own devices, it seeks to create an autonomous, self-sustaining system where data ownership remains firmly in the hands of individuals rather than corporations. + +## Quick Links + +- [Installation Guide](getting-started/installation.md) +- Core Concepts: + - [Data Types](guides/data_types.md) - Understanding the fundamental data structures + - [Client Modes](guides/client_modes.md) - Different operational modes of the client + - [Data Storage](guides/data_storage.md) - How data is stored and retrieved + - [Local Network Setup](guides/local_network.md) - Setting up a local development environmentv + +### API References + +- [Autonomi Client](api/autonomi-client/README.md) - Core client library for network operations +- [Ant Node](api/ant-node/README.md) - Node implementation for network participation +- [BLS Threshold Crypto](api/blsttc/README.md) - Threshold cryptography implementation +- [Self Encryption](api/self-encryption/README.md) - Content-based encryption library +- Developer Resources: + + +## Language Support + +Autonomi provides client libraries for multiple languages: + +=== "Node.js" + ```typescript + import { Client } from 'autonomi'; + + const client = new Client(); + await client.connect(); + ``` + +=== "Python" + ```python + from autonomi import Client + + client = Client() + await client.connect() + ``` + +=== "Rust" + ```rust + use autonomi::Client; + + let client = Client::new()?; + ``` + +## Building from Source + +=== "Python (using Maturin & uv)" + ```bash + # Install build dependencies + curl -LsSf | sh + uv pip install maturin + + # Clone the repository + git clone https://github.com/dirvine/autonomi.git + cd autonomi + + # Create and activate virtual environment + uv venv + source .venv/bin/activate # Unix + # or + .venv\Scripts\activate # Windows + + # Build and install the package + cd python + maturin develop + + # Install dependencies + uv pip install -r requirements.txt + ``` + +=== "Node.js" + ```bash + # Install build dependencies + npm install -g node-gyp + + # Clone the repository + git clone https://github.com/dirvine/autonomi.git + cd autonomi + + # Build the Node.js bindings + cd nodejs + npm install + npm run build + + # Link for local development + npm link + ``` + +=== "Rust" + ```bash + # Clone the repository + git clone + cd autonomi + + # Build the project + cargo build --release + + # Run tests + cargo test --all-features + + # Install locally + cargo install --path . + ``` + +## Contributing + +We welcome contributions! Here's how you can help: + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Submit a pull request + +For more details, see our [Contributing Guide](https://github.com/dirvine/autonomi/blob/main/CONTRIBUTING.md). + +## Getting Help + +- [GitHub Issues](https://github.com/dirvine/autonomi/issues) +- API References: + - [Autonomi Client](api/autonomi-client/README.md) + - [Ant Node](api/ant-node/README.md) + - [BLS Threshold Crypto](api/blsttc/README.md) + - [Self Encryption](api/self-encryption/README.md) +- [Testing Guide](guides/testing_guide.md) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000000..a7533dc5d6 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,81 @@ +site_name: Autonomi Documentation +docs_dir: docs/online-documentation +theme: + name: material + features: + - navigation.tabs + - navigation.sections + - navigation.expand + - navigation.indexes + - toc.integrate + - search.suggest + - search.highlight + - content.tabs.link + - content.code.annotation + - content.code.copy + language: en + palette: + - scheme: default + toggle: + icon: material/toggle-switch-off-outline + name: Switch to dark mode + primary: teal + accent: purple + - scheme: slate + toggle: + icon: material/toggle-switch + name: Switch to light mode + primary: teal + accent: lime + +nav: + - Home: index.md + - Getting Started: + - Installation: getting-started/installation.md + - Core Concepts: + - Data Types: guides/data_types.md + - Client Modes: guides/client_modes.md + - Data Storage: guides/data_storage.md + - Developer Guides: + - Local Network Setup: guides/local_network.md + - Local Development: guides/local_development.md + - EVM Integration: guides/evm_integration.md + - Testing Guide: guides/testing_guide.md + - Payments: guides/payments.md + - API Reference: + - Overview: api/index.md + - Client API: + - Overview: api/autonomi-client/README.md + - Data Types: api/autonomi-client/data_types.md + - Error Handling: api/autonomi-client/errors.md + - Node API: + - Overview: api/ant-node/README.md + - Node Configuration: api/ant-node/configuration.md + - Network Operations: api/ant-node/network.md + - Cryptography: + - BLS Threshold Crypto: api/blsttc/README.md + - Self Encryption: api/self-encryption/README.md + +plugins: + - search + - git-revision-date-localized: + enable_creation_date: true + +markdown_extensions: + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - admonition + - pymdownx.arithmatex: + generic: true + - footnotes + - pymdownx.details + - pymdownx.superfences + - pymdownx.mark + - attr_list + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.tabbed: + alternate_style: true \ No newline at end of file diff --git a/nodejs/.gitignore b/nodejs/.gitignore new file mode 100644 index 0000000000..c2658d7d1b --- /dev/null +++ b/nodejs/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/nodejs/README.md b/nodejs/README.md new file mode 100644 index 0000000000..9c2619b922 --- /dev/null +++ b/nodejs/README.md @@ -0,0 +1,116 @@ +# Autonomi Node.js Client + +TypeScript/JavaScript bindings for the Autonomi client. + +## Installation + +```bash +npm install @autonomi/client +``` + +## Usage + +```typescript +import { Client } from '@autonomi/client'; + +async function example() { + // Connect to the network + const client = await Client.connect({ + peers: ['/ip4/127.0.0.1/tcp/12000'] + }); + + // Create a payment option using a wallet + const payment = { + type: 'wallet' as const, + wallet: 'your_wallet_address' + }; + + // Upload public data + const data = Buffer.from('Hello, Safe Network!'); + const addr = await client.dataPutPublic(data, payment); + console.log(`Data uploaded to: ${addr}`); + + // Download public data + const retrieved = await client.dataGetPublic(addr); + console.log(`Retrieved: ${retrieved.toString()}`); +} +``` + +## Features + +- TypeScript support with full type definitions +- Async/await API +- Support for: + - Public and private data operations + - Linked Lists + - Pointers + - Vaults + - User data management + +## API Reference + +### Client + +The main interface to interact with the Autonomi network. + +#### Connection + +```typescript +static connect(config: NetworkConfig): Promise +``` + +#### Data Operations + +```typescript +dataPutPublic(data: Buffer, payment: PaymentOption): Promise +dataGetPublic(address: string): Promise +``` + +#### Linked List Operations + +```typescript +linkedListGet(address: string): Promise +linkedListPut(options: LinkedListOptions, payment: PaymentOption): Promise +linkedListCost(key: string): Promise +``` + +#### Pointer Operations + +```typescript +pointerGet(address: string): Promise +pointerPut(options: PointerOptions, payment: PaymentOption): Promise +pointerCost(key: string): Promise +``` + +#### Vault Operations + +```typescript +vaultCost(key: string): Promise +writeBytesToVault(data: Buffer, payment: PaymentOption, options: VaultOptions): Promise +fetchAndDecryptVault(key: string): Promise<[Buffer, number]> +getUserDataFromVault(key: string): Promise +putUserDataToVault(key: string, payment: PaymentOption, userData: UserData): Promise +``` + +## Development + +```bash +# Install dependencies +npm install + +# Build +npm run build + +# Run tests +npm test + +# Run tests in watch mode +npm run test:watch + +# Lint +npm run lint +``` + +## License + +GPL-3.0 diff --git a/nodejs/jest.config.js b/nodejs/jest.config.js new file mode 100644 index 0000000000..d58f488638 --- /dev/null +++ b/nodejs/jest.config.js @@ -0,0 +1,11 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: ['/src', '/tests'], + testMatch: ['**/*.test.ts'], + collectCoverage: true, + coverageDirectory: 'coverage', + coverageReporters: ['text', 'lcov'], + coveragePathIgnorePatterns: ['/node_modules/', '/dist/'] +}; \ No newline at end of file diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json new file mode 100644 index 0000000000..9af942eede --- /dev/null +++ b/nodejs/package-lock.json @@ -0,0 +1,4012 @@ +{ + "name": "nodejs", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nodejs", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@types/jest": "^29.5.14", + "@types/node": "^22.10.2", + "jest": "^29.7.0", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", + "typescript": "^5.7.2" + } + }, + "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/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", + "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.3" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.3", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/node": { + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "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/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", + "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "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/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", + "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "dev": true, + "license": "MIT" + }, + "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/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.76", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz", + "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "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/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "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/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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": "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": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "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/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "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/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "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": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/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": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.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/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-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/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-jest": { + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "^2.1.0", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "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" + }, + "bin": { + "node-which": "bin/node-which" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/nodejs/package.json b/nodejs/package.json new file mode 100644 index 0000000000..8a67efcc56 --- /dev/null +++ b/nodejs/package.json @@ -0,0 +1,38 @@ +{ + "name": "@autonomi/client", + "version": "0.1.0", + "description": "Node.js bindings for Autonomi client", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "test": "jest", + "test:watch": "jest --watch", + "lint": "eslint src/**/*.ts", + "clean": "rm -rf dist", + "prepare": "npm run build" + }, + "keywords": [ + "autonomi", + "client", + "network", + "linked-list", + "pointer", + "vault" + ], + "author": "Safe Network", + "license": "GPL-3.0", + "devDependencies": { + "@types/jest": "^29.5.11", + "@types/node": "^20.10.6", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + }, + "files": [ + "dist", + "README.md", + "LICENSE" + ] +} \ No newline at end of file diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts new file mode 100644 index 0000000000..7839c8bc1c --- /dev/null +++ b/nodejs/src/client.ts @@ -0,0 +1,91 @@ +import { NetworkConfig, PaymentOption, LinkedListOptions, PointerOptions, VaultOptions, UserData } from './types'; + +export class Client { + private nativeClient: any; // Will be replaced with actual native binding type + + private constructor(nativeClient: any) { + this.nativeClient = nativeClient; + } + + static async connect(config: NetworkConfig): Promise { + // TODO: Initialize native client + throw new Error('Not implemented'); + } + + // Data Operations + async dataPutPublic(data: Buffer, payment: PaymentOption): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + async dataGetPublic(address: string): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + // Linked List Operations + async linkedListGet(address: string): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + async linkedListPut(options: LinkedListOptions, payment: PaymentOption): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + async linkedListCost(key: string): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + // Pointer Operations + async pointerGet(address: string): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + async pointerPut(options: PointerOptions, payment: PaymentOption): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + async pointerCost(key: string): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + // Vault Operations + async vaultCost(key: string): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + async writeBytesToVault( + data: Buffer, + payment: PaymentOption, + options: VaultOptions + ): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + async fetchAndDecryptVault(key: string): Promise<[Buffer, number]> { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + async getUserDataFromVault(key: string): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } + + async putUserDataToVault( + key: string, + payment: PaymentOption, + userData: UserData + ): Promise { + // TODO: Implement native binding call + throw new Error('Not implemented'); + } +} \ No newline at end of file diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts new file mode 100644 index 0000000000..2a09e8fb44 --- /dev/null +++ b/nodejs/src/index.ts @@ -0,0 +1,6 @@ +export * from './client'; +export * from './types'; +export * from './wallet'; +export * from './linkedList'; +export * from './pointer'; +export * from './vault'; \ No newline at end of file diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts new file mode 100644 index 0000000000..0adcbef559 --- /dev/null +++ b/nodejs/src/types.ts @@ -0,0 +1,38 @@ +export type Address = string; +export type HexString = string; +export type SecretKey = string; +export type PublicKey = string; + +export interface PaymentOption { + type: 'wallet'; + wallet: string; +} + +export interface LinkedListOptions { + owner: PublicKey; + counter: number; + target: string; + key: SecretKey; +} + +export interface PointerOptions { + owner: PublicKey; + counter: number; + target: string; + key: SecretKey; +} + +export interface VaultOptions { + key: SecretKey; + contentType?: number; +} + +export interface UserData { + fileArchives: Array<[string, string]>; + privateFileArchives: Array<[string, string]>; +} + +export interface NetworkConfig { + peers: string[]; + network?: 'arbitrum' | 'arbitrum_testnet'; +} \ No newline at end of file diff --git a/nodejs/tests/client.test.ts b/nodejs/tests/client.test.ts new file mode 100644 index 0000000000..ccacd2a2bd --- /dev/null +++ b/nodejs/tests/client.test.ts @@ -0,0 +1,33 @@ +import { Client } from '../src/client'; + +describe('Client', () => { + describe('connect', () => { + it('should throw not implemented error', async () => { + await expect(Client.connect({ peers: [] })).rejects.toThrow('Not implemented'); + }); + }); + + describe('linkedListOperations', () => { + it('should throw not implemented error for linkedListGet', async () => { + const client = await Client.connect({ peers: [] }).catch(() => null); + if (!client) return; + await expect(client.linkedListGet('address')).rejects.toThrow('Not implemented'); + }); + + it('should throw not implemented error for linkedListPut', async () => { + const client = await Client.connect({ peers: [] }).catch(() => null); + if (!client) return; + await expect( + client.linkedListPut( + { + owner: 'owner', + counter: 0, + target: 'target', + key: 'key' + }, + { type: 'wallet', wallet: 'wallet' } + ) + ).rejects.toThrow('Not implemented'); + }); + }); +}); \ No newline at end of file diff --git a/nodejs/tsconfig.json b/nodejs/tsconfig.json new file mode 100644 index 0000000000..6094d01583 --- /dev/null +++ b/nodejs/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": [ + "ES2020" + ], + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node" + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist", + "tests" + ] +} \ No newline at end of file