Migrate from Supabase to direct PostgreSQL connection

- Replace @supabase/supabase-js with native pg library
- Rewrite database.js to use PostgreSQL connection pool
- Update server.js with PostgreSQL connection testing
- Create postgres-schema.sql with complete database schema
- Add apply-schema.js script for easy schema deployment
- Update all documentation (README.md, DEPLOYMENT.md, deploy.sh)
- Remove Supabase-specific files and references
- Update db.config.example.js with PostgreSQL format
This commit is contained in:
2025-12-22 12:54:36 +11:00
parent 90cf68327a
commit 0a8ea2b603
234 changed files with 754 additions and 33727 deletions

View File

@@ -1,6 +1,6 @@
# Connect-5 Production Deployment Guide
Complete guide for deploying Connect-5 to production with Supabase database.
Complete guide for deploying Connect-5 to production with PostgreSQL database.
## Quick Deploy
@@ -12,7 +12,7 @@ sudo bash deploy.sh
The script will:
1. ✅ Prompt for project directory (or use current)
2. ✅ Request Supabase credentials
2. ✅ Request PostgreSQL credentials
3. ✅ Create `db.config.js`
4. ✅ Install dependencies
5. ✅ Detect and configure web server (Nginx/Apache)
@@ -23,16 +23,17 @@ The script will:
## Prerequisites
### 1. Supabase Setup
### 1. PostgreSQL Database Setup
1. Create project at [app.supabase.com](https://app.supabase.com)
2. Run the SQL schema from [supabase-schema-complete.sql](supabase-schema-complete.sql)
3. Get your credentials:
- Project URL
- Anon/Public API key
- Database password
1. Ensure PostgreSQL server is running and accessible
2. Create the database: `CREATE DATABASE connect5;`
3. Run the SQL schema from [postgres-schema.sql](postgres-schema.sql):
```bash
psql -h HOST -U postgres -d connect5 -f postgres-schema.sql
```
4. Ensure your PostgreSQL server accepts remote connections (if deploying remotely)
See [SUPABASE_SETUP.md](SUPABASE_SETUP.md) for detailed instructions.
See [README_DB_CONFIG.md](README_DB_CONFIG.md) for database configuration details.
### 2. Server Requirements
@@ -61,10 +62,17 @@ Create `db.config.js`:
```javascript
module.exports = {
supabaseUrl: 'https://your-project.supabase.co',
supabaseAnonKey: 'your-anon-key',
supabasePassword: 'your-db-password',
postgresConnectionString: 'postgresql://postgres:password@db.project.supabase.co:5432/postgres'
HOST: 'your-postgres-host',
USER: 'postgres',
PASSWORD: 'your-database-password',
DB: 'connect5',
dialect: 'postgres',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
};
```
@@ -182,7 +190,7 @@ Should return:
"connected": true,
"latency": 45,
"writeCapable": true,
"database": "Supabase PostgreSQL"
"connectionType": "PostgreSQL Direct Connection"
}
```
@@ -216,12 +224,13 @@ Visit `https://yourdomain.com/` and verify:
### Database Disconnected
**Problem**: Supabase credentials incorrect
**Problem**: PostgreSQL credentials incorrect or server unreachable
**Solution**:
1. Check `db.config.js` has correct URL and key
2. Verify credentials in Supabase dashboard
1. Check `db.config.js` has correct HOST, USER, PASSWORD, and DB
2. Verify PostgreSQL server is running: `sudo systemctl status postgresql`
3. Check server.log: `tail -f server.log`
4. Test direct connection: `psql -h HOST -U postgres -d connect5`
### WebSocket Connection Failed
@@ -239,7 +248,7 @@ Visit `https://yourdomain.com/` and verify:
**Solution**:
1. Check port: `netstat -tlnp | grep 3000`
2. Check logs: `tail -f server.log`
3. Verify Supabase credentials
3. Verify PostgreSQL credentials in `db.config.js`
4. Test database: `curl http://localhost:3000/api/db-status`
---
@@ -321,9 +330,10 @@ sudo systemctl restart apache2
- `db.config.js` is in `.gitignore` (never commit credentials)
- Use environment variables for sensitive data in production
- Enable Supabase Row Level Security (RLS) policies
- Configure PostgreSQL firewall rules to restrict access
- Keep dependencies updated: `npm audit fix`
- Use HTTPS only (no HTTP)
- Use strong PostgreSQL passwords
---
@@ -331,7 +341,7 @@ sudo systemctl restart apache2
For issues:
1. Check this deployment guide
2. Review [SUPABASE_SETUP.md](SUPABASE_SETUP.md)
2. Review [README_DB_CONFIG.md](README_DB_CONFIG.md)
3. Check server logs
4. Verify Supabase dashboard shows activity
4. Verify PostgreSQL server status: `sudo systemctl status postgresql`
5. Test local endpoint: `curl http://localhost:3000/api/db-status`

View File

@@ -10,7 +10,7 @@ A beautiful, feature-rich implementation of the classic Connect-5 (Gomoku) game
[![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)
[![Socket.io](https://img.shields.io/badge/Socket.io-4.0+-blue.svg)](https://socket.io/)
[![Supabase](https://img.shields.io/badge/Supabase-PostgreSQL-3ECF8E.svg)](https://supabase.com/)
[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-3ECF8E.svg)](https://postgresql.org/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[Play Now](https://connect5.beyondcloud.technology/) • [Features](#features) • [Installation](#installation) • [Usage](#usage) • [Multiplayer](#multiplayer) • [Tech Stack](#tech-stack)
@@ -70,7 +70,7 @@ A beautiful, feature-rich implementation of the classic Connect-5 (Gomoku) game
### Prerequisites
- **Node.js** 18+ ([Download](https://nodejs.org/))
- **Supabase Account** (Free tier available at [supabase.com](https://supabase.com/))
- **PostgreSQL** Database ([Download](https://www.postgresql.org/download/))
- **Git** ([Download](https://git-scm.com/))
### Quick Start
@@ -84,12 +84,14 @@ cd Connect-5
npm install
# Configure database
# 1. Create a Supabase project at https://supabase.com
# 1. Ensure PostgreSQL is running and create the database:
# CREATE DATABASE connect5;
# 2. Copy db.config.example.js to db.config.js
cp db.config.example.js db.config.js
# 3. Edit db.config.js with your Supabase credentials
# 4. Run the SQL schema in Supabase SQL Editor (see SUPABASE_SETUP.md)
# 3. Edit db.config.js with your PostgreSQL credentials
# 4. Run the SQL schema
psql -h HOST -U postgres -d connect5 -f postgres-schema.sql
# Start the server
npm start
@@ -97,7 +99,7 @@ npm start
The server will start on **http://localhost:3000**
For detailed setup instructions, see [SUPABASE_SETUP.md](SUPABASE_SETUP.md)
For detailed setup instructions, see [README_DB_CONFIG.md](README_DB_CONFIG.md)
---
@@ -192,16 +194,16 @@ For detailed setup instructions, see [SUPABASE_SETUP.md](SUPABASE_SETUP.md)
- **Supabase Client**: PostgreSQL database client with real-time capabilities
### Database
- **Supabase**: Managed PostgreSQL database with real-time subscriptions
- **Row Level Security**: Built-in security policies
- **Auto-generated APIs**: RESTful and real-time APIs
- **PostgreSQL**: Robust open-source relational database
- **Connection Pooling**: Efficient connection management
- **Native SQL**: Direct PostgreSQL queries for performance
### Dependencies
```json
{
"express": "^4.18.2",
"socket.io": "^4.6.1",
"@supabase/supabase-js": "^2.39.0",
"pg": "^8.11.3",
"bad-words": "^3.0.4",
"cors": "^2.8.5",
"nodemon": "^2.0.22"
@@ -221,7 +223,7 @@ Connect-5/
├── 🌐 multiplayer.js # Multiplayer client logic
├── 🖼️ Logo.png # BCT logo
├── 🔧 server.js # Express & Socket.io server
├── 💾 database.js # MySQL connection & queries
├── 💾 database.js # PostgreSQL connection & queries
├── 🎯 gameManager.js # Multiplayer game management
├── 📦 package.json # Dependencies
└── 📚 README.md # This file
@@ -243,14 +245,16 @@ Edit `db.config.js`:
```javascript
module.exports = {
supabaseUrl: 'https://your-project.supabase.co',
supabaseAnonKey: 'your-anon-key-here',
supabasePassword: 'your-database-password',
postgresConnectionString: 'postgresql://postgres:password@...'
HOST: 'your-postgres-host',
USER: 'postgres',
PASSWORD: 'your-database-password',
DB: 'connect5',
dialect: 'postgres',
pool: { max: 5, min: 0, acquire: 30000, idle: 10000 }
};
```
See [SUPABASE_SETUP.md](SUPABASE_SETUP.md) for detailed setup instructions.
See [README_DB_CONFIG.md](README_DB_CONFIG.md) for detailed setup instructions.
### Server Configuration
@@ -272,7 +276,7 @@ sudo bash deploy.sh
The script will:
- ✅ Prompt for project directory
- ✅ Request Supabase credentials
- ✅ Request PostgreSQL credentials
- ✅ Configure database connection
- ✅ Install dependencies
- ✅ Detect and configure web server (Nginx/Apache)
@@ -328,8 +332,8 @@ npm start
## 🐛 Troubleshooting
### Connection Refused Error
**Problem**: Cannot connect to Supabase database
**Solution**: Verify credentials in `db.config.js` and check Supabase dashboard
**Problem**: Cannot connect to PostgreSQL database
**Solution**: Verify credentials in `db.config.js` and check PostgreSQL is running
### Port Already in Use
**Problem**: Port 3000 is already occupied
@@ -345,7 +349,7 @@ npm start
### Database Disconnected
**Problem**: Status bar shows "Disconnected"
**Solution**: Check `db.config.js` credentials and Supabase project status
**Solution**: Check `db.config.js` credentials and PostgreSQL server status
For more troubleshooting, see [DEPLOYMENT.md](DEPLOYMENT.md)

View File

@@ -1,45 +1,46 @@
# Database Configuration Setup - Supabase
# Database Configuration Setup - PostgreSQL
## Overview
Database credentials are stored in a separate configuration file (`db.config.js`) that is **NOT committed to GitHub** for security reasons.
This project now uses **Supabase** (PostgreSQL) instead of MySQL.
This project uses **PostgreSQL** for persistent data storage.
## Files
### 1. `db.config.example.js` (Committed to Git)
Template file showing the required Supabase configuration structure.
Template file showing the required PostgreSQL configuration structure.
### 2. `db.config.js` (NOT Committed - in .gitignore)
Contains actual Supabase credentials. This file must be created manually.
Contains actual PostgreSQL credentials. This file must be created manually.
### 3. `.gitignore`
Ensures `db.config.js` is never committed to the repository.
## Quick Setup
See **[SUPABASE_SETUP.md](SUPABASE_SETUP.md)** for detailed step-by-step instructions.
### Quick Start
1. **Create Supabase project** at [app.supabase.com](https://app.supabase.com)
2. **Copy credentials** from Project Settings → API
3. **Update `db.config.js`:**
1. **Ensure PostgreSQL is running** on your server
2. **Create the database:** `CREATE DATABASE connect5;`
3. **Run the schema:** `psql -h HOST -U postgres -d connect5 -f postgres-schema.sql`
4. **Create `db.config.js`:**
```javascript
module.exports = {
supabaseUrl: 'https://xxxxx.supabase.co',
supabaseAnonKey: 'eyJhbGci...',
supabasePassword: 't1hWsackxbYzRIPD'
HOST: '202.171.184.108',
USER: 'postgres',
PASSWORD: 'your-password',
DB: 'connect5',
dialect: 'postgres',
pool: { max: 5, min: 0, acquire: 30000, idle: 10000 }
};
```
4. **Run SQL schema** in Supabase SQL Editor (see SUPABASE_SETUP.md)
5. **Start server:** `npm start`
## Security Features
✅ **Credentials not in git** - `db.config.js` is in `.gitignore`
✅ **Template provided** - `db.config.example.js` shows the structure
✅ **Supabase RLS** - Row Level Security policies protect data
✅ **Connection pooling** - Efficient database connection management
✅ **Separate config** - Easy to update without touching main code
## Troubleshooting
@@ -49,28 +50,29 @@ See **[SUPABASE_SETUP.md](SUPABASE_SETUP.md)** for detailed step-by-step instruc
**Solution:** Create the `db.config.js` file:
```bash
cp db.config.example.js db.config.js
# Then edit with your Supabase credentials
# Then edit with your PostgreSQL credentials
```
### Error: Invalid API key
### Error: ECONNREFUSED or connection timeout
**Solution:** Check your credentials in `db.config.js`:
- Verify `supabaseUrl` is correct
- Verify `supabaseAnonKey` (should start with `eyJ...`)
- Get credentials from Supabase dashboard → Project Settings → API
- Verify `HOST` is accessible
- Verify `USER` and `PASSWORD` are correct
- Ensure PostgreSQL server is running: `sudo systemctl status postgresql`
- Check firewall allows connection to port 5432
### Error: Table 'players' does not exist
**Solution:**
- Run the SQL schema in Supabase SQL Editor
- See SUPABASE_SETUP.md Step 4 for the complete schema
- Run the SQL schema: `psql -h HOST -U postgres -d connect5 -f postgres-schema.sql`
- See README.md for setup instructions
## Important Notes
⚠️ **NEVER commit `db.config.js` to git**
⚠️ **Keep credentials secure**
⚠️ **Use different projects for dev/prod**
⚠️ **The anon key is safe for client-side use** (protected by RLS)
⚠️ **Use different databases for dev/prod**
⚠️ **Configure PostgreSQL firewall rules appropriately**
## File Structure
@@ -80,7 +82,6 @@ Connect-5/
├── db.config.js ← Your credentials (NOT in git)
├── .gitignore ← Protects db.config.js
├── database.js ← Imports from db.config.js
├── supabase-functions.sql ← Helper functions for Supabase
├── SUPABASE_SETUP.md ← Detailed setup guide
├── postgres-schema.sql ← Database schema
└── README_DB_CONFIG.md ← This file
```

70
SETUP_INSTRUCTIONS.txt Normal file
View File

@@ -0,0 +1,70 @@
=================================================================
POSTGRESQL MIGRATION - FINAL SETUP STEP
=================================================================
✅ Code migration: COMPLETE
✅ Dependencies installed: COMPLETE
✅ Configuration file created: COMPLETE
⚠️ DATABASE SCHEMA: NEEDS TO BE APPLIED
=================================================================
NEXT STEP: Initialize PostgreSQL Database
=================================================================
You need to run the postgres-schema.sql file on your PostgreSQL server.
METHOD 1: If you have PostgreSQL client tools installed
--------------------------------------------------------
Run this command from PowerShell:
$env:PGPASSWORD='X@gon2005!#$'; psql -h 202.171.184.108 -U postgres -d connect5 -f postgres-schema.sql
METHOD 2: Using pgAdmin or another PostgreSQL GUI
--------------------------------------------------
1. Open pgAdmin or your PostgreSQL management tool
2. Connect to server: 202.171.184.108
3. Username: postgres
4. Password: X@gon2005!#$
5. Right-click on database 'connect5' (create if doesn't exist)
6. Select "Query Tool"
7. Open the file: postgres-schema.sql
8. Execute the entire script
9. You should see "Tables Created Successfully! table_count = 4"
METHOD 3: Copy/Paste SQL
-------------------------
If database 'connect5' doesn't exist, first run:
CREATE DATABASE connect5;
Then connect to connect5 and run the entire contents of:
postgres-schema.sql
=================================================================
VERIFY SCHEMA WAS APPLIED
=================================================================
After running the schema, verify with this query:
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name IN ('players', 'active_sessions', 'games', 'game_moves');
Expected: 4 tables listed
=================================================================
THEN START THE SERVER
=================================================================
Once the schema is applied:
npm start
The server should start successfully and show:
✅ Database schema verified successfully
🌐 Server running on port 3000
Then test at: http://localhost:3000
=================================================================

View File

@@ -1,223 +0,0 @@
# Supabase Setup Guide for Connect-5
This guide will help you set up Supabase for the Connect-5 multiplayer game.
## Step 1: Create Supabase Project
1. Go to [https://app.supabase.com](https://app.supabase.com)
2. Sign in or create an account
3. Click "New Project"
4. Fill in the project details:
- **Organization**: Select or create your organization (e.g., "DeNNiiInc's Org")
- **Project name**: `Connect5`
- **Database password**: `t1hWsackxbYzRIPD` (or your chosen password)
- **Region**: Oceania (Sydney) - or closest to your users
- **Pricing Plan**: Free tier is sufficient for development
5. Click "Create new project"
6. Wait for the project to be provisioned (takes 1-2 minutes)
## Step 2: Get Your Credentials
Once your project is ready:
1. Go to **Project Settings** (gear icon in sidebar)
2. Navigate to **API** section
3. Copy the following values:
- **Project URL** (e.g., `https://xxxxxxxxxxxxx.supabase.co`)
- **anon/public key** (long JWT token starting with `eyJ...`)
## Step 3: Configure Your Application
1. Open `db.config.js` in your project
2. Replace the placeholder values:
```javascript
module.exports = {
supabaseUrl: 'https://YOUR_PROJECT_ID.supabase.co', // Paste your Project URL here
supabaseAnonKey: 'YOUR_ANON_KEY_HERE', // Paste your anon key here
supabasePassword: 't1hWsackxbYzRIPD', // Your database password
// Optional: Direct PostgreSQL connection
postgresConnectionString: 'postgresql://postgres:t1hWsackxbYzRIPD@db.YOUR_PROJECT_ID.supabase.co:5432/postgres'
};
```
## Step 4: Create Database Tables
1. In your Supabase dashboard, click on **SQL Editor** in the sidebar
2. Click **New Query**
3. Copy and paste the following SQL:
```sql
-- Create players table
CREATE TABLE IF NOT EXISTS players (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
total_wins INT DEFAULT 0,
total_losses INT DEFAULT 0,
total_draws INT DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_username ON players(username);
-- Create active sessions table
CREATE TABLE IF NOT EXISTS active_sessions (
session_id VARCHAR(100) PRIMARY KEY,
player_id BIGINT NOT NULL,
username VARCHAR(50) NOT NULL,
connected_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_heartbeat TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
FOREIGN KEY (player_id) REFERENCES players(id) ON DELETE CASCADE
);
-- Create game state enum type
DO $$ BEGIN
CREATE TYPE game_state_enum AS ENUM ('pending', 'active', 'completed', 'abandoned');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- Create games table
CREATE TABLE IF NOT EXISTS games (
id BIGSERIAL PRIMARY KEY,
player1_id BIGINT NOT NULL,
player2_id BIGINT NOT NULL,
player1_username VARCHAR(50) NOT NULL,
player2_username VARCHAR(50) NOT NULL,
board_size INT DEFAULT 15,
winner_id BIGINT,
game_state game_state_enum DEFAULT 'pending',
started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
completed_at TIMESTAMP WITH TIME ZONE,
FOREIGN KEY (player1_id) REFERENCES players(id),
FOREIGN KEY (player2_id) REFERENCES players(id),
FOREIGN KEY (winner_id) REFERENCES players(id)
);
-- Create game moves table
CREATE TABLE IF NOT EXISTS game_moves (
id BIGSERIAL PRIMARY KEY,
game_id BIGINT NOT NULL,
player_id BIGINT NOT NULL,
row_position INT NOT NULL,
col_position INT NOT NULL,
move_number INT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
FOREIGN KEY (game_id) REFERENCES games(id) ON DELETE CASCADE,
FOREIGN KEY (player_id) REFERENCES players(id)
);
CREATE INDEX IF NOT EXISTS idx_game ON game_moves(game_id);
-- Enable Row Level Security (RLS)
ALTER TABLE players ENABLE ROW LEVEL SECURITY;
ALTER TABLE active_sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE games ENABLE ROW LEVEL SECURITY;
ALTER TABLE game_moves ENABLE ROW LEVEL SECURITY;
-- Create policies to allow all operations (adjust based on your security needs)
CREATE POLICY "Allow all operations on players" ON players FOR ALL USING (true);
CREATE POLICY "Allow all operations on active_sessions" ON active_sessions FOR ALL USING (true);
CREATE POLICY "Allow all operations on games" ON games FOR ALL USING (true);
CREATE POLICY "Allow all operations on game_moves" ON game_moves FOR ALL USING (true);
```
4. Click **Run** or press `Ctrl+Enter`
5. You should see "Success. No rows returned" message
## Step 5: Create Helper Functions
1. In the same SQL Editor, create a new query
2. Copy and paste the contents of `supabase-functions.sql`:
```sql
-- Function to increment wins
CREATE OR REPLACE FUNCTION increment_wins(player_id BIGINT)
RETURNS void AS $$
BEGIN
UPDATE players
SET total_wins = total_wins + 1
WHERE id = player_id;
END;
$$ LANGUAGE plpgsql;
-- Function to increment losses
CREATE OR REPLACE FUNCTION increment_losses(player_id BIGINT)
RETURNS void AS $$
BEGIN
UPDATE players
SET total_losses = total_losses + 1
WHERE id = player_id;
END;
$$ LANGUAGE plpgsql;
-- Function to increment draws
CREATE OR REPLACE FUNCTION increment_draws(player_id BIGINT)
RETURNS void AS $$
BEGIN
UPDATE players
SET total_draws = total_draws + 1
WHERE id = player_id;
END;
$$ LANGUAGE plpgsql;
```
3. Click **Run**
## Step 6: Test Your Connection
1. Install dependencies:
```bash
npm install
```
2. Start the server:
```bash
npm start
```
3. Check the console output for:
- ✅ Database schema verified successfully
- 🗄️ Database connected
4. Open your browser to `http://localhost:3000`
5. Check the bottom status bar - it should show:
- **SQL**: Connected (green)
- **Latency**: Should be reasonable (depends on your location to Sydney)
- **Write**: Enabled (green)
## Troubleshooting
### "Invalid API key" Error
- Double-check your `supabaseAnonKey` in `db.config.js`
- Make sure you copied the **anon/public** key, not the service_role key
### "Cannot reach Supabase" Error
- Verify your `supabaseUrl` is correct
- Check your internet connection
- Ensure no firewall is blocking Supabase
### "Table 'players' does not exist" Error
- Make sure you ran the SQL schema in Step 4
- Check the SQL Editor for any error messages
- Verify all tables were created in the **Table Editor**
### High Latency
- This is normal if you're far from the Sydney region
- Consider changing the region when creating your project
- Latency doesn't significantly affect gameplay for turn-based games
## Security Notes
- The `db.config.js` file is in `.gitignore` and will NOT be committed to Git
- Never share your database password or anon key publicly
- The anon key is safe to use in client-side code (it's protected by RLS policies)
- For production, consider implementing more restrictive RLS policies
## Next Steps
Once connected, you can:
- Test multiplayer functionality
- Monitor your database in the Supabase dashboard
- View real-time data in the **Table Editor**
- Check logs in the **Logs** section
- Set up database backups (available in paid plans)

60
apply-schema.js Normal file
View File

@@ -0,0 +1,60 @@
// Quick script to apply postgres-schema.sql to the database
// Run with: node apply-schema.js
const fs = require('fs');
const { Pool } = require('pg');
const dbConfig = require('./db.config.js');
const pool = new Pool({
host: dbConfig.HOST,
user: dbConfig.USER,
password: dbConfig.PASSWORD,
database: dbConfig.DB,
port: 5432
});
async function applySchema() {
try {
console.log('📄 Reading postgres-schema.sql...');
const schema = fs.readFileSync('./postgres-schema.sql', 'utf8');
console.log('🔗 Connecting to PostgreSQL...');
console.log(` Host: ${dbConfig.HOST}`);
console.log(` Database: ${dbConfig.DB}`);
console.log('⚙️ Applying schema...');
await pool.query(schema);
console.log('✅ Schema applied successfully!');
// Verify tables were created
console.log('\n🔍 Verifying tables...');
const result = await pool.query(`
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name IN ('players', 'active_sessions', 'games', 'game_moves')
ORDER BY table_name;
`);
console.log(`✅ Found ${result.rows.length} tables:`);
result.rows.forEach(row => {
console.log(` - ${row.table_name}`);
});
if (result.rows.length === 4) {
console.log('\n🎉 Database setup complete! You can now run: npm start');
} else {
console.log('\n⚠ Warning: Expected 4 tables but found', result.rows.length);
}
} catch (error) {
console.error('❌ Error applying schema:', error.message);
console.error('\nDetails:', error);
process.exit(1);
} finally {
await pool.end();
}
}
applySchema();

View File

@@ -1,105 +1,49 @@
const { createClient } = require('@supabase/supabase-js');
const { Pool } = require('pg');
// Import database configuration from external file
// This file (db.config.js) is not committed to git for security
// Use db.config.example.js as a template
const dbConfig = require('./db.config.js');
// Create Supabase client
const supabase = createClient(dbConfig.supabaseUrl, dbConfig.supabaseAnonKey);
// Create PostgreSQL connection pool
const pool = new Pool({
host: dbConfig.HOST,
user: dbConfig.USER,
password: dbConfig.PASSWORD,
database: dbConfig.DB,
port: 5432,
max: dbConfig.pool.max,
min: dbConfig.pool.min,
acquireTimeoutMillis: dbConfig.pool.acquire,
idleTimeoutMillis: dbConfig.pool.idle
});
// Handle pool errors
pool.on('error', (err) => {
console.error('Unexpected error on idle PostgreSQL client', err);
});
// Initialize database schema
async function initializeDatabase() {
try {
console.log('🔄 Initializing Supabase database schema...');
console.log('🔄 Initializing PostgreSQL database schema...');
// Create players table
const { error: playersError } = await supabase.rpc('create_players_table', {});
// Check if tables exist by trying to query them
const result = await pool.query(`
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'players'
);
`);
// Since we can't run raw SQL directly with the JS client in the same way,
// we'll use Supabase's SQL editor or migrations
// For now, we'll check if tables exist by trying to query them
const { data: playersCheck, error: playersCheckError } = await supabase
.from('players')
.select('id')
.limit(1);
if (playersCheckError && playersCheckError.code === '42P01') {
console.log('⚠️ Tables not found. Please run the following SQL in your Supabase SQL Editor:');
if (!result.rows[0].exists) {
console.log('⚠️ Tables not found. Please run the following SQL in your PostgreSQL database:');
console.log(`
-- Create players table
CREATE TABLE IF NOT EXISTS players (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
total_wins INT DEFAULT 0,
total_losses INT DEFAULT 0,
total_draws INT DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_username ON players(username);
-- Create active sessions table
CREATE TABLE IF NOT EXISTS active_sessions (
session_id VARCHAR(100) PRIMARY KEY,
player_id BIGINT NOT NULL,
username VARCHAR(50) NOT NULL,
connected_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_heartbeat TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
FOREIGN KEY (player_id) REFERENCES players(id) ON DELETE CASCADE
);
-- Create game state enum type
DO $$ BEGIN
CREATE TYPE game_state_enum AS ENUM ('pending', 'active', 'completed', 'abandoned');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- Create games table
CREATE TABLE IF NOT EXISTS games (
id BIGSERIAL PRIMARY KEY,
player1_id BIGINT NOT NULL,
player2_id BIGINT NOT NULL,
player1_username VARCHAR(50) NOT NULL,
player2_username VARCHAR(50) NOT NULL,
board_size INT DEFAULT 15,
winner_id BIGINT,
game_state game_state_enum DEFAULT 'pending',
started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
completed_at TIMESTAMP WITH TIME ZONE,
FOREIGN KEY (player1_id) REFERENCES players(id),
FOREIGN KEY (player2_id) REFERENCES players(id),
FOREIGN KEY (winner_id) REFERENCES players(id)
);
-- Create game moves table
CREATE TABLE IF NOT EXISTS game_moves (
id BIGSERIAL PRIMARY KEY,
game_id BIGINT NOT NULL,
player_id BIGINT NOT NULL,
row_position INT NOT NULL,
col_position INT NOT NULL,
move_number INT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
FOREIGN KEY (game_id) REFERENCES games(id) ON DELETE CASCADE,
FOREIGN KEY (player_id) REFERENCES players(id)
);
CREATE INDEX IF NOT EXISTS idx_game ON game_moves(game_id);
-- Enable Row Level Security (RLS) - Optional but recommended
ALTER TABLE players ENABLE ROW LEVEL SECURITY;
ALTER TABLE active_sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE games ENABLE ROW LEVEL SECURITY;
ALTER TABLE game_moves ENABLE ROW LEVEL SECURITY;
-- Create policies to allow all operations (adjust based on your security needs)
CREATE POLICY "Allow all operations on players" ON players FOR ALL USING (true);
CREATE POLICY "Allow all operations on active_sessions" ON active_sessions FOR ALL USING (true);
CREATE POLICY "Allow all operations on games" ON games FOR ALL USING (true);
CREATE POLICY "Allow all operations on game_moves" ON game_moves FOR ALL USING (true);
Run the postgres-schema.sql file in your PostgreSQL database:
psql -h ${dbConfig.HOST} -U ${dbConfig.USER} -d ${dbConfig.DB} -f postgres-schema.sql
`);
throw new Error('Database tables not initialized. Please run the SQL above in Supabase SQL Editor.');
throw new Error('Database tables not initialized. Please run postgres-schema.sql first.');
}
console.log('✅ Database schema verified successfully');
@@ -115,25 +59,22 @@ const db = {
async createPlayer(username) {
try {
// First try to get existing player
const { data: existingPlayer, error: selectError } = await supabase
.from('players')
.select('id')
.eq('username', username)
.single();
const selectResult = await pool.query(
'SELECT id FROM players WHERE username = $1',
[username]
);
if (existingPlayer) {
return existingPlayer.id;
if (selectResult.rows.length > 0) {
return selectResult.rows[0].id;
}
// If not found, create new player
const { data, error } = await supabase
.from('players')
.insert([{ username }])
.select('id')
.single();
const insertResult = await pool.query(
'INSERT INTO players (username) VALUES ($1) RETURNING id',
[username]
);
if (error) throw error;
return data.id;
return insertResult.rows[0].id;
} catch (error) {
console.error('Error creating player:', error);
throw error;
@@ -142,160 +83,120 @@ const db = {
// Get player by username
async getPlayer(username) {
const { data, error } = await supabase
.from('players')
.select('*')
.eq('username', username)
.single();
const result = await pool.query(
'SELECT * FROM players WHERE username = $1',
[username]
);
if (error && error.code !== 'PGRST116') throw error; // PGRST116 = not found
return data;
return result.rows[0] || null;
},
// Get player by ID
async getPlayerById(playerId) {
const { data, error } = await supabase
.from('players')
.select('*')
.eq('id', playerId)
.single();
const result = await pool.query(
'SELECT * FROM players WHERE id = $1',
[playerId]
);
if (error && error.code !== 'PGRST116') throw error;
return data;
return result.rows[0] || null;
},
// Add active session
async addSession(sessionId, playerId, username) {
const { error } = await supabase
.from('active_sessions')
.upsert([{
session_id: sessionId,
player_id: playerId,
username: username,
last_heartbeat: new Date().toISOString()
}], {
onConflict: 'session_id'
});
if (error) throw error;
await pool.query(
`INSERT INTO active_sessions (session_id, player_id, username, last_heartbeat)
VALUES ($1, $2, $3, NOW())
ON CONFLICT (session_id)
DO UPDATE SET last_heartbeat = NOW()`,
[sessionId, playerId, username]
);
},
// Remove session
async removeSession(sessionId) {
const { error } = await supabase
.from('active_sessions')
.delete()
.eq('session_id', sessionId);
if (error) throw error;
await pool.query(
'DELETE FROM active_sessions WHERE session_id = $1',
[sessionId]
);
},
// Get all active players
async getActivePlayers() {
const twoMinutesAgo = new Date(Date.now() - 2 * 60 * 1000).toISOString();
const result = await pool.query(
`SELECT
s.session_id,
s.username,
p.total_wins,
p.total_losses,
p.total_draws
FROM active_sessions s
INNER JOIN players p ON s.player_id = p.id
WHERE s.last_heartbeat > NOW() - INTERVAL '2 minutes'`
);
const { data, error } = await supabase
.from('active_sessions')
.select(`
session_id,
username,
players!inner(total_wins, total_losses, total_draws)
`)
.gt('last_heartbeat', twoMinutesAgo);
if (error) throw error;
// Flatten the response to match the old format
return data.map(row => ({
session_id: row.session_id,
username: row.username,
total_wins: row.players.total_wins,
total_losses: row.players.total_losses,
total_draws: row.players.total_draws
}));
return result.rows;
},
// Create new game
async createGame(player1Id, player2Id, player1Username, player2Username, boardSize) {
const { data, error } = await supabase
.from('games')
.insert([{
player1_id: player1Id,
player2_id: player2Id,
player1_username: player1Username,
player2_username: player2Username,
board_size: boardSize,
game_state: 'active'
}])
.select('id')
.single();
const result = await pool.query(
`INSERT INTO games (player1_id, player2_id, player1_username, player2_username, board_size, game_state)
VALUES ($1, $2, $3, $4, $5, 'active')
RETURNING id`,
[player1Id, player2Id, player1Username, player2Username, boardSize]
);
if (error) throw error;
return data.id;
return result.rows[0].id;
},
// Record move
async recordMove(gameId, playerId, row, col, moveNumber) {
const { error } = await supabase
.from('game_moves')
.insert([{
game_id: gameId,
player_id: playerId,
row_position: row,
col_position: col,
move_number: moveNumber
}]);
if (error) throw error;
await pool.query(
`INSERT INTO game_moves (game_id, player_id, row_position, col_position, move_number)
VALUES ($1, $2, $3, $4, $5)`,
[gameId, playerId, row, col, moveNumber]
);
},
// Complete game
async completeGame(gameId, winnerId) {
// Update game status
const { error: gameError } = await supabase
.from('games')
.update({
game_state: 'completed',
winner_id: winnerId,
completed_at: new Date().toISOString()
})
.eq('id', gameId);
if (gameError) throw gameError;
await pool.query(
`UPDATE games
SET game_state = 'completed', winner_id = $1, completed_at = NOW()
WHERE id = $2`,
[winnerId, gameId]
);
// Update player stats
if (winnerId) {
// Get game details
const { data: game, error: selectError } = await supabase
.from('games')
.select('player1_id, player2_id')
.eq('id', gameId)
.single();
const gameResult = await pool.query(
'SELECT player1_id, player2_id FROM games WHERE id = $1',
[gameId]
);
if (selectError) throw selectError;
if (game) {
if (gameResult.rows.length > 0) {
const game = gameResult.rows[0];
const loserId = game.player1_id === winnerId ? game.player2_id : game.player1_id;
// Update winner
await supabase.rpc('increment_wins', { player_id: winnerId });
await pool.query('SELECT increment_wins($1)', [winnerId]);
// Update loser
await supabase.rpc('increment_losses', { player_id: loserId });
await pool.query('SELECT increment_losses($1)', [loserId]);
}
} else {
// Draw - update both players
const { data: game, error: selectError } = await supabase
.from('games')
.select('player1_id, player2_id')
.eq('id', gameId)
.single();
const gameResult = await pool.query(
'SELECT player1_id, player2_id FROM games WHERE id = $1',
[gameId]
);
if (selectError) throw selectError;
if (game) {
await supabase.rpc('increment_draws', { player_id: game.player1_id });
await supabase.rpc('increment_draws', { player_id: game.player2_id });
if (gameResult.rows.length > 0) {
const game = gameResult.rows[0];
await pool.query('SELECT increment_draws($1)', [game.player1_id]);
await pool.query('SELECT increment_draws($1)', [game.player2_id]);
}
}
},
@@ -303,56 +204,44 @@ const db = {
// Abandon game
async abandonGame(gameId, winnerId) {
// Update game status
const { error: gameError } = await supabase
.from('games')
.update({
game_state: 'abandoned',
winner_id: winnerId,
completed_at: new Date().toISOString()
})
.eq('id', gameId);
if (gameError) throw gameError;
await pool.query(
`UPDATE games
SET game_state = 'abandoned', winner_id = $1, completed_at = NOW()
WHERE id = $2`,
[winnerId, gameId]
);
// Update stats (winner gets win, other player gets loss)
if (winnerId) {
const { data: game, error: selectError } = await supabase
.from('games')
.select('player1_id, player2_id')
.eq('id', gameId)
.single();
const gameResult = await pool.query(
'SELECT player1_id, player2_id FROM games WHERE id = $1',
[gameId]
);
if (selectError) throw selectError;
if (game) {
if (gameResult.rows.length > 0) {
const game = gameResult.rows[0];
const loserId = game.player1_id === winnerId ? game.player2_id : game.player1_id;
await supabase.rpc('increment_wins', { player_id: winnerId });
await supabase.rpc('increment_losses', { player_id: loserId });
await pool.query('SELECT increment_wins($1)', [winnerId]);
await pool.query('SELECT increment_losses($1)', [loserId]);
}
}
},
// Update heartbeat
async updateHeartbeat(sessionId) {
const { error } = await supabase
.from('active_sessions')
.update({ last_heartbeat: new Date().toISOString() })
.eq('session_id', sessionId);
if (error) throw error;
await pool.query(
'UPDATE active_sessions SET last_heartbeat = NOW() WHERE session_id = $1',
[sessionId]
);
},
// Clean up stale sessions
async cleanupStaleSessions() {
const twoMinutesAgo = new Date(Date.now() - 2 * 60 * 1000).toISOString();
const { error } = await supabase
.from('active_sessions')
.delete()
.lt('last_heartbeat', twoMinutesAgo);
if (error) throw error;
await pool.query(
`DELETE FROM active_sessions
WHERE last_heartbeat < NOW() - INTERVAL '2 minutes'`
);
}
};
module.exports = { supabase, initializeDatabase, db };
module.exports = { pool, initializeDatabase, db };

View File

@@ -1,18 +1,19 @@
// Database Configuration File - EXAMPLE
// Copy this file to db.config.js and fill in your actual Supabase credentials
// Copy this file to db.config.js and fill in your actual PostgreSQL credentials
// DO NOT commit db.config.js to git - it's in .gitignore
// Supabase Configuration
// Get these values from your Supabase project dashboard:
// 1. Go to https://app.supabase.com
// 2. Select your project
// 3. Go to Project Settings → API
// PostgreSQL Configuration
// Update these values with your PostgreSQL database details
module.exports = {
supabaseUrl: 'https://xxxxxxxxxxxxx.supabase.co', // Your Supabase project URL
supabaseAnonKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', // Your Supabase anon/public key
supabasePassword: 'your_database_password_here', // Your database password
// Optional: Direct PostgreSQL connection string
// Found in Project Settings → Database → Connection String
postgresConnectionString: 'postgresql://postgres:your_password@db.xxxxxxxxxxxxx.supabase.co:5432/postgres'
HOST: "your-postgres-host", // e.g., 'localhost' or '202.171.184.108'
USER: "postgres", // PostgreSQL username
PASSWORD: "your-database-password", // Your database password
DB: "connect5", // Database name
dialect: "postgres",
pool: {
max: 5, // Maximum number of connections in pool
min: 0, // Minimum number of connections in pool
acquire: 30000, // Maximum time (ms) to try to get connection before throwing error
idle: 10000, // Maximum time (ms) a connection can be idle before being released
},
};

View File

@@ -6,7 +6,7 @@ set -e
echo "╔════════════════════════════════════════════════════════════╗"
echo "║ Connect-5 Production Deployment Script ║"
echo "║ Supabase + Node.js + Nginx/Apache ║"
echo "║ PostgreSQL + Node.js + Nginx/Apache ║"
echo "╚════════════════════════════════════════════════════════════╝"
echo ""
@@ -48,17 +48,20 @@ cd "$PROJECT_DIR"
echo -e "${GREEN}✅ Using project directory: $PROJECT_DIR${NC}"
echo ""
# Get Supabase credentials
echo -e "${BLUE}🔐 Supabase Configuration${NC}"
# Get PostgreSQL credentials
echo -e "${BLUE}🔐 PostgreSQL Configuration${NC}"
echo ""
read -p "Supabase URL: " SUPABASE_URL
read -p "Supabase Anon Key: " SUPABASE_KEY
read -s -p "Supabase Password: " SUPABASE_PASSWORD
read -p "PostgreSQL Host: " PG_HOST
read -p "PostgreSQL User [postgres]: " PG_USER
PG_USER=${PG_USER:-postgres}
read -s -p "PostgreSQL Password: " PG_PASSWORD
echo ""
read -p "Database Name [connect5]: " PG_DB
PG_DB=${PG_DB:-connect5}
echo ""
if [ -z "$SUPABASE_URL" ] || [ -z "$SUPABASE_KEY" ]; then
echo -e "${RED}Supabase credentials are required${NC}"
if [ -z "$PG_HOST" ] || [ -z "$PG_PASSWORD" ]; then
echo -e "${RED}PostgreSQL host and password are required${NC}"
exit 1
fi
@@ -66,13 +69,17 @@ fi
echo -e "${BLUE}📝 Creating db.config.js...${NC}"
cat > "$PROJECT_DIR/db.config.js" << EOF
module.exports = {
// Supabase Configuration
supabaseUrl: '$SUPABASE_URL',
supabaseAnonKey: '$SUPABASE_KEY',
supabasePassword: '$SUPABASE_PASSWORD',
// PostgreSQL Connection String (optional, for direct connections)
postgresConnectionString: 'postgresql://postgres:$SUPABASE_PASSWORD@db.${SUPABASE_URL#https://}.supabase.co:5432/postgres'
HOST: '$PG_HOST',
USER: '$PG_USER',
PASSWORD: '$PG_PASSWORD',
DB: '$PG_DB',
dialect: 'postgres',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
};
EOF
echo -e "${GREEN}✅ db.config.js created${NC}"
@@ -240,7 +247,7 @@ echo "║ Deployment Complete! ║"
echo "╚════════════════════════════════════════════════════════════╝"
echo ""
echo -e "${GREEN}✅ Project Directory:${NC} $PROJECT_DIR"
echo -e "${GREEN}✅ Database:${NC} Supabase PostgreSQL"
echo -e "${GREEN}✅ Database:${NC} PostgreSQL"
echo -e "${GREEN}✅ Web Server:${NC} $WEB_SERVER"
echo -e "${GREEN}✅ Node.js:${NC} Running on port 3000"
echo ""
@@ -255,6 +262,6 @@ echo " Web Server: journalctl -u $WEB_SERVER -f"
echo ""
echo "🔧 Troubleshooting:"
echo " - If API returns 404, check web server proxy configuration"
echo " - If database disconnected, verify Supabase credentials"
echo " - If database disconnected, verify PostgreSQL credentials"
echo " - See DEPLOYMENT.md for detailed instructions"
echo ""

388
node_modules/.package-lock.json generated vendored
View File

@@ -10,107 +10,6 @@
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
},
"node_modules/@supabase/auth-js": {
"version": "2.89.0",
"resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.89.0.tgz",
"integrity": "sha512-wiWZdz8WMad8LQdJMWYDZ2SJtZP5MwMqzQq3ehtW2ngiI3UTgbKiFrvMUUS3KADiVlk4LiGfODB2mrYx7w2f8w==",
"license": "MIT",
"dependencies": {
"tslib": "2.8.1"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@supabase/functions-js": {
"version": "2.89.0",
"resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.89.0.tgz",
"integrity": "sha512-XEueaC5gMe5NufNYfBh9kPwJlP5M2f+Ogr8rvhmRDAZNHgY6mI35RCkYDijd92pMcNM7g8pUUJov93UGUnqfyw==",
"license": "MIT",
"dependencies": {
"tslib": "2.8.1"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@supabase/postgrest-js": {
"version": "2.89.0",
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.89.0.tgz",
"integrity": "sha512-/b0fKrxV9i7RNOEXMno/I1862RsYhuUo+Q6m6z3ar1f4ulTMXnDfv0y4YYxK2POcgrOXQOgKYQx1eArybyNvtg==",
"license": "MIT",
"dependencies": {
"tslib": "2.8.1"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@supabase/realtime-js": {
"version": "2.89.0",
"resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.89.0.tgz",
"integrity": "sha512-aMOvfDb2a52u6PX6jrrjvACHXGV3zsOlWRzZsTIOAJa0hOVvRp01AwC1+nLTGUzxzezejrYeCX+KnnM1xHdl+w==",
"license": "MIT",
"dependencies": {
"@types/phoenix": "^1.6.6",
"@types/ws": "^8.18.1",
"tslib": "2.8.1",
"ws": "^8.18.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@supabase/realtime-js/node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/@supabase/storage-js": {
"version": "2.89.0",
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.89.0.tgz",
"integrity": "sha512-6zKcXofk/M/4Eato7iqpRh+B+vnxeiTumCIP+Tz26xEqIiywzD9JxHq+udRrDuv6hXE+pmetvJd8n5wcf4MFRQ==",
"license": "MIT",
"dependencies": {
"iceberg-js": "^0.8.1",
"tslib": "2.8.1"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@supabase/supabase-js": {
"version": "2.89.0",
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.89.0.tgz",
"integrity": "sha512-KlaRwSfFA0fD73PYVMHj5/iXFtQGCcX7PSx0FdQwYEEw9b2wqM7GxadY+5YwcmuEhalmjFB/YvqaoNVF+sWUlg==",
"license": "MIT",
"dependencies": {
"@supabase/auth-js": "2.89.0",
"@supabase/functions-js": "2.89.0",
"@supabase/postgrest-js": "2.89.0",
"@supabase/realtime-js": "2.89.0",
"@supabase/storage-js": "2.89.0"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@types/cors": {
"version": "2.8.19",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
@@ -129,21 +28,6 @@
"undici-types": "~7.16.0"
}
},
"node_modules/@types/phoenix": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz",
"integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==",
"license": "MIT"
},
"node_modules/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -177,15 +61,6 @@
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
"node_modules/aws-ssl-profiles": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
"license": "MIT",
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/bad-words": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/bad-words/-/bad-words-3.0.4.tgz",
@@ -409,15 +284,6 @@
"ms": "2.0.0"
}
},
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -667,15 +533,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/generate-function": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
"license": "MIT",
"dependencies": {
"is-property": "^1.0.2"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -792,15 +649,6 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/iceberg-js": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz",
"integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==",
"license": "MIT",
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -881,33 +729,6 @@
"node": ">=0.12.0"
}
},
"node_modules/is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
"license": "MIT"
},
"node_modules/long": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
"license": "Apache-2.0"
},
"node_modules/lru.min": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.3.tgz",
"integrity": "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q==",
"license": "MIT",
"engines": {
"bun": ">=1.0.0",
"deno": ">=1.30.0",
"node": ">=8.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wellwelwel"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -996,54 +817,6 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/mysql2": {
"version": "3.15.3",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz",
"integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==",
"license": "MIT",
"dependencies": {
"aws-ssl-profiles": "^1.1.1",
"denque": "^2.1.0",
"generate-function": "^2.3.1",
"iconv-lite": "^0.7.0",
"long": "^5.2.1",
"lru.min": "^1.0.0",
"named-placeholders": "^1.1.3",
"seq-queue": "^0.0.5",
"sqlstring": "^2.3.2"
},
"engines": {
"node": ">= 8.0"
}
},
"node_modules/mysql2/node_modules/iconv-lite": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz",
"integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/named-placeholders": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.4.tgz",
"integrity": "sha512-/qfG0Kk/bLJIvej4FcPQ2KYUJP8iQdU1CTxysNb/U2wUNb+/4K485yeio8iNoiwfqJnsTInXoRPTza0dZWHVJQ==",
"license": "MIT",
"dependencies": {
"lru.min": "^1.1.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -1165,6 +938,96 @@
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT"
},
"node_modules/pg": {
"version": "8.16.3",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
"license": "MIT",
"peer": true,
"dependencies": {
"pg-connection-string": "^2.9.1",
"pg-pool": "^3.10.1",
"pg-protocol": "^1.10.3",
"pg-types": "2.2.0",
"pgpass": "1.0.5"
},
"engines": {
"node": ">= 16.0.0"
},
"optionalDependencies": {
"pg-cloudflare": "^1.2.7"
},
"peerDependencies": {
"pg-native": ">=3.0.1"
},
"peerDependenciesMeta": {
"pg-native": {
"optional": true
}
}
},
"node_modules/pg-cloudflare": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz",
"integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==",
"license": "MIT",
"optional": true
},
"node_modules/pg-connection-string": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz",
"integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==",
"license": "MIT"
},
"node_modules/pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
"license": "ISC",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/pg-pool": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz",
"integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==",
"license": "MIT",
"peerDependencies": {
"pg": ">=8.0"
}
},
"node_modules/pg-protocol": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz",
"integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==",
"license": "MIT"
},
"node_modules/pg-types": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"license": "MIT",
"dependencies": {
"pg-int8": "1.0.1",
"postgres-array": "~2.0.0",
"postgres-bytea": "~1.0.0",
"postgres-date": "~1.0.4",
"postgres-interval": "^1.1.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pgpass": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
"license": "MIT",
"dependencies": {
"split2": "^4.1.0"
}
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -1178,6 +1041,45 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/postgres-bytea": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz",
"integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-date": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-interval": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
"license": "MIT",
"dependencies": {
"xtend": "^4.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -1344,11 +1246,6 @@
"node": ">= 0.8"
}
},
"node_modules/seq-queue": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
},
"node_modules/serve-static": {
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
@@ -1629,13 +1526,13 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/sqlstring": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
"license": "MIT",
"node_modules/split2": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
"license": "ISC",
"engines": {
"node": ">= 0.6"
"node": ">= 10.x"
}
},
"node_modules/statuses": {
@@ -1692,12 +1589,6 @@
"nodetouch": "bin/nodetouch.js"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@@ -1771,6 +1662,15 @@
"optional": true
}
}
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"license": "MIT",
"engines": {
"node": ">=0.4"
}
}
}
}

View File

@@ -1,19 +0,0 @@
Copyright (c) 2024 Andrey Sidorov, Douglas Wilson, Weslley Araújo and contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,146 +0,0 @@
# AWS SSL Profiles
[**AWS RDS**](https://aws.amazon.com/rds/) **SSL** Certificates Bundles.
**Table of Contents**
- [Installation](#installation)
- [Usage](#usage)
- [**mysqljs/mysql**](#mysqljsmysql)
- [**MySQL2**](#mysql2)
- [**node-postgres**](#node-postgres)
- [Custom `ssl` options](#custom-ssl-options)
- [License](#license)
- [Security](#security)
- [Contributing](#contributing)
- [Acknowledgements](#acknowledgements)
---
## Installation
```bash
npm install --save aws-ssl-profiles
```
---
## Usage
### [mysqljs/mysql](https://github.com/mysqljs/mysql)
```js
const mysql = require('mysql');
const awsCaBundle = require('aws-ssl-profiles');
// mysql connection
const connection = mysql.createConnection({
//...
ssl: awsCaBundle,
});
// mysql connection pool
const pool = mysql.createPool({
//...
ssl: awsCaBundle,
});
```
### [MySQL2](https://github.com/sidorares/node-mysql2)
```js
const mysql = require('mysql2');
const awsCaBundle = require('aws-ssl-profiles');
// mysql2 connection
const connection = mysql.createConnection({
//...
ssl: awsCaBundle,
});
// mysql2 connection pool
const pool = mysql.createPool({
//...
ssl: awsCaBundle,
});
```
### [node-postgres](https://github.com/brianc/node-postgres)
```js
const pg = require('pg');
const awsCaBundle = require('aws-ssl-profiles');
// pg connection
const client = new pg.Client({
// ...
ssl: awsCaBundle,
});
// pg connection pool
const pool = new pg.Pool({
// ...
ssl: awsCaBundle,
});
```
### Custom `ssl` options
Using **AWS SSL Profiles** with custom `ssl` options:
```js
{
// ...
ssl: {
...awsCaBundle,
rejectUnauthorized: true,
// ...
}
}
```
```js
{
// ...
ssl: {
ca: awsCaBundle.ca,
rejectUnauthorized: true,
// ...
}
}
```
### Custom bundles
```js
const { proxyBundle } = require('aws-ssl-profiles');
{
// ...
ssl: proxyBundle,
}
```
---
## License
**AWS SSL Profiles** is under the [**MIT License**](./LICENSE).
---
## Security
Please check the [**SECURITY.md**](./SECURITY.md).
---
## Contributing
Please check the [**CONTRIBUTING.md**](./CONTRIBUTING.md) for instructions.
---
## Acknowledgements
[**Contributors**](https://github.com/mysqljs/aws-ssl-profiles/graphs/contributors).

View File

@@ -1,4 +0,0 @@
export type CA = string[];
export type Profiles = {
ca: CA;
};

View File

@@ -1,2 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -1,8 +0,0 @@
import type { Profiles } from "./@types/profiles.js";
export declare const proxyBundle: Profiles;
declare const profiles: Profiles;
declare module "aws-ssl-profiles" {
const profiles: Profiles & { proxyBundle: Profiles };
export = profiles;
}
export default profiles;

View File

@@ -1,13 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const defaults_js_1 = require("./profiles/ca/defaults.js");
const proxies_js_1 = require("./profiles/ca/proxies.js");
const proxyBundle = {
ca: proxies_js_1.proxies,
};
const profiles = {
ca: [...defaults_js_1.defaults, ...proxies_js_1.proxies],
};
module.exports = profiles;
module.exports.proxyBundle = proxyBundle;
module.exports.default = profiles;

View File

@@ -1,9 +0,0 @@
import type { CA } from '../../@types/profiles.js';
/**
* CA Certificates for **Amazon RDS** (2024)
*
* - https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html
* - https://docs.amazonaws.cn/en_us/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.SSL.html
* - https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.html#aurora-serverless.tls
*/
export declare const defaults: CA;

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
import type { CA } from '../../@types/profiles.js';
/**
* CA Certificates for **Amazon RDS Proxy** (2024)
*
* - https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.howitworks.html#rds-proxy-security.tls
* - https://www.amazontrust.com/repository/
*/
export declare const proxies: CA;

View File

@@ -1,111 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.proxies = void 0;
/**
* CA Certificates for **Amazon RDS Proxy** (2024)
*
* - https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.howitworks.html#rds-proxy-security.tls
* - https://www.amazontrust.com/repository/
*/
exports.proxies = [
'-----BEGIN CERTIFICATE-----\n' +
'MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n' +
'ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n' +
'b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n' +
'MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n' +
'b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n' +
'ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n' +
'9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n' +
'IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n' +
'VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n' +
'93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n' +
'jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n' +
'AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n' +
'A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n' +
'U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n' +
'N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n' +
'o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n' +
'5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n' +
'rqXRfboQnoZsG4q5WTP468SQvvG5\n' +
'-----END CERTIFICATE-----\n',
'-----BEGIN CERTIFICATE-----\n' +
'MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF\n' +
'ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n' +
'b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL\n' +
'MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n' +
'b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK\n' +
'gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ\n' +
'W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg\n' +
'1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K\n' +
'8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r\n' +
'2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me\n' +
'z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR\n' +
'8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj\n' +
'mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz\n' +
'7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6\n' +
'+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI\n' +
'0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB\n' +
'Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm\n' +
'UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2\n' +
'LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY\n' +
'+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS\n' +
'k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl\n' +
'7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm\n' +
'btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl\n' +
'urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+\n' +
'fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63\n' +
'n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE\n' +
'76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H\n' +
'9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT\n' +
'4PsJYGw=\n' +
'-----END CERTIFICATE-----\n',
'-----BEGIN CERTIFICATE-----\n' +
'MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5\n' +
'MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n' +
'Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG\n' +
'A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg\n' +
'Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl\n' +
'ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j\n' +
'QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr\n' +
'ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr\n' +
'BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM\n' +
'YyRIHN8wfdVoOw==\n' +
'-----END CERTIFICATE-----\n',
'-----BEGIN CERTIFICATE-----\n' +
'MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5\n' +
'MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n' +
'Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG\n' +
'A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg\n' +
'Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi\n' +
'9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk\n' +
'M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB\n' +
'/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB\n' +
'MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw\n' +
'CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW\n' +
'1KyLa2tJElMzrdfkviT8tQp21KW8EA==\n' +
'-----END CERTIFICATE-----\n',
'-----BEGIN CERTIFICATE-----\n' +
'MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx\n' +
'EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n' +
'HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs\n' +
'ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5\n' +
'MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD\n' +
'VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy\n' +
'ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy\n' +
'dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI\n' +
'hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p\n' +
'OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2\n' +
'8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K\n' +
'Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe\n' +
'hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk\n' +
'6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw\n' +
'DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q\n' +
'AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI\n' +
'bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB\n' +
've6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z\n' +
'qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd\n' +
'iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn\n' +
'0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN\n' +
'sSi6\n' +
'-----END CERTIFICATE-----\n',
];

View File

@@ -1,52 +0,0 @@
{
"name": "aws-ssl-profiles",
"version": "1.1.2",
"main": "lib/index.js",
"author": "https://github.com/wellwelwel",
"description": "AWS RDS SSL certificates bundles.",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/mysqljs/aws-ssl-profiles"
},
"bugs": {
"url": "https://github.com/mysqljs/aws-ssl-profiles/issues"
},
"devDependencies": {
"@biomejs/biome": "^1.8.3",
"@types/node": "^22.5.1",
"@types/x509.js": "^1.0.3",
"poku": "^2.5.0",
"prettier": "^3.3.3",
"tsx": "^4.19.0",
"typescript": "^5.5.4",
"x509.js": "^1.0.0"
},
"files": [
"lib"
],
"engines": {
"node": ">= 6.0.0"
},
"keywords": [
"mysql",
"mysql2",
"pg",
"postgres",
"aws",
"rds",
"ssl",
"certificates",
"ca",
"bundle"
],
"scripts": {
"build": "npx tsc",
"postbuild": "cp src/index.d.ts lib/index.d.ts",
"lint": "npx @biomejs/biome lint && prettier --check .",
"lint:fix": "npx @biomejs/biome lint --write . && prettier --write .",
"pretest": "npm run build",
"test": "poku --parallel ./test",
"test:ci": "npm run lint && npm run test"
}
}

29
node_modules/denque/CHANGELOG.md generated vendored
View File

@@ -1,29 +0,0 @@
## 2.1.0
- fix: issue where `clear()` is still keeping references to the elements (#47)
- refactor: performance optimizations for growth and array copy (#43)
- refactor: performance optimizations for toArray and fromArray (#46)
- test: add additional benchmarks for queue growth and `toArray` (#45)
## 2.0.1
- fix(types): incorrect return type on `size()`
## 2.0.0
- fix!: `push` & `unshift` now accept `undefined` values to match behaviour of `Array` (fixes #25) (#35)
- This is only a **BREAKING** change if you are currently expecting `push(undefined)` and `unshift(undefined)` to do
nothing - the new behaviour now correctly adds undefined values to the queue.
- **Note**: behaviour of `push()` & `unshift()` (no arguments) remains unchanged (nothing gets added to the queue).
- **Note**: If you need to differentiate between `undefined` values in the queue and the return value of `pop()` then
check the queue `.length` before popping.
- fix: incorrect methods in types definition file
## 1.5.1
- perf: minor performance tweak when growing queue size (#29)
## 1.5.0
- feat: adds capacity option for circular buffers (#27)

201
node_modules/denque/LICENSE generated vendored
View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018-present Invertase Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

77
node_modules/denque/README.md generated vendored
View File

@@ -1,77 +0,0 @@
<p align="center">
<h1 align="center">Denque</h1>
</p>
<p align="center">
<a href="https://www.npmjs.com/package/denque"><img src="https://img.shields.io/npm/dm/denque.svg?style=flat-square" alt="NPM downloads"></a>
<a href="https://www.npmjs.com/package/denque"><img src="https://img.shields.io/npm/v/denque.svg?style=flat-square" alt="NPM version"></a>
<a href="https://github.com/invertase/denque/actions/workflows/testing.yam"><img src="https://github.com/invertase/denque/actions/workflows/testing.yaml/badge.svg" alt="Tests status"></a>
<a href="https://codecov.io/gh/invertase/denque"><img src="https://codecov.io/gh/invertase/denque/branch/master/graph/badge.svg?token=rn91iI4bSe" alt="Coverage"></a>
<a href="/LICENSE"><img src="https://img.shields.io/npm/l/denque.svg?style=flat-square" alt="License"></a>
<a href="https://twitter.com/invertaseio"><img src="https://img.shields.io/twitter/follow/invertaseio.svg?style=social&label=Follow" alt="Follow on Twitter"></a>
</p>
Denque is a well tested, extremely fast and lightweight [double-ended queue](http://en.wikipedia.org/wiki/Double-ended_queue)
implementation with zero dependencies and includes TypeScript types.
Double-ended queues can also be used as a:
- [Stack](http://en.wikipedia.org/wiki/Stack_\(abstract_data_type\))
- [Queue](http://en.wikipedia.org/wiki/Queue_\(data_structure\))
This implementation is currently the fastest available, even faster than `double-ended-queue`, see the [benchmarks](https://docs.page/invertase/denque/benchmarks).
Every queue operation is done at a constant `O(1)` - including random access from `.peekAt(index)`.
**Works on all node versions >= v0.10**
## Quick Start
Install the package:
```bash
npm install denque
```
Create and consume a queue:
```js
const Denque = require("denque");
const denque = new Denque([1,2,3,4]);
denque.shift(); // 1
denque.pop(); // 4
```
See the [API reference documentation](https://docs.page/invertase/denque/api) for more examples.
---
## Who's using it?
- [Kafka Node.js client](https://www.npmjs.com/package/kafka-node)
- [MariaDB Node.js client](https://www.npmjs.com/package/mariadb)
- [MongoDB Node.js client](https://www.npmjs.com/package/mongodb)
- [MySQL Node.js client](https://www.npmjs.com/package/mysql2)
- [Redis Node.js clients](https://www.npmjs.com/package/redis)
... and [many more](https://www.npmjs.com/browse/depended/denque).
---
## License
- See [LICENSE](/LICENSE)
---
<p align="center">
<a href="https://invertase.io/?utm_source=readme&utm_medium=footer&utm_campaign=denque">
<img width="75px" src="https://static.invertase.io/assets/invertase/invertase-rounded-avatar.png">
</a>
<p align="center">
Built and maintained by <a href="https://invertase.io/?utm_source=readme&utm_medium=footer&utm_campaign=denque">Invertase</a>.
</p>
</p>

47
node_modules/denque/index.d.ts generated vendored
View File

@@ -1,47 +0,0 @@
declare class Denque<T = any> {
length: number;
constructor();
constructor(array: T[]);
constructor(array: T[], options: IDenqueOptions);
push(item: T): number;
unshift(item: T): number;
pop(): T | undefined;
shift(): T | undefined;
peekBack(): T | undefined;
peekFront(): T | undefined;
peekAt(index: number): T | undefined;
get(index: number): T | undefined;
remove(index: number, count: number): T[];
removeOne(index: number): T | undefined;
splice(index: number, count: number, ...item: T[]): T[] | undefined;
isEmpty(): boolean;
clear(): void;
size(): number;
toString(): string;
toArray(): T[];
}
interface IDenqueOptions {
capacity?: number
}
export = Denque;

481
node_modules/denque/index.js generated vendored
View File

@@ -1,481 +0,0 @@
'use strict';
/**
* Custom implementation of a double ended queue.
*/
function Denque(array, options) {
var options = options || {};
this._capacity = options.capacity;
this._head = 0;
this._tail = 0;
if (Array.isArray(array)) {
this._fromArray(array);
} else {
this._capacityMask = 0x3;
this._list = new Array(4);
}
}
/**
* --------------
* PUBLIC API
* -------------
*/
/**
* Returns the item at the specified index from the list.
* 0 is the first element, 1 is the second, and so on...
* Elements at negative values are that many from the end: -1 is one before the end
* (the last element), -2 is two before the end (one before last), etc.
* @param index
* @returns {*}
*/
Denque.prototype.peekAt = function peekAt(index) {
var i = index;
// expect a number or return undefined
if ((i !== (i | 0))) {
return void 0;
}
var len = this.size();
if (i >= len || i < -len) return undefined;
if (i < 0) i += len;
i = (this._head + i) & this._capacityMask;
return this._list[i];
};
/**
* Alias for peekAt()
* @param i
* @returns {*}
*/
Denque.prototype.get = function get(i) {
return this.peekAt(i);
};
/**
* Returns the first item in the list without removing it.
* @returns {*}
*/
Denque.prototype.peek = function peek() {
if (this._head === this._tail) return undefined;
return this._list[this._head];
};
/**
* Alias for peek()
* @returns {*}
*/
Denque.prototype.peekFront = function peekFront() {
return this.peek();
};
/**
* Returns the item that is at the back of the queue without removing it.
* Uses peekAt(-1)
*/
Denque.prototype.peekBack = function peekBack() {
return this.peekAt(-1);
};
/**
* Returns the current length of the queue
* @return {Number}
*/
Object.defineProperty(Denque.prototype, 'length', {
get: function length() {
return this.size();
}
});
/**
* Return the number of items on the list, or 0 if empty.
* @returns {number}
*/
Denque.prototype.size = function size() {
if (this._head === this._tail) return 0;
if (this._head < this._tail) return this._tail - this._head;
else return this._capacityMask + 1 - (this._head - this._tail);
};
/**
* Add an item at the beginning of the list.
* @param item
*/
Denque.prototype.unshift = function unshift(item) {
if (arguments.length === 0) return this.size();
var len = this._list.length;
this._head = (this._head - 1 + len) & this._capacityMask;
this._list[this._head] = item;
if (this._tail === this._head) this._growArray();
if (this._capacity && this.size() > this._capacity) this.pop();
if (this._head < this._tail) return this._tail - this._head;
else return this._capacityMask + 1 - (this._head - this._tail);
};
/**
* Remove and return the first item on the list,
* Returns undefined if the list is empty.
* @returns {*}
*/
Denque.prototype.shift = function shift() {
var head = this._head;
if (head === this._tail) return undefined;
var item = this._list[head];
this._list[head] = undefined;
this._head = (head + 1) & this._capacityMask;
if (head < 2 && this._tail > 10000 && this._tail <= this._list.length >>> 2) this._shrinkArray();
return item;
};
/**
* Add an item to the bottom of the list.
* @param item
*/
Denque.prototype.push = function push(item) {
if (arguments.length === 0) return this.size();
var tail = this._tail;
this._list[tail] = item;
this._tail = (tail + 1) & this._capacityMask;
if (this._tail === this._head) {
this._growArray();
}
if (this._capacity && this.size() > this._capacity) {
this.shift();
}
if (this._head < this._tail) return this._tail - this._head;
else return this._capacityMask + 1 - (this._head - this._tail);
};
/**
* Remove and return the last item on the list.
* Returns undefined if the list is empty.
* @returns {*}
*/
Denque.prototype.pop = function pop() {
var tail = this._tail;
if (tail === this._head) return undefined;
var len = this._list.length;
this._tail = (tail - 1 + len) & this._capacityMask;
var item = this._list[this._tail];
this._list[this._tail] = undefined;
if (this._head < 2 && tail > 10000 && tail <= len >>> 2) this._shrinkArray();
return item;
};
/**
* Remove and return the item at the specified index from the list.
* Returns undefined if the list is empty.
* @param index
* @returns {*}
*/
Denque.prototype.removeOne = function removeOne(index) {
var i = index;
// expect a number or return undefined
if ((i !== (i | 0))) {
return void 0;
}
if (this._head === this._tail) return void 0;
var size = this.size();
var len = this._list.length;
if (i >= size || i < -size) return void 0;
if (i < 0) i += size;
i = (this._head + i) & this._capacityMask;
var item = this._list[i];
var k;
if (index < size / 2) {
for (k = index; k > 0; k--) {
this._list[i] = this._list[i = (i - 1 + len) & this._capacityMask];
}
this._list[i] = void 0;
this._head = (this._head + 1 + len) & this._capacityMask;
} else {
for (k = size - 1 - index; k > 0; k--) {
this._list[i] = this._list[i = (i + 1 + len) & this._capacityMask];
}
this._list[i] = void 0;
this._tail = (this._tail - 1 + len) & this._capacityMask;
}
return item;
};
/**
* Remove number of items from the specified index from the list.
* Returns array of removed items.
* Returns undefined if the list is empty.
* @param index
* @param count
* @returns {array}
*/
Denque.prototype.remove = function remove(index, count) {
var i = index;
var removed;
var del_count = count;
// expect a number or return undefined
if ((i !== (i | 0))) {
return void 0;
}
if (this._head === this._tail) return void 0;
var size = this.size();
var len = this._list.length;
if (i >= size || i < -size || count < 1) return void 0;
if (i < 0) i += size;
if (count === 1 || !count) {
removed = new Array(1);
removed[0] = this.removeOne(i);
return removed;
}
if (i === 0 && i + count >= size) {
removed = this.toArray();
this.clear();
return removed;
}
if (i + count > size) count = size - i;
var k;
removed = new Array(count);
for (k = 0; k < count; k++) {
removed[k] = this._list[(this._head + i + k) & this._capacityMask];
}
i = (this._head + i) & this._capacityMask;
if (index + count === size) {
this._tail = (this._tail - count + len) & this._capacityMask;
for (k = count; k > 0; k--) {
this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
}
return removed;
}
if (index === 0) {
this._head = (this._head + count + len) & this._capacityMask;
for (k = count - 1; k > 0; k--) {
this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
}
return removed;
}
if (i < size / 2) {
this._head = (this._head + index + count + len) & this._capacityMask;
for (k = index; k > 0; k--) {
this.unshift(this._list[i = (i - 1 + len) & this._capacityMask]);
}
i = (this._head - 1 + len) & this._capacityMask;
while (del_count > 0) {
this._list[i = (i - 1 + len) & this._capacityMask] = void 0;
del_count--;
}
if (index < 0) this._tail = i;
} else {
this._tail = i;
i = (i + count + len) & this._capacityMask;
for (k = size - (count + index); k > 0; k--) {
this.push(this._list[i++]);
}
i = this._tail;
while (del_count > 0) {
this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
del_count--;
}
}
if (this._head < 2 && this._tail > 10000 && this._tail <= len >>> 2) this._shrinkArray();
return removed;
};
/**
* Native splice implementation.
* Remove number of items from the specified index from the list and/or add new elements.
* Returns array of removed items or empty array if count == 0.
* Returns undefined if the list is empty.
*
* @param index
* @param count
* @param {...*} [elements]
* @returns {array}
*/
Denque.prototype.splice = function splice(index, count) {
var i = index;
// expect a number or return undefined
if ((i !== (i | 0))) {
return void 0;
}
var size = this.size();
if (i < 0) i += size;
if (i > size) return void 0;
if (arguments.length > 2) {
var k;
var temp;
var removed;
var arg_len = arguments.length;
var len = this._list.length;
var arguments_index = 2;
if (!size || i < size / 2) {
temp = new Array(i);
for (k = 0; k < i; k++) {
temp[k] = this._list[(this._head + k) & this._capacityMask];
}
if (count === 0) {
removed = [];
if (i > 0) {
this._head = (this._head + i + len) & this._capacityMask;
}
} else {
removed = this.remove(i, count);
this._head = (this._head + i + len) & this._capacityMask;
}
while (arg_len > arguments_index) {
this.unshift(arguments[--arg_len]);
}
for (k = i; k > 0; k--) {
this.unshift(temp[k - 1]);
}
} else {
temp = new Array(size - (i + count));
var leng = temp.length;
for (k = 0; k < leng; k++) {
temp[k] = this._list[(this._head + i + count + k) & this._capacityMask];
}
if (count === 0) {
removed = [];
if (i != size) {
this._tail = (this._head + i + len) & this._capacityMask;
}
} else {
removed = this.remove(i, count);
this._tail = (this._tail - leng + len) & this._capacityMask;
}
while (arguments_index < arg_len) {
this.push(arguments[arguments_index++]);
}
for (k = 0; k < leng; k++) {
this.push(temp[k]);
}
}
return removed;
} else {
return this.remove(i, count);
}
};
/**
* Soft clear - does not reset capacity.
*/
Denque.prototype.clear = function clear() {
this._list = new Array(this._list.length);
this._head = 0;
this._tail = 0;
};
/**
* Returns true or false whether the list is empty.
* @returns {boolean}
*/
Denque.prototype.isEmpty = function isEmpty() {
return this._head === this._tail;
};
/**
* Returns an array of all queue items.
* @returns {Array}
*/
Denque.prototype.toArray = function toArray() {
return this._copyArray(false);
};
/**
* -------------
* INTERNALS
* -------------
*/
/**
* Fills the queue with items from an array
* For use in the constructor
* @param array
* @private
*/
Denque.prototype._fromArray = function _fromArray(array) {
var length = array.length;
var capacity = this._nextPowerOf2(length);
this._list = new Array(capacity);
this._capacityMask = capacity - 1;
this._tail = length;
for (var i = 0; i < length; i++) this._list[i] = array[i];
};
/**
*
* @param fullCopy
* @param size Initialize the array with a specific size. Will default to the current list size
* @returns {Array}
* @private
*/
Denque.prototype._copyArray = function _copyArray(fullCopy, size) {
var src = this._list;
var capacity = src.length;
var length = this.length;
size = size | length;
// No prealloc requested and the buffer is contiguous
if (size == length && this._head < this._tail) {
// Simply do a fast slice copy
return this._list.slice(this._head, this._tail);
}
var dest = new Array(size);
var k = 0;
var i;
if (fullCopy || this._head > this._tail) {
for (i = this._head; i < capacity; i++) dest[k++] = src[i];
for (i = 0; i < this._tail; i++) dest[k++] = src[i];
} else {
for (i = this._head; i < this._tail; i++) dest[k++] = src[i];
}
return dest;
}
/**
* Grows the internal list array.
* @private
*/
Denque.prototype._growArray = function _growArray() {
if (this._head != 0) {
// double array size and copy existing data, head to end, then beginning to tail.
var newList = this._copyArray(true, this._list.length << 1);
this._tail = this._list.length;
this._head = 0;
this._list = newList;
} else {
this._tail = this._list.length;
this._list.length <<= 1;
}
this._capacityMask = (this._capacityMask << 1) | 1;
};
/**
* Shrinks the internal list array.
* @private
*/
Denque.prototype._shrinkArray = function _shrinkArray() {
this._list.length >>>= 1;
this._capacityMask >>>= 1;
};
/**
* Find the next power of 2, at least 4
* @private
* @param {number} num
* @returns {number}
*/
Denque.prototype._nextPowerOf2 = function _nextPowerOf2(num) {
var log2 = Math.log(num) / Math.log(2);
var nextPow2 = 1 << (log2 + 1);
return Math.max(nextPow2, 4);
}
module.exports = Denque;

58
node_modules/denque/package.json generated vendored
View File

@@ -1,58 +0,0 @@
{
"name": "denque",
"version": "2.1.0",
"description": "The fastest javascript implementation of a double-ended queue. Used by the official Redis, MongoDB, MariaDB & MySQL libraries for Node.js and many other libraries. Maintains compatability with deque.",
"main": "index.js",
"engines": {
"node": ">=0.10"
},
"keywords": [
"data-structure",
"data-structures",
"queue",
"double",
"end",
"ended",
"deque",
"denque",
"double-ended-queue"
],
"scripts": {
"test": "istanbul cover --report lcov _mocha && npm run typescript",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"typescript": "tsc --project ./test/type/tsconfig.json",
"benchmark_thousand": "node benchmark/thousand",
"benchmark_2mil": "node benchmark/two_million",
"benchmark_splice": "node benchmark/splice",
"benchmark_remove": "node benchmark/remove",
"benchmark_removeOne": "node benchmark/removeOne",
"benchmark_growth": "node benchmark/growth",
"benchmark_toArray": "node benchmark/toArray",
"benchmark_fromArray": "node benchmark/fromArray"
},
"repository": {
"type": "git",
"url": "git+https://github.com/invertase/denque.git"
},
"license": "Apache-2.0",
"author": {
"name": "Invertase",
"email": "oss@invertase.io",
"url": "http://github.com/invertase/"
},
"contributors": [
"Mike Diarmid (Salakar) <mike@invertase.io>"
],
"bugs": {
"url": "https://github.com/invertase/denque/issues"
},
"homepage": "https://docs.page/invertase/denque",
"devDependencies": {
"benchmark": "^2.1.4",
"codecov": "^3.8.3",
"double-ended-queue": "^2.1.0-0",
"istanbul": "^0.4.5",
"mocha": "^3.5.3",
"typescript": "^3.4.1"
}
}

View File

@@ -1,3 +0,0 @@
language: node_js
node_js:
- "0.10"

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 Mathias Buus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,89 +0,0 @@
# generate-function
Module that helps you write generated functions in Node
```
npm install generate-function
```
[![build status](http://img.shields.io/travis/mafintosh/generate-function.svg?style=flat)](http://travis-ci.org/mafintosh/generate-function)
## Disclamer
Writing code that generates code is hard.
You should only use this if you really, really, really need this for performance reasons (like schema validators / parsers etc).
## Usage
``` js
const genfun = require('generate-function')
const { d } = genfun.formats
function addNumber (val) {
const gen = genfun()
gen(`
function add (n) {')
return n + ${d(val)}) // supports format strings to insert values
}
`)
return gen.toFunction() // will compile the function
}
const add2 = addNumber(2)
console.log('1 + 2 =', add2(1))
console.log(add2.toString()) // prints the generated function
```
If you need to close over variables in your generated function pass them to `toFunction(scope)`
``` js
function multiply (a, b) {
return a * b
}
function addAndMultiplyNumber (val) {
const gen = genfun()
gen(`
function (n) {
if (typeof n !== 'number') {
throw new Error('argument should be a number')
}
const result = multiply(${d(val)}, n + ${d(val)})
return result
}
`)
// use gen.toString() if you want to see the generated source
return gen.toFunction({multiply})
}
const addAndMultiply2 = addAndMultiplyNumber(2)
console.log(addAndMultiply2.toString())
console.log('(3 + 2) * 2 =', addAndMultiply2(3))
```
You can call `gen(src)` as many times as you want to append more source code to the function.
## Variables
If you need a unique safe identifier for the scope of the generated function call `str = gen.sym('friendlyName')`.
These are safe to use for variable names etc.
## Object properties
If you need to access an object property use the `str = gen.property('objectName', 'propertyName')`.
This returns `'objectName.propertyName'` if `propertyName` is safe to use as a variable. Otherwise
it returns `objectName[propertyNameAsString]`.
If you only pass `gen.property('propertyName')` it will only return the `propertyName` part safely
## License
MIT

View File

@@ -1,27 +0,0 @@
const genfun = require('./')
const { d } = genfun.formats
function multiply (a, b) {
return a * b
}
function addAndMultiplyNumber (val) {
const fn = genfun(`
function (n) {
if (typeof n !== 'number') {
throw new Error('argument should be a number')
}
const result = multiply(${d(val)}, n + ${d(val)})
return result
}
`)
// use fn.toString() if you want to see the generated source
return fn.toFunction({multiply})
}
const addAndMultiply2 = addAndMultiplyNumber(2)
console.log(addAndMultiply2.toString())
console.log('(3 + 2) * 2 =', addAndMultiply2(3))

View File

@@ -1,181 +0,0 @@
var util = require('util')
var isProperty = require('is-property')
var INDENT_START = /[\{\[]/
var INDENT_END = /[\}\]]/
// from https://mathiasbynens.be/notes/reserved-keywords
var RESERVED = [
'do',
'if',
'in',
'for',
'let',
'new',
'try',
'var',
'case',
'else',
'enum',
'eval',
'null',
'this',
'true',
'void',
'with',
'await',
'break',
'catch',
'class',
'const',
'false',
'super',
'throw',
'while',
'yield',
'delete',
'export',
'import',
'public',
'return',
'static',
'switch',
'typeof',
'default',
'extends',
'finally',
'package',
'private',
'continue',
'debugger',
'function',
'arguments',
'interface',
'protected',
'implements',
'instanceof',
'NaN',
'undefined'
]
var RESERVED_MAP = {}
for (var i = 0; i < RESERVED.length; i++) {
RESERVED_MAP[RESERVED[i]] = true
}
var isVariable = function (name) {
return isProperty(name) && !RESERVED_MAP.hasOwnProperty(name)
}
var formats = {
s: function(s) {
return '' + s
},
d: function(d) {
return '' + Number(d)
},
o: function(o) {
return JSON.stringify(o)
}
}
var genfun = function() {
var lines = []
var indent = 0
var vars = {}
var push = function(str) {
var spaces = ''
while (spaces.length < indent*2) spaces += ' '
lines.push(spaces+str)
}
var pushLine = function(line) {
if (INDENT_END.test(line.trim()[0]) && INDENT_START.test(line[line.length-1])) {
indent--
push(line)
indent++
return
}
if (INDENT_START.test(line[line.length-1])) {
push(line)
indent++
return
}
if (INDENT_END.test(line.trim()[0])) {
indent--
push(line)
return
}
push(line)
}
var line = function(fmt) {
if (!fmt) return line
if (arguments.length === 1 && fmt.indexOf('\n') > -1) {
var lines = fmt.trim().split('\n')
for (var i = 0; i < lines.length; i++) {
pushLine(lines[i].trim())
}
} else {
pushLine(util.format.apply(util, arguments))
}
return line
}
line.scope = {}
line.formats = formats
line.sym = function(name) {
if (!name || !isVariable(name)) name = 'tmp'
if (!vars[name]) vars[name] = 0
return name + (vars[name]++ || '')
}
line.property = function(obj, name) {
if (arguments.length === 1) {
name = obj
obj = ''
}
name = name + ''
if (isProperty(name)) return (obj ? obj + '.' + name : name)
return obj ? obj + '[' + JSON.stringify(name) + ']' : JSON.stringify(name)
}
line.toString = function() {
return lines.join('\n')
}
line.toFunction = function(scope) {
if (!scope) scope = {}
var src = 'return ('+line.toString()+')'
Object.keys(line.scope).forEach(function (key) {
if (!scope[key]) scope[key] = line.scope[key]
})
var keys = Object.keys(scope).map(function(key) {
return key
})
var vals = keys.map(function(key) {
return scope[key]
})
return Function.apply(null, keys.concat(src)).apply(null, vals)
}
if (arguments.length) line.apply(null, arguments)
return line
}
genfun.formats = formats
module.exports = genfun

View File

@@ -1,32 +0,0 @@
{
"name": "generate-function",
"version": "2.3.1",
"description": "Module that helps you write generated functions in Node",
"main": "index.js",
"scripts": {
"test": "tape test.js"
},
"repository": {
"type": "git",
"url": "https://github.com/mafintosh/generate-function"
},
"keywords": [
"generate",
"code",
"generation",
"function",
"performance"
],
"author": "Mathias Buus",
"license": "MIT",
"bugs": {
"url": "https://github.com/mafintosh/generate-function/issues"
},
"homepage": "https://github.com/mafintosh/generate-function",
"devDependencies": {
"tape": "^4.9.1"
},
"dependencies": {
"is-property": "^1.0.2"
}
}

View File

@@ -1,49 +0,0 @@
var tape = require('tape')
var genfun = require('./')
tape('generate add function', function(t) {
var fn = genfun()
('function add(n) {')
('return n + %d', 42)
('}')
t.same(fn.toString(), 'function add(n) {\n return n + 42\n}', 'code is indented')
t.same(fn.toFunction()(10), 52, 'function works')
t.end()
})
tape('generate function + closed variables', function(t) {
var fn = genfun()
('function add(n) {')
('return n + %d + number', 42)
('}')
var notGood = fn.toFunction()
var good = fn.toFunction({number:10})
try {
notGood(10)
t.ok(false, 'function should not work')
} catch (err) {
t.same(err.message, 'number is not defined', 'throws reference error')
}
t.same(good(11), 63, 'function with closed var works')
t.end()
})
tape('generate property', function(t) {
var gen = genfun()
t.same(gen.property('a'), 'a')
t.same(gen.property('42'), '"42"')
t.same(gen.property('b', 'a'), 'b.a')
t.same(gen.property('b', '42'), 'b["42"]')
t.same(gen.sym(42), 'tmp')
t.same(gen.sym('a'), 'a')
t.same(gen.sym('a'), 'a1')
t.same(gen.sym(42), 'tmp1')
t.same(gen.sym('const'), 'tmp2')
t.end()
})

17
node_modules/is-property/.npmignore generated vendored
View File

@@ -1,17 +0,0 @@
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
npm-debug.log
node_modules/*
*.DS_Store
test/*

22
node_modules/is-property/LICENSE generated vendored
View File

@@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 Mikola Lysenko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

28
node_modules/is-property/README.md generated vendored
View File

@@ -1,28 +0,0 @@
is-property
===========
Tests if a property of a JavaScript object can be accessed using the dot (.) notation or if it must be enclosed in brackets, (ie use x[" ... "])
Example
-------
```javascript
var isProperty = require("is-property")
console.log(isProperty("foo")) //Prints true
console.log(isProperty("0")) //Prints false
```
Install
-------
npm install is-property
### `require("is-property")(str)`
Checks if str is a property
* `str` is a string which we will test if it is a property or not
**Returns** true or false depending if str is a property
## Credits
(c) 2013 Mikola Lysenko. MIT License

File diff suppressed because one or more lines are too long

View File

@@ -1,36 +0,0 @@
{
"name": "is-property",
"version": "1.0.2",
"description": "Tests if a JSON property can be accessed using . syntax",
"main": "is-property.js",
"directories": {
"test": "test"
},
"dependencies": {},
"devDependencies": {
"tape": "~1.0.4"
},
"scripts": {
"test": "tap test/*.js"
},
"repository": {
"type": "git",
"url": "git://github.com/mikolalysenko/is-property.git"
},
"keywords": [
"is",
"property",
"json",
"dot",
"bracket",
".",
"[]"
],
"author": "Mikola Lysenko",
"license": "MIT",
"readmeFilename": "README.md",
"gitHead": "0a85ea5b6b1264ea1cdecc6e5cf186adbb3ffc50",
"bugs": {
"url": "https://github.com/mikolalysenko/is-property/issues"
}
}

202
node_modules/long/LICENSE generated vendored
View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

286
node_modules/long/README.md generated vendored
View File

@@ -1,286 +0,0 @@
# long.js
A Long class for representing a 64 bit two's-complement integer value derived from the [Closure Library](https://github.com/google/closure-library)
for stand-alone use and extended with unsigned support.
[![Build Status](https://img.shields.io/github/actions/workflow/status/dcodeIO/long.js/test.yml?branch=main&label=test&logo=github)](https://github.com/dcodeIO/long.js/actions/workflows/test.yml) [![Publish Status](https://img.shields.io/github/actions/workflow/status/dcodeIO/long.js/publish.yml?branch=main&label=publish&logo=github)](https://github.com/dcodeIO/long.js/actions/workflows/publish.yml) [![npm](https://img.shields.io/npm/v/long.svg?label=npm&color=007acc&logo=npm)](https://www.npmjs.com/package/long)
## Background
As of [ECMA-262 5th Edition](http://ecma262-5.com/ELS5_HTML.htm#Section_8.5), "all the positive and negative integers
whose magnitude is no greater than 2<sup>53</sup> are representable in the Number type", which is "representing the
doubleprecision 64-bit format IEEE 754 values as specified in the IEEE Standard for Binary Floating-Point Arithmetic".
The [maximum safe integer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER)
in JavaScript is 2<sup>53</sup>-1.
Example: 2<sup>64</sup>-1 is 1844674407370955**1615** but in JavaScript it evaluates to 1844674407370955**2000**.
Furthermore, bitwise operators in JavaScript "deal only with integers in the range 2<sup>31</sup> through
2<sup>31</sup>1, inclusive, or in the range 0 through 2<sup>32</sup>1, inclusive. These operators accept any value of
the Number type but first convert each such value to one of 2<sup>32</sup> integer values."
In some use cases, however, it is required to be able to reliably work with and perform bitwise operations on the full
64 bits. This is where long.js comes into play.
## Usage
The package exports an ECMAScript module with an UMD fallback.
```
$> npm install long
```
```js
import Long from "long";
var value = new Long(0xFFFFFFFF, 0x7FFFFFFF);
console.log(value.toString());
...
```
Note that mixing ESM and CommonJS is not recommended as it yields different classes, albeit with the same functionality.
### Usage with a CDN
- From GitHub via [jsDelivr](https://www.jsdelivr.com):<br />
`https://cdn.jsdelivr.net/gh/dcodeIO/long.js@TAG/index.js` (ESM)
- From npm via [jsDelivr](https://www.jsdelivr.com):<br />
`https://cdn.jsdelivr.net/npm/long@VERSION/index.js` (ESM)<br />
`https://cdn.jsdelivr.net/npm/long@VERSION/umd/index.js` (UMD)
- From npm via [unpkg](https://unpkg.com):<br />
`https://unpkg.com/long@VERSION/index.js` (ESM)<br />
`https://unpkg.com/long@VERSION/umd/index.js` (UMD)
Replace `TAG` respectively `VERSION` with a [specific version](https://github.com/dcodeIO/long.js/releases) or omit it (not recommended in production) to use main/latest.
## API
### Constructor
- new **Long**(low: `number`, high?: `number`, unsigned?: `boolean`)<br />
Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as _signed_ integers. See the from\* functions below for more convenient ways of constructing Longs.
### Fields
- Long#**low**: `number`<br />
The low 32 bits as a signed value.
- Long#**high**: `number`<br />
The high 32 bits as a signed value.
- Long#**unsigned**: `boolean`<br />
Whether unsigned or not.
### Constants
- Long.**ZERO**: `Long`<br />
Signed zero.
- Long.**ONE**: `Long`<br />
Signed one.
- Long.**NEG_ONE**: `Long`<br />
Signed negative one.
- Long.**UZERO**: `Long`<br />
Unsigned zero.
- Long.**UONE**: `Long`<br />
Unsigned one.
- Long.**MAX_VALUE**: `Long`<br />
Maximum signed value.
- Long.**MIN_VALUE**: `Long`<br />
Minimum signed value.
- Long.**MAX_UNSIGNED_VALUE**: `Long`<br />
Maximum unsigned value.
### Utility
- type **LongLike**: `Long | number | bigint | string`<br />
Any value or object that either is or can be converted to a Long.
- Long.**isLong**(obj: `any`): `boolean`<br />
Tests if the specified object is a Long.
- Long.**fromBits**(lowBits: `number`, highBits: `number`, unsigned?: `boolean`): `Long`<br />
Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is assumed to use 32 bits.
- Long.**fromBytes**(bytes: `number[]`, unsigned?: `boolean`, le?: `boolean`): `Long`<br />
Creates a Long from its byte representation.
- Long.**fromBytesLE**(bytes: `number[]`, unsigned?: `boolean`): `Long`<br />
Creates a Long from its little endian byte representation.
- Long.**fromBytesBE**(bytes: `number[]`, unsigned?: `boolean`): `Long`<br />
Creates a Long from its big endian byte representation.
- Long.**fromInt**(value: `number`, unsigned?: `boolean`): `Long`<br />
Returns a Long representing the given 32 bit integer value.
- Long.**fromNumber**(value: `number`, unsigned?: `boolean`): `Long`<br />
Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned.
- Long.**fromBigInt**(value: `bigint`, unsigned?: `boolean`): `Long`<br />
Returns a Long representing the given big integer.
- Long.**fromString**(str: `string`, unsigned?: `boolean`, radix?: `number`)<br />
Long.**fromString**(str: `string`, radix: `number`)<br />
Returns a Long representation of the given string, written using the specified radix.
- Long.**fromValue**(val: `LongLike`, unsigned?: `boolean`): `Long`<br />
Converts the specified value to a Long using the appropriate from\* function for its type.
### Methods
- Long#**add**(addend: `LongLike`): `Long`<br />
Returns the sum of this and the specified Long.
- Long#**and**(other: `LongLike`): `Long`<br />
Returns the bitwise AND of this Long and the specified.
- Long#**compare**/**comp**(other: `LongLike`): `number`<br />
Compares this Long's value with the specified's. Returns `0` if they are the same, `1` if the this is greater and `-1` if the given one is greater.
- Long#**divide**/**div**(divisor: `LongLike`): `Long`<br />
Returns this Long divided by the specified.
- Long#**equals**/**eq**(other: `LongLike`): `boolean`<br />
Tests if this Long's value equals the specified's.
- Long#**getHighBits**(): `number`<br />
Gets the high 32 bits as a signed integer.
- Long#**getHighBitsUnsigned**(): `number`<br />
Gets the high 32 bits as an unsigned integer.
- Long#**getLowBits**(): `number`<br />
Gets the low 32 bits as a signed integer.
- Long#**getLowBitsUnsigned**(): `number`<br />
Gets the low 32 bits as an unsigned integer.
- Long#**getNumBitsAbs**(): `number`<br />
Gets the number of bits needed to represent the absolute value of this Long.
- Long#**greaterThan**/**gt**(other: `LongLike`): `boolean`<br />
Tests if this Long's value is greater than the specified's.
- Long#**greaterThanOrEqual**/**gte**/**ge**(other: `LongLike`): `boolean`<br />
Tests if this Long's value is greater than or equal the specified's.
- Long#**isEven**(): `boolean`<br />
Tests if this Long's value is even.
- Long#**isNegative**(): `boolean`<br />
Tests if this Long's value is negative.
- Long#**isOdd**(): `boolean`<br />
Tests if this Long's value is odd.
- Long#**isPositive**(): `boolean`<br />
Tests if this Long's value is positive or zero.
- Long#**isSafeInteger**(): `boolean`<br />
Tests if this Long can be safely represented as a JavaScript number.
- Long#**isZero**/**eqz**(): `boolean`<br />
Tests if this Long's value equals zero.
- Long#**lessThan**/**lt**(other: `LongLike`): `boolean`<br />
Tests if this Long's value is less than the specified's.
- Long#**lessThanOrEqual**/**lte**/**le**(other: `LongLike`): `boolean`<br />
Tests if this Long's value is less than or equal the specified's.
- Long#**modulo**/**mod**/**rem**(divisor: `LongLike`): `Long`<br />
Returns this Long modulo the specified.
- Long#**multiply**/**mul**(multiplier: `LongLike`): `Long`<br />
Returns the product of this and the specified Long.
- Long#**negate**/**neg**(): `Long`<br />
Negates this Long's value.
- Long#**not**(): `Long`<br />
Returns the bitwise NOT of this Long.
- Long#**countLeadingZeros**/**clz**(): `number`<br />
Returns count leading zeros of this Long.
- Long#**countTrailingZeros**/**ctz**(): `number`<br />
Returns count trailing zeros of this Long.
- Long#**notEquals**/**neq**/**ne**(other: `LongLike`): `boolean`<br />
Tests if this Long's value differs from the specified's.
- Long#**or**(other: `LongLike`): `Long`<br />
Returns the bitwise OR of this Long and the specified.
- Long#**shiftLeft**/**shl**(numBits: `Long | number`): `Long`<br />
Returns this Long with bits shifted to the left by the given amount.
- Long#**shiftRight**/**shr**(numBits: `Long | number`): `Long`<br />
Returns this Long with bits arithmetically shifted to the right by the given amount.
- Long#**shiftRightUnsigned**/**shru**/**shr_u**(numBits: `Long | number`): `Long`<br />
Returns this Long with bits logically shifted to the right by the given amount.
- Long#**rotateLeft**/**rotl**(numBits: `Long | number`): `Long`<br />
Returns this Long with bits rotated to the left by the given amount.
- Long#**rotateRight**/**rotr**(numBits: `Long | number`): `Long`<br />
Returns this Long with bits rotated to the right by the given amount.
- Long#**subtract**/**sub**(subtrahend: `LongLike`): `Long`<br />
Returns the difference of this and the specified Long.
- Long#**toBytes**(le?: `boolean`): `number[]`<br />
Converts this Long to its byte representation.
- Long#**toBytesLE**(): `number[]`<br />
Converts this Long to its little endian byte representation.
- Long#**toBytesBE**(): `number[]`<br />
Converts this Long to its big endian byte representation.
- Long#**toInt**(): `number`<br />
Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
- Long#**toNumber**(): `number`<br />
Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
- Long#**toBigInt**(): `bigint`<br />
Converts the Long to its big integer representation.
- Long#**toSigned**(): `Long`<br />
Converts this Long to signed.
- Long#**toString**(radix?: `number`): `string`<br />
Converts the Long to a string written in the specified radix.
- Long#**toUnsigned**(): `Long`<br />
Converts this Long to unsigned.
- Long#**xor**(other: `Long | number | string`): `Long`<br />
Returns the bitwise XOR of this Long and the given one.
## WebAssembly support
[WebAssembly](http://webassembly.org) supports 64-bit integer arithmetic out of the box, hence a [tiny WebAssembly module](./wasm.wat) is used to compute operations like multiplication, division and remainder more efficiently (slow operations like division are around twice as fast), falling back to floating point based computations in JavaScript where WebAssembly is not yet supported, e.g., in older versions of node.
## Building
Building the UMD fallback:
```
$> npm run build
```
Running the [tests](./tests):
```
$> npm test
```

2
node_modules/long/index.d.ts generated vendored
View File

@@ -1,2 +0,0 @@
import { Long } from "./types.js";
export default Long;

1581
node_modules/long/index.js generated vendored

File diff suppressed because it is too large Load Diff

58
node_modules/long/package.json generated vendored
View File

@@ -1,58 +0,0 @@
{
"name": "long",
"version": "5.3.2",
"author": "Daniel Wirtz <dcode@dcode.io>",
"description": "A Long class for representing a 64-bit two's-complement integer value.",
"repository": {
"type": "git",
"url": "https://github.com/dcodeIO/long.js.git"
},
"bugs": {
"url": "https://github.com/dcodeIO/long.js/issues"
},
"keywords": [
"math",
"long",
"int64"
],
"license": "Apache-2.0",
"type": "module",
"main": "umd/index.js",
"types": "umd/index.d.ts",
"exports": {
".": {
"import": {
"types": "./index.d.ts",
"default": "./index.js"
},
"require": {
"types": "./umd/index.d.ts",
"default": "./umd/index.js"
}
}
},
"scripts": {
"build": "node scripts/build.js",
"lint": "prettier --check .",
"format": "prettier --write .",
"test": "npm run test:unit && npm run test:typescript",
"test:unit": "node tests",
"test:typescript": "tsc --project tests/typescript/tsconfig.esnext.json && tsc --project tests/typescript/tsconfig.nodenext.json && tsc --project tests/typescript/tsconfig.commonjs.json && tsc --project tests/typescript/tsconfig.global.json"
},
"files": [
"index.js",
"index.d.ts",
"types.d.ts",
"umd/index.js",
"umd/index.d.ts",
"umd/types.d.ts",
"umd/package.json",
"LICENSE",
"README.md"
],
"devDependencies": {
"esm2umd": "^0.3.1",
"prettier": "^3.5.0",
"typescript": "^5.7.3"
}
}

474
node_modules/long/types.d.ts generated vendored
View File

@@ -1,474 +0,0 @@
// Common type definitions for both the ESM and UMD variants. The ESM variant
// reexports the Long class as its default export, whereas the UMD variant makes
// the Long class a whole-module export with a global variable fallback.
type LongLike =
| Long
| number
| bigint
| string
| { low: number; high: number; unsigned: boolean };
export declare class Long {
/**
* Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as signed integers. See the from* functions below for more convenient ways of constructing Longs.
*/
constructor(low: number, high?: number, unsigned?: boolean);
/**
* Maximum unsigned value.
*/
static MAX_UNSIGNED_VALUE: Long;
/**
* Maximum signed value.
*/
static MAX_VALUE: Long;
/**
* Minimum signed value.
*/
static MIN_VALUE: Long;
/**
* Signed negative one.
*/
static NEG_ONE: Long;
/**
* Signed one.
*/
static ONE: Long;
/**
* Unsigned one.
*/
static UONE: Long;
/**
* Unsigned zero.
*/
static UZERO: Long;
/**
* Signed zero
*/
static ZERO: Long;
/**
* The high 32 bits as a signed value.
*/
high: number;
/**
* The low 32 bits as a signed value.
*/
low: number;
/**
* Whether unsigned or not.
*/
unsigned: boolean;
/**
* Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is assumed to use 32 bits.
*/
static fromBits(lowBits: number, highBits: number, unsigned?: boolean): Long;
/**
* Returns a Long representing the given 32 bit integer value.
*/
static fromInt(value: number, unsigned?: boolean): Long;
/**
* Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned.
*/
static fromNumber(value: number, unsigned?: boolean): Long;
/**
* Returns a Long representing the given big integer value.
*/
static fromBigInt(value: bigint, unsigned?: boolean): Long;
/**
* Returns a Long representation of the given string, written using the specified radix.
*/
static fromString(
str: string,
unsigned?: boolean | number,
radix?: number,
): Long;
/**
* Creates a Long from its byte representation.
*/
static fromBytes(bytes: number[], unsigned?: boolean, le?: boolean): Long;
/**
* Creates a Long from its little endian byte representation.
*/
static fromBytesLE(bytes: number[], unsigned?: boolean): Long;
/**
* Creates a Long from its big endian byte representation.
*/
static fromBytesBE(bytes: number[], unsigned?: boolean): Long;
/**
* Tests if the specified object is a Long.
*/
static isLong(obj: any): obj is Long;
/**
* Converts the specified value to a Long.
*/
static fromValue(val: LongLike, unsigned?: boolean): Long;
/**
* Returns the sum of this and the specified Long.
*/
add(addend: LongLike): Long;
/**
* Returns the bitwise AND of this Long and the specified.
*/
and(other: LongLike): Long;
/**
* Compares this Long's value with the specified's.
*/
compare(other: LongLike): number;
/**
* Compares this Long's value with the specified's.
*/
comp(other: LongLike): number;
/**
* Returns this Long divided by the specified.
*/
divide(divisor: LongLike): Long;
/**
* Returns this Long divided by the specified.
*/
div(divisor: LongLike): Long;
/**
* Tests if this Long's value equals the specified's.
*/
equals(other: LongLike): boolean;
/**
* Tests if this Long's value equals the specified's.
*/
eq(other: LongLike): boolean;
/**
* Gets the high 32 bits as a signed integer.
*/
getHighBits(): number;
/**
* Gets the high 32 bits as an unsigned integer.
*/
getHighBitsUnsigned(): number;
/**
* Gets the low 32 bits as a signed integer.
*/
getLowBits(): number;
/**
* Gets the low 32 bits as an unsigned integer.
*/
getLowBitsUnsigned(): number;
/**
* Gets the number of bits needed to represent the absolute value of this Long.
*/
getNumBitsAbs(): number;
/**
* Tests if this Long's value is greater than the specified's.
*/
greaterThan(other: LongLike): boolean;
/**
* Tests if this Long's value is greater than the specified's.
*/
gt(other: LongLike): boolean;
/**
* Tests if this Long's value is greater than or equal the specified's.
*/
greaterThanOrEqual(other: LongLike): boolean;
/**
* Tests if this Long's value is greater than or equal the specified's.
*/
gte(other: LongLike): boolean;
/**
* Tests if this Long's value is greater than or equal the specified's.
*/
ge(other: LongLike): boolean;
/**
* Tests if this Long's value is even.
*/
isEven(): boolean;
/**
* Tests if this Long's value is negative.
*/
isNegative(): boolean;
/**
* Tests if this Long's value is odd.
*/
isOdd(): boolean;
/**
* Tests if this Long's value is positive or zero.
*/
isPositive(): boolean;
/**
* Tests if this Long can be safely represented as a JavaScript number.
*/
isSafeInteger(): boolean;
/**
* Tests if this Long's value equals zero.
*/
isZero(): boolean;
/**
* Tests if this Long's value equals zero.
*/
eqz(): boolean;
/**
* Tests if this Long's value is less than the specified's.
*/
lessThan(other: LongLike): boolean;
/**
* Tests if this Long's value is less than the specified's.
*/
lt(other: LongLike): boolean;
/**
* Tests if this Long's value is less than or equal the specified's.
*/
lessThanOrEqual(other: LongLike): boolean;
/**
* Tests if this Long's value is less than or equal the specified's.
*/
lte(other: LongLike): boolean;
/**
* Tests if this Long's value is less than or equal the specified's.
*/
le(other: LongLike): boolean;
/**
* Returns this Long modulo the specified.
*/
modulo(other: LongLike): Long;
/**
* Returns this Long modulo the specified.
*/
mod(other: LongLike): Long;
/**
* Returns this Long modulo the specified.
*/
rem(other: LongLike): Long;
/**
* Returns the product of this and the specified Long.
*/
multiply(multiplier: LongLike): Long;
/**
* Returns the product of this and the specified Long.
*/
mul(multiplier: LongLike): Long;
/**
* Negates this Long's value.
*/
negate(): Long;
/**
* Negates this Long's value.
*/
neg(): Long;
/**
* Returns the bitwise NOT of this Long.
*/
not(): Long;
/**
* Returns count leading zeros of this Long.
*/
countLeadingZeros(): number;
/**
* Returns count leading zeros of this Long.
*/
clz(): number;
/**
* Returns count trailing zeros of this Long.
*/
countTrailingZeros(): number;
/**
* Returns count trailing zeros of this Long.
*/
ctz(): number;
/**
* Tests if this Long's value differs from the specified's.
*/
notEquals(other: LongLike): boolean;
/**
* Tests if this Long's value differs from the specified's.
*/
neq(other: LongLike): boolean;
/**
* Tests if this Long's value differs from the specified's.
*/
ne(other: LongLike): boolean;
/**
* Returns the bitwise OR of this Long and the specified.
*/
or(other: LongLike): Long;
/**
* Returns this Long with bits shifted to the left by the given amount.
*/
shiftLeft(numBits: number | Long): Long;
/**
* Returns this Long with bits shifted to the left by the given amount.
*/
shl(numBits: number | Long): Long;
/**
* Returns this Long with bits arithmetically shifted to the right by the given amount.
*/
shiftRight(numBits: number | Long): Long;
/**
* Returns this Long with bits arithmetically shifted to the right by the given amount.
*/
shr(numBits: number | Long): Long;
/**
* Returns this Long with bits logically shifted to the right by the given amount.
*/
shiftRightUnsigned(numBits: number | Long): Long;
/**
* Returns this Long with bits logically shifted to the right by the given amount.
*/
shru(numBits: number | Long): Long;
/**
* Returns this Long with bits logically shifted to the right by the given amount.
*/
shr_u(numBits: number | Long): Long;
/**
* Returns this Long with bits rotated to the left by the given amount.
*/
rotateLeft(numBits: number | Long): Long;
/**
* Returns this Long with bits rotated to the left by the given amount.
*/
rotl(numBits: number | Long): Long;
/**
* Returns this Long with bits rotated to the right by the given amount.
*/
rotateRight(numBits: number | Long): Long;
/**
* Returns this Long with bits rotated to the right by the given amount.
*/
rotr(numBits: number | Long): Long;
/**
* Returns the difference of this and the specified Long.
*/
subtract(subtrahend: LongLike): Long;
/**
* Returns the difference of this and the specified Long.
*/
sub(subtrahend: LongLike): Long;
/**
* Converts the Long to a big integer.
*/
toBigInt(): bigint;
/**
* Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
*/
toInt(): number;
/**
* Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
*/
toNumber(): number;
/**
* Converts this Long to its byte representation.
*/
toBytes(le?: boolean): number[];
/**
* Converts this Long to its little endian byte representation.
*/
toBytesLE(): number[];
/**
* Converts this Long to its big endian byte representation.
*/
toBytesBE(): number[];
/**
* Converts this Long to signed.
*/
toSigned(): Long;
/**
* Converts the Long to a string written in the specified radix.
*/
toString(radix?: number): string;
/**
* Converts this Long to unsigned.
*/
toUnsigned(): Long;
/**
* Returns the bitwise XOR of this Long and the given one.
*/
xor(other: LongLike): Long;
}

3
node_modules/long/umd/index.d.ts generated vendored
View File

@@ -1,3 +0,0 @@
import { Long } from "./types.js";
export = Long;
export as namespace Long;

1622
node_modules/long/umd/index.js generated vendored

File diff suppressed because it is too large Load Diff

3
node_modules/long/umd/package.json generated vendored
View File

@@ -1,3 +0,0 @@
{
"type": "commonjs"
}

474
node_modules/long/umd/types.d.ts generated vendored
View File

@@ -1,474 +0,0 @@
// Common type definitions for both the ESM and UMD variants. The ESM variant
// reexports the Long class as its default export, whereas the UMD variant makes
// the Long class a whole-module export with a global variable fallback.
type LongLike =
| Long
| number
| bigint
| string
| { low: number; high: number; unsigned: boolean };
export declare class Long {
/**
* Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as signed integers. See the from* functions below for more convenient ways of constructing Longs.
*/
constructor(low: number, high?: number, unsigned?: boolean);
/**
* Maximum unsigned value.
*/
static MAX_UNSIGNED_VALUE: Long;
/**
* Maximum signed value.
*/
static MAX_VALUE: Long;
/**
* Minimum signed value.
*/
static MIN_VALUE: Long;
/**
* Signed negative one.
*/
static NEG_ONE: Long;
/**
* Signed one.
*/
static ONE: Long;
/**
* Unsigned one.
*/
static UONE: Long;
/**
* Unsigned zero.
*/
static UZERO: Long;
/**
* Signed zero
*/
static ZERO: Long;
/**
* The high 32 bits as a signed value.
*/
high: number;
/**
* The low 32 bits as a signed value.
*/
low: number;
/**
* Whether unsigned or not.
*/
unsigned: boolean;
/**
* Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is assumed to use 32 bits.
*/
static fromBits(lowBits: number, highBits: number, unsigned?: boolean): Long;
/**
* Returns a Long representing the given 32 bit integer value.
*/
static fromInt(value: number, unsigned?: boolean): Long;
/**
* Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned.
*/
static fromNumber(value: number, unsigned?: boolean): Long;
/**
* Returns a Long representing the given big integer value.
*/
static fromBigInt(value: bigint, unsigned?: boolean): Long;
/**
* Returns a Long representation of the given string, written using the specified radix.
*/
static fromString(
str: string,
unsigned?: boolean | number,
radix?: number,
): Long;
/**
* Creates a Long from its byte representation.
*/
static fromBytes(bytes: number[], unsigned?: boolean, le?: boolean): Long;
/**
* Creates a Long from its little endian byte representation.
*/
static fromBytesLE(bytes: number[], unsigned?: boolean): Long;
/**
* Creates a Long from its big endian byte representation.
*/
static fromBytesBE(bytes: number[], unsigned?: boolean): Long;
/**
* Tests if the specified object is a Long.
*/
static isLong(obj: any): obj is Long;
/**
* Converts the specified value to a Long.
*/
static fromValue(val: LongLike, unsigned?: boolean): Long;
/**
* Returns the sum of this and the specified Long.
*/
add(addend: LongLike): Long;
/**
* Returns the bitwise AND of this Long and the specified.
*/
and(other: LongLike): Long;
/**
* Compares this Long's value with the specified's.
*/
compare(other: LongLike): number;
/**
* Compares this Long's value with the specified's.
*/
comp(other: LongLike): number;
/**
* Returns this Long divided by the specified.
*/
divide(divisor: LongLike): Long;
/**
* Returns this Long divided by the specified.
*/
div(divisor: LongLike): Long;
/**
* Tests if this Long's value equals the specified's.
*/
equals(other: LongLike): boolean;
/**
* Tests if this Long's value equals the specified's.
*/
eq(other: LongLike): boolean;
/**
* Gets the high 32 bits as a signed integer.
*/
getHighBits(): number;
/**
* Gets the high 32 bits as an unsigned integer.
*/
getHighBitsUnsigned(): number;
/**
* Gets the low 32 bits as a signed integer.
*/
getLowBits(): number;
/**
* Gets the low 32 bits as an unsigned integer.
*/
getLowBitsUnsigned(): number;
/**
* Gets the number of bits needed to represent the absolute value of this Long.
*/
getNumBitsAbs(): number;
/**
* Tests if this Long's value is greater than the specified's.
*/
greaterThan(other: LongLike): boolean;
/**
* Tests if this Long's value is greater than the specified's.
*/
gt(other: LongLike): boolean;
/**
* Tests if this Long's value is greater than or equal the specified's.
*/
greaterThanOrEqual(other: LongLike): boolean;
/**
* Tests if this Long's value is greater than or equal the specified's.
*/
gte(other: LongLike): boolean;
/**
* Tests if this Long's value is greater than or equal the specified's.
*/
ge(other: LongLike): boolean;
/**
* Tests if this Long's value is even.
*/
isEven(): boolean;
/**
* Tests if this Long's value is negative.
*/
isNegative(): boolean;
/**
* Tests if this Long's value is odd.
*/
isOdd(): boolean;
/**
* Tests if this Long's value is positive or zero.
*/
isPositive(): boolean;
/**
* Tests if this Long can be safely represented as a JavaScript number.
*/
isSafeInteger(): boolean;
/**
* Tests if this Long's value equals zero.
*/
isZero(): boolean;
/**
* Tests if this Long's value equals zero.
*/
eqz(): boolean;
/**
* Tests if this Long's value is less than the specified's.
*/
lessThan(other: LongLike): boolean;
/**
* Tests if this Long's value is less than the specified's.
*/
lt(other: LongLike): boolean;
/**
* Tests if this Long's value is less than or equal the specified's.
*/
lessThanOrEqual(other: LongLike): boolean;
/**
* Tests if this Long's value is less than or equal the specified's.
*/
lte(other: LongLike): boolean;
/**
* Tests if this Long's value is less than or equal the specified's.
*/
le(other: LongLike): boolean;
/**
* Returns this Long modulo the specified.
*/
modulo(other: LongLike): Long;
/**
* Returns this Long modulo the specified.
*/
mod(other: LongLike): Long;
/**
* Returns this Long modulo the specified.
*/
rem(other: LongLike): Long;
/**
* Returns the product of this and the specified Long.
*/
multiply(multiplier: LongLike): Long;
/**
* Returns the product of this and the specified Long.
*/
mul(multiplier: LongLike): Long;
/**
* Negates this Long's value.
*/
negate(): Long;
/**
* Negates this Long's value.
*/
neg(): Long;
/**
* Returns the bitwise NOT of this Long.
*/
not(): Long;
/**
* Returns count leading zeros of this Long.
*/
countLeadingZeros(): number;
/**
* Returns count leading zeros of this Long.
*/
clz(): number;
/**
* Returns count trailing zeros of this Long.
*/
countTrailingZeros(): number;
/**
* Returns count trailing zeros of this Long.
*/
ctz(): number;
/**
* Tests if this Long's value differs from the specified's.
*/
notEquals(other: LongLike): boolean;
/**
* Tests if this Long's value differs from the specified's.
*/
neq(other: LongLike): boolean;
/**
* Tests if this Long's value differs from the specified's.
*/
ne(other: LongLike): boolean;
/**
* Returns the bitwise OR of this Long and the specified.
*/
or(other: LongLike): Long;
/**
* Returns this Long with bits shifted to the left by the given amount.
*/
shiftLeft(numBits: number | Long): Long;
/**
* Returns this Long with bits shifted to the left by the given amount.
*/
shl(numBits: number | Long): Long;
/**
* Returns this Long with bits arithmetically shifted to the right by the given amount.
*/
shiftRight(numBits: number | Long): Long;
/**
* Returns this Long with bits arithmetically shifted to the right by the given amount.
*/
shr(numBits: number | Long): Long;
/**
* Returns this Long with bits logically shifted to the right by the given amount.
*/
shiftRightUnsigned(numBits: number | Long): Long;
/**
* Returns this Long with bits logically shifted to the right by the given amount.
*/
shru(numBits: number | Long): Long;
/**
* Returns this Long with bits logically shifted to the right by the given amount.
*/
shr_u(numBits: number | Long): Long;
/**
* Returns this Long with bits rotated to the left by the given amount.
*/
rotateLeft(numBits: number | Long): Long;
/**
* Returns this Long with bits rotated to the left by the given amount.
*/
rotl(numBits: number | Long): Long;
/**
* Returns this Long with bits rotated to the right by the given amount.
*/
rotateRight(numBits: number | Long): Long;
/**
* Returns this Long with bits rotated to the right by the given amount.
*/
rotr(numBits: number | Long): Long;
/**
* Returns the difference of this and the specified Long.
*/
subtract(subtrahend: LongLike): Long;
/**
* Returns the difference of this and the specified Long.
*/
sub(subtrahend: LongLike): Long;
/**
* Converts the Long to a big integer.
*/
toBigInt(): bigint;
/**
* Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
*/
toInt(): number;
/**
* Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
*/
toNumber(): number;
/**
* Converts this Long to its byte representation.
*/
toBytes(le?: boolean): number[];
/**
* Converts this Long to its little endian byte representation.
*/
toBytesLE(): number[];
/**
* Converts this Long to its big endian byte representation.
*/
toBytesBE(): number[];
/**
* Converts this Long to signed.
*/
toSigned(): Long;
/**
* Converts the Long to a string written in the specified radix.
*/
toString(radix?: number): string;
/**
* Converts this Long to unsigned.
*/
toUnsigned(): Long;
/**
* Returns the bitwise XOR of this Long and the given one.
*/
xor(other: LongLike): Long;
}

21
node_modules/lru.min/LICENSE generated vendored
View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024-current Weslley Araújo (@wellwelwel)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

392
node_modules/lru.min/README.md generated vendored
View File

@@ -1,392 +0,0 @@
<h1 align="center">lru.min</h1>
<div align="center">
[![NPM Version](https://img.shields.io/npm/v/lru.min.svg?label=&color=70a1ff&logo=npm&logoColor=white)](https://www.npmjs.com/package/lru.min)
[![NPM Downloads](https://img.shields.io/npm/dm/lru.min.svg?label=&logo=npm&logoColor=white&color=45aaf2)](https://www.npmjs.com/package/lru.min)
[![Coverage](https://img.shields.io/codecov/c/github/wellwelwel/lru.min?label=&logo=codecov&logoColor=white&color=98cc00)](https://app.codecov.io/gh/wellwelwel/lru.min)<br />
[![GitHub Workflow Status (Node.js)](https://img.shields.io/github/actions/workflow/status/wellwelwel/lru.min/ci_node.yml?event=push&label=&branch=main&logo=nodedotjs&logoColor=535c68&color=badc58)](https://github.com/wellwelwel/lru.min/actions/workflows/ci_node.yml?query=branch%3Amain)
[![GitHub Workflow Status (Bun)](https://img.shields.io/github/actions/workflow/status/wellwelwel/lru.min/ci_bun.yml?event=push&label=&branch=main&logo=bun&logoColor=ffffff&color=f368e0)](https://github.com/wellwelwel/lru.min/actions/workflows/ci_bun.yml?query=branch%3Amain)
[![GitHub Workflow Status (Deno)](https://img.shields.io/github/actions/workflow/status/wellwelwel/lru.min/ci_deno.yml?event=push&label=&branch=main&logo=deno&logoColor=ffffff&color=079992)](https://github.com/wellwelwel/lru.min/actions/workflows/ci_deno.yml?query=branch%3Amain)
🔥 An extremely fast, efficient, and lightweight <strong><a href="https://en.m.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29">LRU</a> Cache</strong> for <strong>JavaScript</strong> (<strong>Browser</strong> compatible).
</div>
## Why another LRU?
- 🎖️ **lru.min** is fully compatible with both **Node.js** _(8+)_, **Bun**, **Deno** and, browser environments. All of this, while maintaining the same high performance [_(and a little more)_](https://github.com/wellwelwel/lru.min?tab=readme-ov-file#performance) as the most popular **LRU** packages.
---
## Install
```bash
# Node.js
npm i lru.min
```
```bash
# Bun
bun add lru.min
```
```bash
# Deno
deno add npm:lru.min
```
---
## Usage
### Quickstart
```js
import { createLRU } from 'lru.min';
const max = 2;
const onEviction = (key, value) => {
console.log(`Key "${key}" with value "${value}" has been evicted.`);
};
const LRU = createLRU({
max,
onEviction,
});
LRU.set('A', 'My Value');
LRU.set('B', 'Other Value');
LRU.set('C', 'Another Value');
// => Key "A" with value "My Value" has been evicted.
LRU.has('B');
LRU.get('B');
LRU.delete('B');
// => Key "B" with value "Other Value" has been evicted.
LRU.peek('C');
LRU.clear(); // ← recommended | LRU.evict(max) → (slower alternative)
// => Key "C" with value "Another Value" has been evicted.
LRU.set('D', "You're amazing 💛");
LRU.size; // 1
LRU.max; // 2
LRU.available; // 1
LRU.resize(10);
LRU.size; // 1
LRU.max; // 10
LRU.available; // 9
```
> For _up-to-date_ documentation, always follow the [**README.md**](https://github.com/wellwelwel/lru.min?tab=readme-ov-file#readme) in the **GitHub** repository.
### Import
#### ES Modules
```js
import { createLRU } from 'lru.min';
```
#### CommonJS
```js
const { createLRU } = require('lru.min');
```
#### Browser
> Requires **ES6**.
```html
<script src="https://cdn.jsdelivr.net/npm/lru.min@1.x.x/browser/lru.min.js"></script>
```
- You can use tools such as [**Babel**](https://github.com/babel/babel) to increase the compatibility rate.
### Create a new LRU Cache
> Set maximum size when creating **LRU**.
```ts
const LRU = createLRU({ max: 150_000 });
```
Also, you can set a callback for every deletion/eviction:
```ts
const LRU = createLRU({
max: 150_000,
onEviction: (key, value) => {
// do something
},
});
```
### Set a cache
Adds a key-value pair to the cache. Updates the value if the key already exists
```ts
LRU.set('key', 'value');
```
> `undefined` keys will simply be ignored.
- Complexity: **O(1)**.
### Get a cache
Retrieves the value for a given key and moves the key to the most recent position.
```ts
LRU.get('key');
```
- Complexity: **O(1)**.
### Peek a cache
Retrieves the value for a given key without changing its position.
```ts
LRU.peek('key');
```
- Complexity: **O(1)**.
### Check if a key exists
```ts
LRU.has('key');
```
- Complexity: **O(1)**.
### Delete a cache
```ts
LRU.delete('key');
```
- Complexity: **O(1)**.
### Evict from the oldest cache
Evicts the specified number of the oldest items from the cache.
```ts
LRU.evict(1000);
```
- Complexity: **O(key)** even if passed a number greater than the number of items, only existing items will be evicted.
> [!TIP]
>
> - Methods that perform eviction(s) when maximum size is reached: `set` and `resize`.
> - Methods that always perform eviction(s): `delete`, `clear`, and `evict` itself.
### Resize the cache
Resizes the cache to a new maximum size, evicting items if necessary.
```ts
LRU.resize(50_000);
```
- Complexity:
- Increasing: **O(newMax - max)**.
- Downsizing: **O(n)**.
### Clear the cache
Clears and disposes (if used) all key-value pairs from the cache.
```ts
LRU.clear();
```
- Complexity:
- Without `onEviction`: **O(1)**.
- Using `onEviction`: **O(entries)**.
### Debugging
#### Get the max size of the cache
```ts
LRU.max;
```
- Complexity: **O(1)**.
#### Get the current size of the cache
```ts
LRU.size;
```
- Complexity: **O(1)**.
#### Get the available slots in the cache
```ts
LRU.available;
```
- Complexity: **O(1)**.
### Iterating the cache
#### Get all keys
Iterates over all keys in the cache, from most recent to least recent.
```ts
const keys = [...LRU.keys()];
```
- Complexity: **O(keys)**.
#### Get all values
Iterates over all values in the cache, from most recent to least recent.
```ts
const values = [...LRU.values()];
```
- Complexity: **O(values)**.
#### Get all entries
Iterates over `[key, value]` pairs in the cache, from most recent to least recent.
```ts
const entries = [...LRU.entries()];
```
- Complexity: **O(entries)**.
#### Run a callback for each entry
Iterates over each value-key pair in the cache, from most recent to least recent.
```ts
LRU.forEach((value, key) => {
// do something
});
```
- Complexity: **O(entries)**.
---
> [!NOTE]
>
> - We use `O(keys)`, `O(values)`, `O(entries)`, and `O(newMax - max)` to explicitly indicate what is being iterated over. In traditional complexity notation, this would be represented as `O(n)`.
---
### TypeScript
You can set types for both keys and values. For example:
```ts
import { createLRU } from 'lru.min';
type Key = number;
type Value = {
name: string;
};
const LRU = createLRU<Key, Value>({ max: 1000 });
LRU.set(1, { name: 'Peter' });
LRU.set(2, { name: 'Mary' });
```
Also:
```ts
import { createLRU, type CacheOptions } from 'lru.min';
type Key = number;
type Value = {
name: string;
};
const options: CacheOptions<Key, Value> = {
max: 10,
onEviction(key, value) {
console.log(key, value);
},
};
// No need to repeat the type params
const LRU = createLRU(options);
LRU.set(1, { name: 'Peter' });
LRU.set(2, { name: 'Mary' });
```
---
### Performance
The benchmark is performed by comparing `1,000,000` runs through a maximum cache limit of `100,000`, getting `333,333` caches and deleting `200,000` keys 10 consecutive times, clearing the cache every run.
> - [**lru-cache**](https://github.com/isaacs/node-lru-cache) `v11.0.0`
```sh
# Time:
lru.min: 240.45ms
lru-cache: 258.32ms
# CPU:
lru.min: 275558.30µs
lru-cache: 306858.30µs
```
- See detailed results and how the tests are run and compared in the [**benchmark**](https://github.com/wellwelwel/lru.min/tree/main/benchmark) directory.
---
## Security Policy
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/wellwelwel/lru.min/ci_codeql.yml?event=push&label=&branch=main&logo=github&logoColor=white&color=f368e0)](https://github.com/wellwelwel/lru.min/actions/workflows/ci_codeql.yml?query=branch%3Amain)
Please check the [**SECURITY.md**](https://github.com/wellwelwel/lru.min/blob/main/SECURITY.md).
---
## Contributing
See the [**Contributing Guide**](https://github.com/wellwelwel/lru.min/blob/main/CONTRIBUTING.md) and please follow our [**Code of Conduct**](https://github.com/wellwelwel/lru.min/blob/main/CODE_OF_CONDUCT.md) 🚀
---
## Acknowledgements
- [![Contributors](https://img.shields.io/github/contributors/wellwelwel/lru.min?label=Contributors)](https://github.com/wellwelwel/lru.min/graphs/contributors)
- **lru.min** is inspired by [**lru-cache**](https://github.com/isaacs/node-lru-cache) architecture and [**quick-lru**](https://github.com/sindresorhus/quick-lru) usage, simplifying and improving their concepts for enhanced performance and compatibility.
> [!IMPORTANT]
>
> No [**lru-cache**](https://github.com/isaacs/node-lru-cache) or [**quick-lru**](https://github.com/sindresorhus/quick-lru) code is used in **lru.min**. For more comprehensive features such as **TTL** support, consider using and supporting them 🤝
---
## License
**lru.min** is under the [**MIT License**](https://github.com/wellwelwel/lru.min/blob/main/LICENSE).<br />
Copyright © 2024-present [Weslley Araújo](https://github.com/wellwelwel) and **lru.min** [contributors](https://github.com/wellwelwel/lru.min/graphs/contributors).

View File

@@ -1 +0,0 @@
"use strict";window.createLRU=function(r){var e=r.max;if(!(Number.isInteger(e)&&e>0))throw new TypeError("`max` must be a positive integer");var n=0,i=0,t=0,a=[],o=r.onEviction,l=new Map,f=new Array(e).fill(void 0),u=new Array(e).fill(void 0),v=new Array(e).fill(0),s=new Array(e).fill(0),p=function(r,e){if(r!==t){var n=v[r],a=s[r];r===i?i=n:("get"===e||0!==a)&&(v[a]=n),0!==n&&(s[n]=a),v[t]=r,s[r]=t,v[r]=0,t=r}},c=function(){var r=i,e=f[r];return null==o||o(e,u[r]),l.delete(e),f[r]=void 0,u[r]=void 0,0!==(i=v[r])&&(s[i]=0),0===--n&&(i=t=0),a.push(r),r};return{set:function(r,v){if(void 0!==r){var s=l.get(r);void 0===s?(s=n===e?c():a.length>0?a.pop():n,l.set(r,s),f[s]=r,n++):null==o||o(r,u[s]),u[s]=v,1===n?i=t=s:p(s,"set")}},get:function(r){var e=l.get(r);if(void 0!==e)return e!==t&&p(e,"get"),u[e]},peek:function(r){var e=l.get(r);return void 0!==e?u[e]:void 0},has:function(r){return l.has(r)},keys:function*(){for(var r=t,e=0;e<n;e++)yield f[r],r=s[r]},values:function*(){for(var r=t,e=0;e<n;e++)yield u[r],r=s[r]},entries:function*(){for(var r=t,e=0;e<n;e++)yield[f[r],u[r]],r=s[r]},forEach:function(r){for(var e=t,i=0;i<n;i++){var a=f[e];r(u[e],a),e=s[e]}},delete:function(r){var e=l.get(r);if(void 0===e)return!1;null==o||o(r,u[e]),l.delete(r),a.push(e),f[e]=void 0,u[e]=void 0;var p=s[e],c=v[e];return 0!==p&&(v[p]=c),0!==c&&(s[c]=p),e===i&&(i=c),e===t&&(t=p),n--,!0},evict:function(r){for(var e=Math.min(r,n);e>0;)c(),e--},clear:function(){if("function"==typeof o)for(var r=i,e=0;e<n;e++)o(f[r],u[r]),r=v[r];l.clear(),f.fill(void 0),u.fill(void 0),a=[],n=0,i=t=0},resize:function(r){if(!(Number.isInteger(r)&&r>0))throw new TypeError("`max` must be a positive integer");if(r!==e){if(r<e){for(var p=t,c=Math.min(n,r),d=n-c,y=new Array(r),g=new Array(r),h=new Array(r),w=new Array(r),A=1;A<=d;A++)null==o||o(f[A],u[A]);for(var m=c-1;m>=0;m--)y[m]=f[p],g[m]=u[p],h[m]=m+1,w[m]=m-1,l.set(y[m],m),p=s[p];i=0,t=c-1,n=c,f.length=r,u.length=r,v.length=r,s.length=r;for(var b=0;b<c;b++)f[b]=y[b],u[b]=g[b],v[b]=h[b],s[b]=w[b];a=[];for(var x=c;x<r;x++)a.push(x)}else{var E=r-e;f.push.apply(f,new Array(E).fill(void 0)),u.push.apply(u,new Array(E).fill(void 0)),v.push.apply(v,new Array(E).fill(0)),s.push.apply(s,new Array(E).fill(0))}e=r}},get max(){return e},get size(){return n},get available(){return e-n}}};

38
node_modules/lru.min/lib/index.d.ts generated vendored
View File

@@ -1,38 +0,0 @@
export type CacheOptions<Key = unknown, Value = unknown> = {
/** Maximum number of items the cache can hold. */
max: number;
/** Function called when an item is evicted from the cache. */
onEviction?: (key: Key, value: Value) => unknown;
};
export declare const createLRU: <Key, Value>(options: CacheOptions<Key, Value>) => {
/** Adds a key-value pair to the cache. Updates the value if the key already exists. */
set(key: Key, value: Value): undefined;
/** Retrieves the value for a given key and moves the key to the most recent position. */
get(key: Key): Value | undefined;
/** Retrieves the value for a given key without changing its position. */
peek: (key: Key) => Value | undefined;
/** Checks if a key exists in the cache. */
has: (key: Key) => boolean;
/** Iterates over all keys in the cache, from most recent to least recent. */
keys(): IterableIterator<Key>;
/** Iterates over all values in the cache, from most recent to least recent. */
values(): IterableIterator<Value>;
/** Iterates over `[key, value]` pairs in the cache, from most recent to least recent. */
entries(): IterableIterator<[Key, Value]>;
/** Iterates over each value-key pair in the cache, from most recent to least recent. */
forEach: (callback: (value: Value, key: Key) => unknown) => undefined;
/** Deletes a key-value pair from the cache. */
delete(key: Key): boolean;
/** Evicts the oldest item or the specified number of the oldest items from the cache. */
evict: (number: number) => undefined;
/** Clears all key-value pairs from the cache. */
clear(): undefined;
/** Resizes the cache to a new maximum size, evicting items if necessary. */
resize: (newMax: number) => undefined;
/** Returns the maximum number of items that can be stored in the cache. */
readonly max: number;
/** Returns the number of items currently stored in the cache. */
readonly size: number;
/** Returns the number of currently available slots in the cache before reaching the maximum size. */
readonly available: number;
};

231
node_modules/lru.min/lib/index.js generated vendored
View File

@@ -1,231 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createLRU = void 0;
const createLRU = (options) => {
let { max } = options;
if (!(Number.isInteger(max) && max > 0))
throw new TypeError('`max` must be a positive integer');
let size = 0;
let head = 0;
let tail = 0;
let free = [];
const { onEviction } = options;
const keyMap = new Map();
const keyList = new Array(max).fill(undefined);
const valList = new Array(max).fill(undefined);
const next = new Array(max).fill(0);
const prev = new Array(max).fill(0);
const setTail = (index, type) => {
if (index === tail)
return;
const nextIndex = next[index];
const prevIndex = prev[index];
if (index === head)
head = nextIndex;
else if (type === 'get' || prevIndex !== 0)
next[prevIndex] = nextIndex;
if (nextIndex !== 0)
prev[nextIndex] = prevIndex;
next[tail] = index;
prev[index] = tail;
next[index] = 0;
tail = index;
};
const _evict = () => {
const evictHead = head;
const key = keyList[evictHead];
onEviction === null || onEviction === void 0 ? void 0 : onEviction(key, valList[evictHead]);
keyMap.delete(key);
keyList[evictHead] = undefined;
valList[evictHead] = undefined;
head = next[evictHead];
if (head !== 0)
prev[head] = 0;
size--;
if (size === 0)
head = tail = 0;
free.push(evictHead);
return evictHead;
};
return {
/** Adds a key-value pair to the cache. Updates the value if the key already exists. */
set(key, value) {
if (key === undefined)
return;
let index = keyMap.get(key);
if (index === undefined) {
index = size === max ? _evict() : free.length > 0 ? free.pop() : size;
keyMap.set(key, index);
keyList[index] = key;
size++;
}
else
onEviction === null || onEviction === void 0 ? void 0 : onEviction(key, valList[index]);
valList[index] = value;
if (size === 1)
head = tail = index;
else
setTail(index, 'set');
},
/** Retrieves the value for a given key and moves the key to the most recent position. */
get(key) {
const index = keyMap.get(key);
if (index === undefined)
return;
if (index !== tail)
setTail(index, 'get');
return valList[index];
},
/** Retrieves the value for a given key without changing its position. */
peek: (key) => {
const index = keyMap.get(key);
return index !== undefined ? valList[index] : undefined;
},
/** Checks if a key exists in the cache. */
has: (key) => keyMap.has(key),
/** Iterates over all keys in the cache, from most recent to least recent. */
*keys() {
let current = tail;
for (let i = 0; i < size; i++) {
yield keyList[current];
current = prev[current];
}
},
/** Iterates over all values in the cache, from most recent to least recent. */
*values() {
let current = tail;
for (let i = 0; i < size; i++) {
yield valList[current];
current = prev[current];
}
},
/** Iterates over `[key, value]` pairs in the cache, from most recent to least recent. */
*entries() {
let current = tail;
for (let i = 0; i < size; i++) {
yield [keyList[current], valList[current]];
current = prev[current];
}
},
/** Iterates over each value-key pair in the cache, from most recent to least recent. */
forEach: (callback) => {
let current = tail;
for (let i = 0; i < size; i++) {
const key = keyList[current];
const value = valList[current];
callback(value, key);
current = prev[current];
}
},
/** Deletes a key-value pair from the cache. */
delete(key) {
const index = keyMap.get(key);
if (index === undefined)
return false;
onEviction === null || onEviction === void 0 ? void 0 : onEviction(key, valList[index]);
keyMap.delete(key);
free.push(index);
keyList[index] = undefined;
valList[index] = undefined;
const prevIndex = prev[index];
const nextIndex = next[index];
if (prevIndex !== 0)
next[prevIndex] = nextIndex;
if (nextIndex !== 0)
prev[nextIndex] = prevIndex;
if (index === head)
head = nextIndex;
if (index === tail)
tail = prevIndex;
size--;
return true;
},
/** Evicts the oldest item or the specified number of the oldest items from the cache. */
evict: (number) => {
let toPrune = Math.min(number, size);
while (toPrune > 0) {
_evict();
toPrune--;
}
},
/** Clears all key-value pairs from the cache. */
clear() {
if (typeof onEviction === 'function') {
let current = head;
for (let i = 0; i < size; i++) {
onEviction(keyList[current], valList[current]);
current = next[current];
}
}
keyMap.clear();
keyList.fill(undefined);
valList.fill(undefined);
free = [];
size = 0;
head = tail = 0;
},
/** Resizes the cache to a new maximum size, evicting items if necessary. */
resize: (newMax) => {
if (!(Number.isInteger(newMax) && newMax > 0))
throw new TypeError('`max` must be a positive integer');
if (newMax === max)
return;
if (newMax < max) {
let current = tail;
const preserve = Math.min(size, newMax);
const remove = size - preserve;
const newKeyList = new Array(newMax);
const newValList = new Array(newMax);
const newNext = new Array(newMax);
const newPrev = new Array(newMax);
for (let i = 1; i <= remove; i++)
onEviction === null || onEviction === void 0 ? void 0 : onEviction(keyList[i], valList[i]);
for (let i = preserve - 1; i >= 0; i--) {
newKeyList[i] = keyList[current];
newValList[i] = valList[current];
newNext[i] = i + 1;
newPrev[i] = i - 1;
keyMap.set(newKeyList[i], i);
current = prev[current];
}
head = 0;
tail = preserve - 1;
size = preserve;
keyList.length = newMax;
valList.length = newMax;
next.length = newMax;
prev.length = newMax;
for (let i = 0; i < preserve; i++) {
keyList[i] = newKeyList[i];
valList[i] = newValList[i];
next[i] = newNext[i];
prev[i] = newPrev[i];
}
free = [];
for (let i = preserve; i < newMax; i++)
free.push(i);
}
else {
const fill = newMax - max;
keyList.push(...new Array(fill).fill(undefined));
valList.push(...new Array(fill).fill(undefined));
next.push(...new Array(fill).fill(0));
prev.push(...new Array(fill).fill(0));
}
max = newMax;
},
/** Returns the maximum number of items that can be stored in the cache. */
get max() {
return max;
},
/** Returns the number of items currently stored in the cache. */
get size() {
return size;
},
/** Returns the number of currently available slots in the cache before reaching the maximum size. */
get available() {
return max - size;
},
};
};
exports.createLRU = createLRU;

209
node_modules/lru.min/lib/index.mjs generated vendored
View File

@@ -1,209 +0,0 @@
const createLRU = (options) => {
let { max } = options;
if (!(Number.isInteger(max) && max > 0))
throw new TypeError("`max` must be a positive integer");
let size = 0;
let head = 0;
let tail = 0;
let free = [];
const { onEviction } = options;
const keyMap = /* @__PURE__ */ new Map();
const keyList = new Array(max).fill(void 0);
const valList = new Array(max).fill(void 0);
const next = new Array(max).fill(0);
const prev = new Array(max).fill(0);
const setTail = (index, type) => {
if (index === tail) return;
const nextIndex = next[index];
const prevIndex = prev[index];
if (index === head) head = nextIndex;
else if (type === "get" || prevIndex !== 0) next[prevIndex] = nextIndex;
if (nextIndex !== 0) prev[nextIndex] = prevIndex;
next[tail] = index;
prev[index] = tail;
next[index] = 0;
tail = index;
};
const _evict = () => {
const evictHead = head;
const key = keyList[evictHead];
onEviction == null ? void 0 : onEviction(key, valList[evictHead]);
keyMap.delete(key);
keyList[evictHead] = void 0;
valList[evictHead] = void 0;
head = next[evictHead];
if (head !== 0) prev[head] = 0;
size--;
if (size === 0) head = tail = 0;
free.push(evictHead);
return evictHead;
};
return {
/** Adds a key-value pair to the cache. Updates the value if the key already exists. */
set(key, value) {
if (key === void 0) return;
let index = keyMap.get(key);
if (index === void 0) {
index = size === max ? _evict() : free.length > 0 ? free.pop() : size;
keyMap.set(key, index);
keyList[index] = key;
size++;
} else onEviction == null ? void 0 : onEviction(key, valList[index]);
valList[index] = value;
if (size === 1) head = tail = index;
else setTail(index, "set");
},
/** Retrieves the value for a given key and moves the key to the most recent position. */
get(key) {
const index = keyMap.get(key);
if (index === void 0) return;
if (index !== tail) setTail(index, "get");
return valList[index];
},
/** Retrieves the value for a given key without changing its position. */
peek: (key) => {
const index = keyMap.get(key);
return index !== void 0 ? valList[index] : void 0;
},
/** Checks if a key exists in the cache. */
has: (key) => keyMap.has(key),
/** Iterates over all keys in the cache, from most recent to least recent. */
*keys() {
let current = tail;
for (let i = 0; i < size; i++) {
yield keyList[current];
current = prev[current];
}
},
/** Iterates over all values in the cache, from most recent to least recent. */
*values() {
let current = tail;
for (let i = 0; i < size; i++) {
yield valList[current];
current = prev[current];
}
},
/** Iterates over `[key, value]` pairs in the cache, from most recent to least recent. */
*entries() {
let current = tail;
for (let i = 0; i < size; i++) {
yield [keyList[current], valList[current]];
current = prev[current];
}
},
/** Iterates over each value-key pair in the cache, from most recent to least recent. */
forEach: (callback) => {
let current = tail;
for (let i = 0; i < size; i++) {
const key = keyList[current];
const value = valList[current];
callback(value, key);
current = prev[current];
}
},
/** Deletes a key-value pair from the cache. */
delete(key) {
const index = keyMap.get(key);
if (index === void 0) return false;
onEviction == null ? void 0 : onEviction(key, valList[index]);
keyMap.delete(key);
free.push(index);
keyList[index] = void 0;
valList[index] = void 0;
const prevIndex = prev[index];
const nextIndex = next[index];
if (prevIndex !== 0) next[prevIndex] = nextIndex;
if (nextIndex !== 0) prev[nextIndex] = prevIndex;
if (index === head) head = nextIndex;
if (index === tail) tail = prevIndex;
size--;
return true;
},
/** Evicts the oldest item or the specified number of the oldest items from the cache. */
evict: (number) => {
let toPrune = Math.min(number, size);
while (toPrune > 0) {
_evict();
toPrune--;
}
},
/** Clears all key-value pairs from the cache. */
clear() {
if (typeof onEviction === "function") {
let current = head;
for (let i = 0; i < size; i++) {
onEviction(keyList[current], valList[current]);
current = next[current];
}
}
keyMap.clear();
keyList.fill(void 0);
valList.fill(void 0);
free = [];
size = 0;
head = tail = 0;
},
/** Resizes the cache to a new maximum size, evicting items if necessary. */
resize: (newMax) => {
if (!(Number.isInteger(newMax) && newMax > 0))
throw new TypeError("`max` must be a positive integer");
if (newMax === max) return;
if (newMax < max) {
let current = tail;
const preserve = Math.min(size, newMax);
const remove = size - preserve;
const newKeyList = new Array(newMax);
const newValList = new Array(newMax);
const newNext = new Array(newMax);
const newPrev = new Array(newMax);
for (let i = 1; i <= remove; i++)
onEviction == null ? void 0 : onEviction(keyList[i], valList[i]);
for (let i = preserve - 1; i >= 0; i--) {
newKeyList[i] = keyList[current];
newValList[i] = valList[current];
newNext[i] = i + 1;
newPrev[i] = i - 1;
keyMap.set(newKeyList[i], i);
current = prev[current];
}
head = 0;
tail = preserve - 1;
size = preserve;
keyList.length = newMax;
valList.length = newMax;
next.length = newMax;
prev.length = newMax;
for (let i = 0; i < preserve; i++) {
keyList[i] = newKeyList[i];
valList[i] = newValList[i];
next[i] = newNext[i];
prev[i] = newPrev[i];
}
free = [];
for (let i = preserve; i < newMax; i++) free.push(i);
} else {
const fill = newMax - max;
keyList.push(...new Array(fill).fill(void 0));
valList.push(...new Array(fill).fill(void 0));
next.push(...new Array(fill).fill(0));
prev.push(...new Array(fill).fill(0));
}
max = newMax;
},
/** Returns the maximum number of items that can be stored in the cache. */
get max() {
return max;
},
/** Returns the number of items currently stored in the cache. */
get size() {
return size;
},
/** Returns the number of currently available slots in the cache before reaching the maximum size. */
get available() {
return max - size;
}
};
};
export {
createLRU
};

87
node_modules/lru.min/package.json generated vendored
View File

@@ -1,87 +0,0 @@
{
"name": "lru.min",
"version": "1.1.3",
"description": "🔥 An extremely fast and efficient LRU cache for JavaScript with high compatibility (including Browsers).",
"main": "./lib/index.js",
"module": "./lib/index.mjs",
"types": "./lib/index.d.ts",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/wellwelwel/lru.min.git"
},
"bugs": {
"url": "https://github.com/wellwelwel/lru.min/issues"
},
"author": "https://github.com/wellwelwel",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wellwelwel"
},
"files": [
"browser",
"lib"
],
"engines": {
"node": ">=8.0.0",
"bun": ">=1.0.0",
"deno": ">=1.30.0"
},
"scripts": {
"benchmark:esm": "cd benchmark && npm ci && node index.mjs",
"benchmark:cjs": "cd benchmark && npm ci && node index.cjs",
"build:browser": "tsx tools/browserfy.ts",
"build:esm": "esbuild src/index.ts --outfile=lib/index.mjs --platform=node --target=node12 --format=esm",
"build": "rm -rf ./browser ./lib && tsc && npm run build:esm && npm run build:browser",
"test:node": "poku",
"test:bun": "bun poku",
"test:deno": "deno run -A npm:poku",
"test:coverage": "mcr --import tsx --config mcr.config.ts npm run test:node",
"lint": "npx @biomejs/biome lint && prettier --check .",
"lint:fix": "npx @biomejs/biome lint --write && prettier --write .github/workflows/*.yml .",
"update": "pu minor && npm i && (npm audit fix || true) && npm run lint:fix",
"size": "ls -lh lib/index.mjs | awk '{print $5}'"
},
"devDependencies": {
"@babel/core": "^7.28.5",
"@babel/preset-env": "^7.28.5",
"@biomejs/biome": "^1.9.4",
"@types/babel__core": "^7.20.5",
"@types/node": "^24.10.1",
"esbuild": "^0.27.0",
"monocart-coverage-reports": "^2.12.9",
"packages-update": "^2.0.0",
"poku": "^3.0.3-canary.ffab4562",
"prettier": "^3.6.2",
"terser": "^5.44.1",
"tsx": "^4.20.6",
"typescript": "^5.9.3"
},
"exports": {
".": {
"import": {
"types": "./lib/index.d.ts",
"default": "./lib/index.mjs"
},
"require": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
}
}
},
"keywords": [
"lru",
"cache",
"caching",
"hash",
"node",
"nodejs",
"bun",
"deno",
"typescript",
"browser",
"fast",
"lru-cache",
"quick-lru"
]
}

19
node_modules/mysql2/License generated vendored
View File

@@ -1,19 +0,0 @@
Copyright (c) 2016 Andrey Sidorov (sidorares@yandex.ru) and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

114
node_modules/mysql2/README.md generated vendored
View File

@@ -1,114 +0,0 @@
[npm-image]: https://img.shields.io/npm/v/mysql2.svg
[npm-url]: https://npmjs.com/package/mysql2
[node-version-image]: https://img.shields.io/node/v/mysql2.svg
[node-version-url]: https://nodejs.org/en/download
[downloads-image]: https://img.shields.io/npm/dm/mysql2.svg
[downloads-url]: https://npmjs.com/package/mysql2
[license-url]: https://github.com/sidorares/node-mysql2/blob/master/License
[license-image]: https://img.shields.io/npm/l/mysql2.svg?maxAge=2592000
[node-mysql]: https://github.com/mysqljs/mysql
[mysqljs]: https://github.com/mysqljs
[mysql-native]: https://github.com/sidorares/nodejs-mysql-native
[sidorares]: https://github.com/sidorares
[TooTallNate]: https://gist.github.com/TooTallNate
[starttls.js]: https://gist.github.com/TooTallNate/848444
[node-mariasql]: https://github.com/mscdex/node-mariasql
[contributors]: https://github.com/sidorares/node-mysql2/graphs/contributors
[contributing]: https://github.com/sidorares/node-mysql2/blob/master/Contributing.md
[docs-base]: https://sidorares.github.io/node-mysql2/docs
[docs-base-zh-CN]: https://sidorares.github.io/node-mysql2/zh-CN/docs
[docs-base-pt-BR]: https://sidorares.github.io/node-mysql2/pt-BR/docs
[docs-prepared-statements]: https://sidorares.github.io/node-mysql2/docs/documentation/prepared-statements
[docs-mysql-server]: https://sidorares.github.io/node-mysql2/docs/documentation/mysql-server
[docs-promise-wrapper]: https://sidorares.github.io/node-mysql2/docs/documentation/promise-wrapper
[docs-authentication-switch]: https://sidorares.github.io/node-mysql2/docs/documentation/authentication-switch
[docs-streams]: https://sidorares.github.io/node-mysql2/docs/documentation/extras
[docs-typescript-docs]: https://sidorares.github.io/node-mysql2/docs/documentation/typescript-examples
[docs-qs-pooling]: https://sidorares.github.io/node-mysql2/docs#using-connection-pools
[docs-qs-first-query]: https://sidorares.github.io/node-mysql2/docs#first-query
[docs-qs-using-prepared-statements]: https://sidorares.github.io/node-mysql2/docs#using-prepared-statements
[docs-examples]: https://sidorares.github.io/node-mysql2/docs/examples
[docs-faq]: https://sidorares.github.io/node-mysql2/docs/faq
[docs-documentation]: https://sidorares.github.io/node-mysql2/docs/documentation
[docs-contributing]: https://sidorares.github.io/node-mysql2/docs/contributing/website
[coverage]: https://img.shields.io/codecov/c/github/sidorares/node-mysql2
[coverage-url]: https://app.codecov.io/github/sidorares/node-mysql2
[ci-url]: https://github.com/sidorares/node-mysql2/actions/workflows/ci-coverage.yml?query=branch%3Amaster
[ci-image]: https://img.shields.io/github/actions/workflow/status/sidorares/node-mysql2/ci-coverage.yml?event=push&style=flat&label=CI&branch=master
# MySQL2
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![GitHub Workflow Status (with event)][ci-image]][ci-url]
[![Codecov][coverage]][coverage-url]
[![License][license-image]][license-url]
[English][docs-base] | [简体中文][docs-base-zh-CN] | [Português (BR)][docs-base-pt-BR]
> MySQL client for Node.js with focus on performance. Supports prepared statements, non-utf8 encodings, binary log protocol, compression, ssl [much more][docs-documentation].
**Table of Contents**
- [History and Why MySQL2](#history-and-why-mysql2)
- [Installation](#installation)
- [Documentation](#documentation)
- [Acknowledgements](#acknowledgements)
- [Contributing](#contributing)
## History and Why MySQL2
MySQL2 project is a continuation of [MySQL-Native][mysql-native]. Protocol parser code was rewritten from scratch and api changed to match popular [Node MySQL][node-mysql]. MySQL2 team is working together with [Node MySQL][node-mysql] team to factor out shared code and move it under [mysqljs][mysqljs] organization.
MySQL2 is mostly API compatible with [Node MySQL][node-mysql] and supports majority of features. MySQL2 also offers these additional features:
- Faster / Better Performance
- [Prepared Statements][docs-prepared-statements]
- MySQL Binary Log Protocol
- [MySQL Server][docs-mysql-server]
- Extended support for Encoding and Collation
- [Promise Wrapper][docs-promise-wrapper]
- Compression
- SSL and [Authentication Switch][docs-authentication-switch]
- [Custom Streams][docs-streams]
- [Pooling][docs-qs-pooling]
## Installation
MySQL2 is free from native bindings and can be installed on Linux, Mac OS or Windows without any issues.
```bash
npm install --save mysql2
```
If you are using TypeScript, you will need to install `@types/node`.
```bash
npm install --save-dev @types/node
```
> For TypeScript documentation and examples, see [here][docs-typescript-docs].
## Documentation
- [Quickstart][docs-base]
- [First Query][docs-qs-first-query], [Using Prepared Statements][docs-qs-using-prepared-statements], [Using Connection Pools][docs-qs-pooling] and more.
- [Documentation][docs-documentation]
- [Examples][docs-examples]
- [FAQ][docs-faq]
## Acknowledgements
- Internal protocol is written by [@sidorares][sidorares] [MySQL-Native][mysql-native].
- Constants, SQL parameters interpolation, Pooling, `ConnectionConfig` class taken from [Node MySQL][node-mysql].
- SSL upgrade code based on [@TooTallNate][TooTallNate] [code][starttls.js].
- Secure connection / compressed connection api flags compatible to [MariaSQL][node-mariasql] client.
- [Contributors][contributors].
## Contributing
Want to improve something in **MySQL2**?
Please check [Contributing.md][contributing] for detailed instruction on how to get started.
To contribute in **MySQL2 Documentation**, please visit the [Website Contributing Guidelines][docs-contributing] for detailed instruction on how to get started.

1
node_modules/mysql2/index.d.ts generated vendored
View File

@@ -1 +0,0 @@
export * from './typings/mysql/index.js';

77
node_modules/mysql2/index.js generated vendored
View File

@@ -1,77 +0,0 @@
'use strict';
const SqlString = require('sqlstring');
const ConnectionConfig = require('./lib/connection_config.js');
const parserCache = require('./lib/parsers/parser_cache.js');
const Connection = require('./lib/connection.js');
exports.createConnection = require('./lib/create_connection.js');
exports.connect = exports.createConnection;
exports.Connection = Connection;
exports.ConnectionConfig = ConnectionConfig;
const Pool = require('./lib/pool.js');
const PoolCluster = require('./lib/pool_cluster.js');
const createPool = require('./lib/create_pool.js');
const createPoolCluster = require('./lib/create_pool_cluster.js');
exports.createPool = createPool;
exports.createPoolCluster = createPoolCluster;
exports.createQuery = Connection.createQuery;
exports.Pool = Pool;
exports.PoolCluster = PoolCluster;
exports.createServer = function (handler) {
const Server = require('./lib/server.js');
const s = new Server();
if (handler) {
s.on('connection', handler);
}
return s;
};
exports.PoolConnection = require('./lib/pool_connection.js');
exports.authPlugins = require('./lib/auth_plugins');
exports.escape = SqlString.escape;
exports.escapeId = SqlString.escapeId;
exports.format = SqlString.format;
exports.raw = SqlString.raw;
exports.__defineGetter__(
'createConnectionPromise',
() => require('./promise.js').createConnection
);
exports.__defineGetter__(
'createPoolPromise',
() => require('./promise.js').createPool
);
exports.__defineGetter__(
'createPoolClusterPromise',
() => require('./promise.js').createPoolCluster
);
exports.__defineGetter__('Types', () => require('./lib/constants/types.js'));
exports.__defineGetter__('Charsets', () =>
require('./lib/constants/charsets.js')
);
exports.__defineGetter__('CharsetToEncoding', () =>
require('./lib/constants/charset_encodings.js')
);
exports.setMaxParserCache = function (max) {
parserCache.setMaxCache(max);
};
exports.clearParserCache = function () {
parserCache.clearCache();
};

95
node_modules/mysql2/lib/auth_41.js generated vendored
View File

@@ -1,95 +0,0 @@
'use strict';
/*
4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
SERVER: public_seed=create_random_string()
send(public_seed)
CLIENT: recv(public_seed)
hash_stage1=sha1("password")
hash_stage2=sha1(hash_stage1)
reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
// this three steps are done in scramble()
send(reply)
SERVER: recv(reply)
hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
candidate_hash2=sha1(hash_stage1)
check(candidate_hash2==hash_stage2)
server stores sha1(sha1(password)) ( hash_stag2)
*/
const crypto = require('crypto');
function sha1(msg, msg1, msg2) {
const hash = crypto.createHash('sha1');
hash.update(msg);
if (msg1) {
hash.update(msg1);
}
if (msg2) {
hash.update(msg2);
}
return hash.digest();
}
function xor(a, b) {
const result = Buffer.allocUnsafe(a.length);
for (let i = 0; i < a.length; i++) {
result[i] = a[i] ^ b[i];
}
return result;
}
exports.xor = xor;
function token(password, scramble1, scramble2) {
if (!password) {
return Buffer.alloc(0);
}
const stage1 = sha1(password);
return exports.calculateTokenFromPasswordSha(stage1, scramble1, scramble2);
}
exports.calculateTokenFromPasswordSha = function (
passwordSha,
scramble1,
scramble2
) {
// we use AUTH 41 here, and we need only the bytes we just need.
const authPluginData1 = scramble1.slice(0, 8);
const authPluginData2 = scramble2.slice(0, 12);
const stage2 = sha1(passwordSha);
const stage3 = sha1(authPluginData1, authPluginData2, stage2);
return xor(stage3, passwordSha);
};
exports.calculateToken = token;
exports.verifyToken = function (publicSeed1, publicSeed2, token, doubleSha) {
const hashStage1 = xor(token, sha1(publicSeed1, publicSeed2, doubleSha));
const candidateHash2 = sha1(hashStage1);
return candidateHash2.compare(doubleSha) === 0;
};
exports.doubleSha1 = function (password) {
return sha1(sha1(password));
};
function xorRotating(a, seed) {
const result = Buffer.allocUnsafe(a.length);
const seedLen = seed.length;
for (let i = 0; i < a.length; i++) {
result[i] = a[i] ^ seed[i % seedLen];
}
return result;
}
exports.xorRotating = xorRotating;

View File

@@ -1,108 +0,0 @@
'use strict';
// https://mysqlserverteam.com/mysql-8-0-4-new-default-authentication-plugin-caching_sha2_password/
const PLUGIN_NAME = 'caching_sha2_password';
const crypto = require('crypto');
const { xor, xorRotating } = require('../auth_41');
const REQUEST_SERVER_KEY_PACKET = Buffer.from([2]);
const FAST_AUTH_SUCCESS_PACKET = Buffer.from([3]);
const PERFORM_FULL_AUTHENTICATION_PACKET = Buffer.from([4]);
const STATE_INITIAL = 0;
const STATE_TOKEN_SENT = 1;
const STATE_WAIT_SERVER_KEY = 2;
const STATE_FINAL = -1;
function sha256(msg) {
const hash = crypto.createHash('sha256');
hash.update(msg);
return hash.digest();
}
function calculateToken(password, scramble) {
if (!password) {
return Buffer.alloc(0);
}
const stage1 = sha256(Buffer.from(password));
const stage2 = sha256(stage1);
const stage3 = sha256(Buffer.concat([stage2, scramble]));
return xor(stage1, stage3);
}
function encrypt(password, scramble, key) {
const stage1 = xorRotating(Buffer.from(`${password}\0`, 'utf8'), scramble);
return crypto.publicEncrypt(
{
key,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
},
stage1
);
}
module.exports =
(pluginOptions = {}) =>
({ connection }) => {
let state = 0;
let scramble = null;
const password = connection.config.password;
const authWithKey = (serverKey) => {
const _password = encrypt(password, scramble, serverKey);
state = STATE_FINAL;
return _password;
};
return (data) => {
switch (state) {
case STATE_INITIAL:
scramble = data.slice(0, 20);
state = STATE_TOKEN_SENT;
return calculateToken(password, scramble);
case STATE_TOKEN_SENT:
if (FAST_AUTH_SUCCESS_PACKET.equals(data)) {
state = STATE_FINAL;
return null;
}
if (PERFORM_FULL_AUTHENTICATION_PACKET.equals(data)) {
const isSecureConnection =
typeof pluginOptions.overrideIsSecure === 'undefined'
? connection.config.ssl || connection.config.socketPath
: pluginOptions.overrideIsSecure;
if (isSecureConnection) {
state = STATE_FINAL;
return Buffer.from(`${password}\0`, 'utf8');
}
// if client provides key we can save one extra roundrip on first connection
if (pluginOptions.serverPublicKey) {
return authWithKey(pluginOptions.serverPublicKey);
}
state = STATE_WAIT_SERVER_KEY;
return REQUEST_SERVER_KEY_PACKET;
}
throw new Error(
`Invalid AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_TOKEN_SENT state.`
);
case STATE_WAIT_SERVER_KEY:
if (pluginOptions.onServerPublicKey) {
pluginOptions.onServerPublicKey(data);
}
return authWithKey(data);
case STATE_FINAL:
throw new Error(
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`
);
}
throw new Error(
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in state ${state}`
);
};
};

View File

@@ -1,18 +0,0 @@
##
https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html
```js
const mysql = require('mysql');
mysql.createConnection({
authPlugins: {
caching_sha2_password: mysql.authPlugins.caching_sha2_password({
onServerPublikKey: function (key) {
console.log(key);
},
serverPublicKey: 'xxxyyy',
overrideIsSecure: true, //
}),
},
});
```

View File

@@ -1,8 +0,0 @@
'use strict';
module.exports = {
caching_sha2_password: require('./caching_sha2_password'),
mysql_clear_password: require('./mysql_clear_password'),
mysql_native_password: require('./mysql_native_password'),
sha256_password: require('./sha256_password'),
};

View File

@@ -1,17 +0,0 @@
'use strict';
function bufferFromStr(str) {
return Buffer.from(`${str}\0`);
}
const create_mysql_clear_password_plugin = (pluginOptions) =>
function mysql_clear_password_plugin({ connection, command }) {
const password =
command.password || pluginOptions.password || connection.config.password;
return function (/* pluginData */) {
return bufferFromStr(password);
};
};
module.exports = create_mysql_clear_password_plugin;

View File

@@ -1,34 +0,0 @@
'use strict';
//const PLUGIN_NAME = 'mysql_native_password';
const auth41 = require('../auth_41.js');
module.exports =
(pluginOptions) =>
({ connection, command }) => {
const password =
command.password || pluginOptions.password || connection.config.password;
const passwordSha1 =
command.passwordSha1 ||
pluginOptions.passwordSha1 ||
connection.config.passwordSha1;
return (data) => {
const authPluginData1 = data.slice(0, 8);
const authPluginData2 = data.slice(8, 20);
let authToken;
if (passwordSha1) {
authToken = auth41.calculateTokenFromPasswordSha(
passwordSha1,
authPluginData1,
authPluginData2
);
} else {
authToken = auth41.calculateToken(
password,
authPluginData1,
authPluginData2
);
}
return authToken;
};
};

View File

@@ -1,68 +0,0 @@
'use strict';
const PLUGIN_NAME = 'sha256_password';
const crypto = require('crypto');
const { xorRotating } = require('../auth_41');
const Tls = require('tls');
const REQUEST_SERVER_KEY_PACKET = Buffer.from([1]);
const STATE_INITIAL = 0;
const STATE_WAIT_SERVER_KEY = 1;
const STATE_FINAL = -1;
function encrypt(password, scramble, key) {
const stage1 = xorRotating(Buffer.from(`${password}\0`, 'utf8'), scramble);
return crypto.publicEncrypt(key, stage1);
}
module.exports =
(pluginOptions = {}) =>
({ connection }) => {
let state = 0;
let scramble = null;
const password = connection.config.password;
const authWithKey = (serverKey) => {
const _password = encrypt(password, scramble, serverKey);
state = STATE_FINAL;
return _password;
};
return (data) => {
switch (state) {
case STATE_INITIAL:
if (
connection.stream instanceof Tls.TLSSocket &&
connection.stream.encrypted === true
) {
// We don't need to encrypt passwords over TLS connection
return Buffer.from(`${password}\0`, 'utf8');
}
scramble = data.slice(0, 20);
// if client provides key we can save one extra roundrip on first connection
if (pluginOptions.serverPublicKey) {
return authWithKey(pluginOptions.serverPublicKey);
}
state = STATE_WAIT_SERVER_KEY;
return REQUEST_SERVER_KEY_PACKET;
case STATE_WAIT_SERVER_KEY:
if (pluginOptions.onServerPublicKey) {
pluginOptions.onServerPublicKey(data);
}
return authWithKey(data);
case STATE_FINAL:
throw new Error(
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`
);
}
throw new Error(
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in state ${state}`
);
};
};

View File

@@ -1,947 +0,0 @@
// This file was modified by Oracle on June 1, 2021.
// The changes involve new logic to handle an additional ERR Packet sent by
// the MySQL server when the connection is closed unexpectedly.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// This file was modified by Oracle on June 17, 2021.
// The changes involve logic to ensure the socket connection is closed when
// there is a fatal error.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// This file was modified by Oracle on September 21, 2021.
// The changes involve passing additional authentication factor passwords
// to the ChangeUser Command instance.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
'use strict';
const Net = require('net');
const Tls = require('tls');
const Timers = require('timers');
const EventEmitter = require('events').EventEmitter;
const Readable = require('stream').Readable;
const Queue = require('denque');
const SqlString = require('sqlstring');
const { createLRU } = require('lru.min');
const PacketParser = require('../packet_parser.js');
const Packets = require('../packets/index.js');
const Commands = require('../commands/index.js');
const ConnectionConfig = require('../connection_config.js');
const CharsetToEncoding = require('../constants/charset_encodings.js');
let _connectionId = 0;
let convertNamedPlaceholders = null;
class BaseConnection extends EventEmitter {
constructor(opts) {
super();
this.config = opts.config;
// TODO: fill defaults
// if no params, connect to /var/lib/mysql/mysql.sock ( /tmp/mysql.sock on OSX )
// if host is given, connect to host:3306
// TODO: use `/usr/local/mysql/bin/mysql_config --socket` output? as default socketPath
// if there is no host/port and no socketPath parameters?
if (!opts.config.stream) {
if (opts.config.socketPath) {
this.stream = Net.connect(opts.config.socketPath);
} else {
this.stream = Net.connect(opts.config.port, opts.config.host);
// Optionally enable keep-alive on the socket.
if (this.config.enableKeepAlive) {
this.stream.on('connect', () => {
this.stream.setKeepAlive(true, this.config.keepAliveInitialDelay);
});
}
// Enable TCP_NODELAY flag. This is needed so that the network packets
// are sent immediately to the server
this.stream.setNoDelay(true);
}
// if stream is a function, treat it as "stream agent / factory"
} else if (typeof opts.config.stream === 'function') {
this.stream = opts.config.stream(opts);
} else {
this.stream = opts.config.stream;
}
this._internalId = _connectionId++;
this._commands = new Queue();
this._command = null;
this._paused = false;
this._paused_packets = new Queue();
this._statements = createLRU({
max: this.config.maxPreparedStatements,
onEviction: function (_, statement) {
statement.close();
},
});
this.serverCapabilityFlags = 0;
this.authorized = false;
this.sequenceId = 0;
this.compressedSequenceId = 0;
this.threadId = null;
this._handshakePacket = null;
this._fatalError = null;
this._protocolError = null;
this._outOfOrderPackets = [];
this.clientEncoding = CharsetToEncoding[this.config.charsetNumber];
this.stream.on('error', this._handleNetworkError.bind(this));
// see https://gist.github.com/khoomeister/4985691#use-that-instead-of-bind
this.packetParser = new PacketParser((p) => {
this.handlePacket(p);
});
this.stream.on('data', (data) => {
if (this.connectTimeout) {
Timers.clearTimeout(this.connectTimeout);
this.connectTimeout = null;
}
this.packetParser.execute(data);
});
this.stream.on('end', () => {
// emit the end event so that the pooled connection can close the connection
this.emit('end');
});
this.stream.on('close', () => {
// we need to set this flag everywhere where we want connection to close
if (this._closing) {
return;
}
if (!this._protocolError) {
// no particular error message before disconnect
this._protocolError = new Error(
'Connection lost: The server closed the connection.'
);
this._protocolError.fatal = true;
this._protocolError.code = 'PROTOCOL_CONNECTION_LOST';
}
this._notifyError(this._protocolError);
});
let handshakeCommand;
if (!this.config.isServer) {
handshakeCommand = new Commands.ClientHandshake(this.config.clientFlags);
handshakeCommand.on('end', () => {
// this happens when handshake finishes early either because there was
// some fatal error or the server sent an error packet instead of
// an hello packet (for example, 'Too many connections' error)
if (
!handshakeCommand.handshake ||
this._fatalError ||
this._protocolError
) {
return;
}
this._handshakePacket = handshakeCommand.handshake;
this.threadId = handshakeCommand.handshake.connectionId;
this.emit('connect', handshakeCommand.handshake);
});
handshakeCommand.on('error', (err) => {
this._closing = true;
this._notifyError(err);
});
this.addCommand(handshakeCommand);
}
// in case there was no initial handshake but we need to read sting, assume it utf-8
// most common example: "Too many connections" error ( packet is sent immediately on connection attempt, we don't know server encoding yet)
// will be overwritten with actual encoding value as soon as server handshake packet is received
this.serverEncoding = 'utf8';
if (this.config.connectTimeout) {
const timeoutHandler = this._handleTimeoutError.bind(this);
this.connectTimeout = Timers.setTimeout(
timeoutHandler,
this.config.connectTimeout
);
}
}
_addCommandClosedState(cmd) {
const err = new Error(
"Can't add new command when connection is in closed state"
);
err.fatal = true;
if (cmd.onResult) {
cmd.onResult(err);
} else {
this.emit('error', err);
}
}
_handleFatalError(err) {
err.fatal = true;
// stop receiving packets
this.stream.removeAllListeners('data');
this.addCommand = this._addCommandClosedState;
this.write = () => {
this.emit('error', new Error("Can't write in closed state"));
};
this._notifyError(err);
this._fatalError = err;
}
_handleNetworkError(err) {
if (this.connectTimeout) {
Timers.clearTimeout(this.connectTimeout);
this.connectTimeout = null;
}
// Do not throw an error when a connection ends with a RST,ACK packet
if (err.code === 'ECONNRESET' && this._closing) {
return;
}
this._handleFatalError(err);
}
_handleTimeoutError() {
if (this.connectTimeout) {
Timers.clearTimeout(this.connectTimeout);
this.connectTimeout = null;
}
this.stream.destroy && this.stream.destroy();
const err = new Error('connect ETIMEDOUT');
err.errorno = 'ETIMEDOUT';
err.code = 'ETIMEDOUT';
err.syscall = 'connect';
this._handleNetworkError(err);
}
// notify all commands in the queue and bubble error as connection "error"
// called on stream error or unexpected termination
_notifyError(err) {
if (this.connectTimeout) {
Timers.clearTimeout(this.connectTimeout);
this.connectTimeout = null;
}
// prevent from emitting 'PROTOCOL_CONNECTION_LOST' after EPIPE or ECONNRESET
if (this._fatalError) {
return;
}
let command;
// if there is no active command, notify connection
// if there are commands and all of them have callbacks, pass error via callback
let bubbleErrorToConnection = !this._command;
if (this._command && this._command.onResult) {
this._command.onResult(err);
this._command = null;
// connection handshake is special because we allow it to be implicit
// if error happened during handshake, but there are others commands in queue
// then bubble error to other commands and not to connection
} else if (
!(
this._command &&
this._command.constructor === Commands.ClientHandshake &&
this._commands.length > 0
)
) {
bubbleErrorToConnection = true;
}
while ((command = this._commands.shift())) {
if (command.onResult) {
command.onResult(err);
} else {
bubbleErrorToConnection = true;
}
}
// notify connection if some comands in the queue did not have callbacks
// or if this is pool connection ( so it can be removed from pool )
if (bubbleErrorToConnection || this._pool) {
this.emit('error', err);
}
// close connection after emitting the event in case of a fatal error
if (err.fatal) {
this.close();
}
}
write(buffer) {
const result = this.stream.write(buffer, (err) => {
if (err) {
this._handleNetworkError(err);
}
});
if (!result) {
this.stream.emit('pause');
}
}
// http://dev.mysql.com/doc/internals/en/sequence-id.html
//
// The sequence-id is incremented with each packet and may wrap around.
// It starts at 0 and is reset to 0 when a new command
// begins in the Command Phase.
// http://dev.mysql.com/doc/internals/en/example-several-mysql-packets.html
_resetSequenceId() {
this.sequenceId = 0;
this.compressedSequenceId = 0;
}
_bumpCompressedSequenceId(numPackets) {
this.compressedSequenceId += numPackets;
this.compressedSequenceId %= 256;
}
_bumpSequenceId(numPackets) {
this.sequenceId += numPackets;
this.sequenceId %= 256;
}
writePacket(packet) {
const MAX_PACKET_LENGTH = 16777215;
const length = packet.length();
let chunk, offset, header;
if (length < MAX_PACKET_LENGTH) {
packet.writeHeader(this.sequenceId);
if (this.config.debug) {
console.log(
`${this._internalId} ${this.connectionId} <== ${this._command._commandName}#${this._command.stateName()}(${[this.sequenceId, packet._name, packet.length()].join(',')})`
);
console.log(
`${this._internalId} ${this.connectionId} <== ${packet.buffer.toString('hex')}`
);
}
this._bumpSequenceId(1);
this.write(packet.buffer);
} else {
if (this.config.debug) {
console.log(
`${this._internalId} ${this.connectionId} <== Writing large packet, raw content not written:`
);
console.log(
`${this._internalId} ${this.connectionId} <== ${this._command._commandName}#${this._command.stateName()}(${[this.sequenceId, packet._name, packet.length()].join(',')})`
);
}
for (offset = 4; offset < 4 + length; offset += MAX_PACKET_LENGTH) {
chunk = packet.buffer.slice(offset, offset + MAX_PACKET_LENGTH);
if (chunk.length === MAX_PACKET_LENGTH) {
header = Buffer.from([0xff, 0xff, 0xff, this.sequenceId]);
} else {
header = Buffer.from([
chunk.length & 0xff,
(chunk.length >> 8) & 0xff,
(chunk.length >> 16) & 0xff,
this.sequenceId,
]);
}
this._bumpSequenceId(1);
this.write(header);
this.write(chunk);
}
}
}
// 0.11+ environment
startTLS(onSecure) {
if (this.config.debug) {
console.log('Upgrading connection to TLS');
}
const secureContext = Tls.createSecureContext({
ca: this.config.ssl.ca,
cert: this.config.ssl.cert,
ciphers: this.config.ssl.ciphers,
key: this.config.ssl.key,
passphrase: this.config.ssl.passphrase,
minVersion: this.config.ssl.minVersion,
maxVersion: this.config.ssl.maxVersion,
});
const rejectUnauthorized = this.config.ssl.rejectUnauthorized;
const verifyIdentity = this.config.ssl.verifyIdentity;
const servername = Net.isIP(this.config.host)
? undefined
: this.config.host;
let secureEstablished = false;
this.stream.removeAllListeners('data');
const secureSocket = Tls.connect(
{
rejectUnauthorized,
requestCert: rejectUnauthorized,
checkServerIdentity: verifyIdentity
? Tls.checkServerIdentity
: function () {
return undefined;
},
secureContext,
isServer: false,
socket: this.stream,
servername,
},
() => {
secureEstablished = true;
if (rejectUnauthorized) {
if (typeof servername === 'string' && verifyIdentity) {
const cert = secureSocket.getPeerCertificate(true);
const serverIdentityCheckError = Tls.checkServerIdentity(
servername,
cert
);
if (serverIdentityCheckError) {
onSecure(serverIdentityCheckError);
return;
}
}
}
onSecure();
}
);
// error handler for secure socket
secureSocket.on('error', (err) => {
if (secureEstablished) {
this._handleNetworkError(err);
} else {
onSecure(err);
}
});
secureSocket.on('data', (data) => {
this.packetParser.execute(data);
});
this.stream = secureSocket;
}
protocolError(message, code) {
// Starting with MySQL 8.0.24, if the client closes the connection
// unexpectedly, the server will send a last ERR Packet, which we can
// safely ignore.
// https://dev.mysql.com/worklog/task/?id=12999
if (this._closing) {
return;
}
const err = new Error(message);
err.fatal = true;
err.code = code || 'PROTOCOL_ERROR';
this.emit('error', err);
}
get fatalError() {
return this._fatalError;
}
handlePacket(packet) {
if (this._paused) {
this._paused_packets.push(packet);
return;
}
if (this.config.debug) {
if (packet) {
console.log(
` raw: ${packet.buffer
.slice(packet.offset, packet.offset + packet.length())
.toString('hex')}`
);
console.trace();
const commandName = this._command
? this._command._commandName
: '(no command)';
const stateName = this._command
? this._command.stateName()
: '(no command)';
console.log(
`${this._internalId} ${this.connectionId} ==> ${commandName}#${stateName}(${[packet.sequenceId, packet.type(), packet.length()].join(',')})`
);
}
}
if (!this._command) {
const marker = packet.peekByte();
// If it's an Err Packet, we should use it.
if (marker === 0xff) {
const error = Packets.Error.fromPacket(packet);
this.protocolError(error.message, error.code);
} else {
// Otherwise, it means it's some other unexpected packet.
this.protocolError(
'Unexpected packet while no commands in the queue',
'PROTOCOL_UNEXPECTED_PACKET'
);
}
this.close();
return;
}
if (packet) {
// Note: when server closes connection due to inactivity, Err packet ER_CLIENT_INTERACTION_TIMEOUT from MySQL 8.0.24, sequenceId will be 0
if (this.sequenceId !== packet.sequenceId) {
const err = new Error(
`Warning: got packets out of order. Expected ${this.sequenceId} but received ${packet.sequenceId}`
);
err.expected = this.sequenceId;
err.received = packet.sequenceId;
this.emit('warn', err); // REVIEW
console.error(err.message);
}
this._bumpSequenceId(packet.numPackets);
}
try {
if (this._fatalError) {
// skip remaining packets after client is in the error state
return;
}
const done = this._command.execute(packet, this);
if (done) {
this._command = this._commands.shift();
if (this._command) {
this.sequenceId = 0;
this.compressedSequenceId = 0;
this.handlePacket();
}
}
} catch (err) {
this._handleFatalError(err);
this.stream.destroy();
}
}
addCommand(cmd) {
// this.compressedSequenceId = 0;
// this.sequenceId = 0;
if (this.config.debug) {
const commandName = cmd.constructor.name;
console.log(`Add command: ${commandName}`);
cmd._commandName = commandName;
}
if (!this._command) {
this._command = cmd;
this.handlePacket();
} else {
this._commands.push(cmd);
}
return cmd;
}
format(sql, values) {
if (typeof this.config.queryFormat === 'function') {
return this.config.queryFormat.call(
this,
sql,
values,
this.config.timezone
);
}
const opts = {
sql: sql,
values: values,
};
this._resolveNamedPlaceholders(opts);
return SqlString.format(
opts.sql,
opts.values,
this.config.stringifyObjects,
this.config.timezone
);
}
escape(value) {
return SqlString.escape(value, false, this.config.timezone);
}
escapeId(value) {
return SqlString.escapeId(value, false);
}
raw(sql) {
return SqlString.raw(sql);
}
_resolveNamedPlaceholders(options) {
let unnamed;
if (this.config.namedPlaceholders || options.namedPlaceholders) {
if (Array.isArray(options.values)) {
// if an array is provided as the values, assume the conversion is not necessary.
// this allows the usage of unnamed placeholders even if the namedPlaceholders flag is enabled.
return;
}
if (convertNamedPlaceholders === null) {
convertNamedPlaceholders = require('named-placeholders')();
}
unnamed = convertNamedPlaceholders(options.sql, options.values);
options.sql = unnamed[0];
options.values = unnamed[1];
}
}
query(sql, values, cb) {
let cmdQuery;
if (sql.constructor === Commands.Query) {
cmdQuery = sql;
} else {
cmdQuery = BaseConnection.createQuery(sql, values, cb, this.config);
}
this._resolveNamedPlaceholders(cmdQuery);
const rawSql = this.format(
cmdQuery.sql,
cmdQuery.values !== undefined ? cmdQuery.values : []
);
cmdQuery.sql = rawSql;
return this.addCommand(cmdQuery);
}
pause() {
this._paused = true;
this.stream.pause();
}
resume() {
let packet;
this._paused = false;
while ((packet = this._paused_packets.shift())) {
this.handlePacket(packet);
// don't resume if packet handler paused connection
if (this._paused) {
return;
}
}
this.stream.resume();
}
// TODO: named placeholders support
prepare(options, cb) {
if (typeof options === 'string') {
options = { sql: options };
}
return this.addCommand(new Commands.Prepare(options, cb));
}
unprepare(sql) {
let options = {};
if (typeof sql === 'object') {
options = sql;
} else {
options.sql = sql;
}
const key = BaseConnection.statementKey(options);
const stmt = this._statements.get(key);
if (stmt) {
this._statements.delete(key);
stmt.close();
}
return stmt;
}
execute(sql, values, cb) {
let options = {
infileStreamFactory: this.config.infileStreamFactory,
};
if (typeof sql === 'object') {
// execute(options, cb)
options = {
...options,
...sql,
sql: sql.sql,
values: sql.values,
};
if (typeof values === 'function') {
cb = values;
} else {
options.values = options.values || values;
}
} else if (typeof values === 'function') {
// execute(sql, cb)
cb = values;
options.sql = sql;
options.values = undefined;
} else {
// execute(sql, values, cb)
options.sql = sql;
options.values = values;
}
this._resolveNamedPlaceholders(options);
// check for values containing undefined
if (options.values) {
//If namedPlaceholder is not enabled and object is passed as bind parameters
if (!Array.isArray(options.values)) {
throw new TypeError(
'Bind parameters must be array if namedPlaceholders parameter is not enabled'
);
}
options.values.forEach((val) => {
//If namedPlaceholder is not enabled and object is passed as bind parameters
if (!Array.isArray(options.values)) {
throw new TypeError(
'Bind parameters must be array if namedPlaceholders parameter is not enabled'
);
}
if (val === undefined) {
throw new TypeError(
'Bind parameters must not contain undefined. To pass SQL NULL specify JS null'
);
}
if (typeof val === 'function') {
throw new TypeError(
'Bind parameters must not contain function(s). To pass the body of a function as a string call .toString() first'
);
}
});
}
const executeCommand = new Commands.Execute(options, cb);
const prepareCommand = new Commands.Prepare(options, (err, stmt) => {
if (err) {
// skip execute command if prepare failed, we have main
// combined callback here
executeCommand.start = function () {
return null;
};
if (cb) {
cb(err);
} else {
executeCommand.emit('error', err);
}
executeCommand.emit('end');
return;
}
executeCommand.statement = stmt;
});
this.addCommand(prepareCommand);
this.addCommand(executeCommand);
return executeCommand;
}
changeUser(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
const charsetNumber = options.charset
? ConnectionConfig.getCharsetNumber(options.charset)
: this.config.charsetNumber;
return this.addCommand(
new Commands.ChangeUser(
{
user: options.user || this.config.user,
// for the purpose of multi-factor authentication, or not, the main
// password (used for the 1st authentication factor) can also be
// provided via the "password1" option
password:
options.password ||
options.password1 ||
this.config.password ||
this.config.password1,
password2: options.password2 || this.config.password2,
password3: options.password3 || this.config.password3,
passwordSha1: options.passwordSha1 || this.config.passwordSha1,
database: options.database || this.config.database,
timeout: options.timeout,
charsetNumber: charsetNumber,
currentConfig: this.config,
},
(err) => {
if (err) {
err.fatal = true;
}
if (callback) {
callback(err);
}
}
)
);
}
// transaction helpers
beginTransaction(cb) {
return this.query('START TRANSACTION', cb);
}
commit(cb) {
return this.query('COMMIT', cb);
}
rollback(cb) {
return this.query('ROLLBACK', cb);
}
ping(cb) {
return this.addCommand(new Commands.Ping(cb));
}
_registerSlave(opts, cb) {
return this.addCommand(new Commands.RegisterSlave(opts, cb));
}
_binlogDump(opts, cb) {
return this.addCommand(new Commands.BinlogDump(opts, cb));
}
// currently just alias to close
destroy() {
this.close();
}
close() {
if (this.connectTimeout) {
Timers.clearTimeout(this.connectTimeout);
this.connectTimeout = null;
}
this._closing = true;
this.stream.end();
this.addCommand = this._addCommandClosedState;
}
createBinlogStream(opts) {
// TODO: create proper stream class
// TODO: use through2
let test = 1;
const stream = new Readable({ objectMode: true });
stream._read = function () {
return {
data: test++,
};
};
this._registerSlave(opts, () => {
const dumpCmd = this._binlogDump(opts);
dumpCmd.on('event', (ev) => {
stream.push(ev);
});
dumpCmd.on('eof', () => {
stream.push(null);
// if non-blocking, then close stream to prevent errors
if (opts.flags && opts.flags & 0x01) {
this.close();
}
});
// TODO: pipe errors as well
});
return stream;
}
connect(cb) {
if (!cb) {
return;
}
if (this._fatalError || this._protocolError) {
return cb(this._fatalError || this._protocolError);
}
if (this._handshakePacket) {
return cb(null, this);
}
let connectCalled = 0;
function callbackOnce(isErrorHandler) {
return function (param) {
if (!connectCalled) {
if (isErrorHandler) {
cb(param);
} else {
cb(null, param);
}
}
connectCalled = 1;
};
}
this.once('error', callbackOnce(true));
this.once('connect', callbackOnce(false));
}
// ===================================
// outgoing server connection methods
// ===================================
writeColumns(columns) {
this.writePacket(Packets.ResultSetHeader.toPacket(columns.length));
columns.forEach((column) => {
this.writePacket(
Packets.ColumnDefinition.toPacket(column, this.serverConfig.encoding)
);
});
this.writeEof();
}
// row is array of columns, not hash
writeTextRow(column) {
this.writePacket(
Packets.TextRow.toPacket(column, this.serverConfig.encoding)
);
}
writeBinaryRow(column) {
this.writePacket(
Packets.BinaryRow.toPacket(column, this.serverConfig.encoding)
);
}
writeTextResult(rows, columns, binary = false) {
this.writeColumns(columns);
rows.forEach((row) => {
const arrayRow = new Array(columns.length);
columns.forEach((column) => {
arrayRow.push(row[column.name]);
});
if (binary) {
this.writeBinaryRow(arrayRow);
} else this.writeTextRow(arrayRow);
});
this.writeEof();
}
writeEof(warnings, statusFlags) {
this.writePacket(Packets.EOF.toPacket(warnings, statusFlags));
}
writeOk(args) {
if (!args) {
args = { affectedRows: 0 };
}
this.writePacket(Packets.OK.toPacket(args, this.serverConfig.encoding));
}
writeError(args) {
// if we want to send error before initial hello was sent, use default encoding
const encoding = this.serverConfig ? this.serverConfig.encoding : 'cesu8';
this.writePacket(Packets.Error.toPacket(args, encoding));
}
serverHandshake(args) {
this.serverConfig = args;
this.serverConfig.encoding =
CharsetToEncoding[this.serverConfig.characterSet];
return this.addCommand(new Commands.ServerHandshake(args));
}
// ===============================================================
end(callback) {
if (this.config.isServer) {
this._closing = true;
const quitCmd = new EventEmitter();
setImmediate(() => {
this.stream.end();
quitCmd.emit('end');
});
return quitCmd;
}
// trigger error if more commands enqueued after end command
const quitCmd = this.addCommand(new Commands.Quit(callback));
this.addCommand = this._addCommandClosedState;
return quitCmd;
}
static createQuery(sql, values, cb, config) {
let options = {
rowsAsArray: config.rowsAsArray,
infileStreamFactory: config.infileStreamFactory,
};
if (typeof sql === 'object') {
// query(options, cb)
options = {
...options,
...sql,
sql: sql.sql,
values: sql.values,
};
if (typeof values === 'function') {
cb = values;
} else if (values !== undefined) {
options.values = values;
}
} else if (typeof values === 'function') {
// query(sql, cb)
cb = values;
options.sql = sql;
options.values = undefined;
} else {
// query(sql, values, cb)
options.sql = sql;
options.values = values;
}
return new Commands.Query(options, cb);
}
static statementKey(options) {
return `${typeof options.nestTables}/${options.nestTables}/${options.rowsAsArray}${options.sql}`;
}
}
module.exports = BaseConnection;

237
node_modules/mysql2/lib/base/pool.js generated vendored
View File

@@ -1,237 +0,0 @@
'use strict';
const process = require('process');
const SqlString = require('sqlstring');
const EventEmitter = require('events').EventEmitter;
const PoolConnection = require('../pool_connection.js');
const Queue = require('denque');
const BaseConnection = require('./connection.js');
function spliceConnection(queue, connection) {
const len = queue.length;
for (let i = 0; i < len; i++) {
if (queue.get(i) === connection) {
queue.removeOne(i);
break;
}
}
}
class BasePool extends EventEmitter {
constructor(options) {
super();
this.config = options.config;
this.config.connectionConfig.pool = this;
this._allConnections = new Queue();
this._freeConnections = new Queue();
this._connectionQueue = new Queue();
this._closed = false;
if (this.config.maxIdle < this.config.connectionLimit) {
// create idle connection timeout automatically release job
this._removeIdleTimeoutConnections();
}
}
getConnection(cb) {
if (this._closed) {
return process.nextTick(() => cb(new Error('Pool is closed.')));
}
let connection;
if (this._freeConnections.length > 0) {
connection = this._freeConnections.pop();
this.emit('acquire', connection);
return process.nextTick(() => cb(null, connection));
}
if (
this.config.connectionLimit === 0 ||
this._allConnections.length < this.config.connectionLimit
) {
connection = new PoolConnection(this, {
config: this.config.connectionConfig,
});
this._allConnections.push(connection);
return connection.connect((err) => {
if (this._closed) {
return cb(new Error('Pool is closed.'));
}
if (err) {
return cb(err);
}
this.emit('connection', connection);
this.emit('acquire', connection);
return cb(null, connection);
});
}
if (!this.config.waitForConnections) {
return process.nextTick(() => cb(new Error('No connections available.')));
}
if (
this.config.queueLimit &&
this._connectionQueue.length >= this.config.queueLimit
) {
return cb(new Error('Queue limit reached.'));
}
this.emit('enqueue');
return this._connectionQueue.push(cb);
}
releaseConnection(connection) {
let cb;
if (!connection._pool) {
// The connection has been removed from the pool and is no longer good.
if (this._connectionQueue.length) {
cb = this._connectionQueue.shift();
process.nextTick(this.getConnection.bind(this, cb));
}
} else if (this._connectionQueue.length) {
cb = this._connectionQueue.shift();
process.nextTick(cb.bind(null, null, connection));
} else {
this._freeConnections.push(connection);
this.emit('release', connection);
}
}
end(cb) {
this._closed = true;
clearTimeout(this._removeIdleTimeoutConnectionsTimer);
if (typeof cb !== 'function') {
cb = function (err) {
if (err) {
throw err;
}
};
}
let calledBack = false;
let closedConnections = 0;
let connection;
const endCB = function (err) {
if (calledBack) {
return;
}
if (err || ++closedConnections >= this._allConnections.length) {
calledBack = true;
cb(err);
return;
}
}.bind(this);
if (this._allConnections.length === 0) {
endCB();
return;
}
for (let i = 0; i < this._allConnections.length; i++) {
connection = this._allConnections.get(i);
connection._realEnd(endCB);
}
}
query(sql, values, cb) {
const cmdQuery = BaseConnection.createQuery(
sql,
values,
cb,
this.config.connectionConfig
);
if (typeof cmdQuery.namedPlaceholders === 'undefined') {
cmdQuery.namedPlaceholders =
this.config.connectionConfig.namedPlaceholders;
}
this.getConnection((err, conn) => {
if (err) {
if (typeof cmdQuery.onResult === 'function') {
cmdQuery.onResult(err);
} else {
cmdQuery.emit('error', err);
}
return;
}
try {
conn.query(cmdQuery).once('end', () => {
conn.release();
});
} catch (e) {
conn.release();
throw e;
}
});
return cmdQuery;
}
execute(sql, values, cb) {
// TODO construct execute command first here and pass it to connection.execute
// so that polymorphic arguments logic is there in one place
if (typeof values === 'function') {
cb = values;
values = [];
}
this.getConnection((err, conn) => {
if (err) {
return cb(err);
}
try {
conn.execute(sql, values, cb).once('end', () => {
conn.release();
});
} catch (e) {
conn.release();
return cb(e);
}
});
}
_removeConnection(connection) {
// Remove connection from all connections
spliceConnection(this._allConnections, connection);
// Remove connection from free connections
spliceConnection(this._freeConnections, connection);
this.releaseConnection(connection);
}
_removeIdleTimeoutConnections() {
if (this._removeIdleTimeoutConnectionsTimer) {
clearTimeout(this._removeIdleTimeoutConnectionsTimer);
}
this._removeIdleTimeoutConnectionsTimer = setTimeout(() => {
try {
while (
this._freeConnections.length > this.config.maxIdle ||
(this._freeConnections.length > 0 &&
Date.now() - this._freeConnections.get(0).lastActiveTime >
this.config.idleTimeout)
) {
if (this.config.connectionConfig.gracefulEnd) {
this._freeConnections.get(0).end();
} else {
this._freeConnections.get(0).destroy();
}
}
} finally {
this._removeIdleTimeoutConnections();
}
}, 1000);
}
format(sql, values) {
return SqlString.format(
sql,
values,
this.config.connectionConfig.stringifyObjects,
this.config.connectionConfig.timezone
);
}
escape(value) {
return SqlString.escape(
value,
this.config.connectionConfig.stringifyObjects,
this.config.connectionConfig.timezone
);
}
escapeId(value) {
return SqlString.escapeId(value, false);
}
}
module.exports = BasePool;

View File

@@ -1,70 +0,0 @@
'use strict';
const BaseConnection = require('./connection.js');
class BasePoolConnection extends BaseConnection {
constructor(pool, options) {
super(options);
this._pool = pool;
// The last active time of this connection
this.lastActiveTime = Date.now();
// When a fatal error occurs the connection's protocol ends, which will cause
// the connection to end as well, thus we only need to watch for the end event
// and we will be notified of disconnects.
// REVIEW: Moved to `once`
this.once('end', () => {
this._removeFromPool();
});
this.once('error', () => {
this._removeFromPool();
});
}
release() {
if (!this._pool || this._pool._closed) {
return;
}
// update last active time
this.lastActiveTime = Date.now();
this._pool.releaseConnection(this);
}
end() {
if (this.config.gracefulEnd) {
this._removeFromPool();
super.end();
return;
}
const err = new Error(
'Calling conn.end() to release a pooled connection is ' +
'deprecated. In next version calling conn.end() will be ' +
'restored to default conn.end() behavior. Use ' +
'conn.release() instead.'
);
this.emit('warn', err);
console.warn(err.message);
this.release();
}
destroy() {
this._removeFromPool();
super.destroy();
}
_removeFromPool() {
if (!this._pool || this._pool._closed) {
return;
}
const pool = this._pool;
this._pool = null;
pool._removeConnection(this);
}
}
BasePoolConnection.statementKey = BaseConnection.statementKey;
module.exports = BasePoolConnection;
// TODO: Remove this when we are removing PoolConnection#end
BasePoolConnection.prototype._realEnd = BaseConnection.prototype.end;

View File

@@ -1,111 +0,0 @@
// This file was modified by Oracle on July 5, 2021.
// Errors generated by asynchronous authentication plugins are now being
// handled and subsequently emitted at the command level.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
'use strict';
const Packets = require('../packets/index.js');
const sha256_password = require('../auth_plugins/sha256_password');
const caching_sha2_password = require('../auth_plugins/caching_sha2_password.js');
const mysql_native_password = require('../auth_plugins/mysql_native_password.js');
const mysql_clear_password = require('../auth_plugins/mysql_clear_password.js');
const standardAuthPlugins = {
sha256_password: sha256_password({}),
caching_sha2_password: caching_sha2_password({}),
mysql_native_password: mysql_native_password({}),
mysql_clear_password: mysql_clear_password({}),
};
function warnLegacyAuthSwitch() {
console.warn(
'WARNING! authSwitchHandler api is deprecated, please use new authPlugins api'
);
}
function authSwitchPluginError(error, command) {
// Authentication errors are fatal
error.code = 'AUTH_SWITCH_PLUGIN_ERROR';
error.fatal = true;
command.emit('error', error);
}
function authSwitchRequest(packet, connection, command) {
const { pluginName, pluginData } =
Packets.AuthSwitchRequest.fromPacket(packet);
let authPlugin =
connection.config.authPlugins && connection.config.authPlugins[pluginName];
// legacy plugin api don't allow to override mysql_native_password
// if pluginName is mysql_native_password it's using standard auth4.1 auth
if (
connection.config.authSwitchHandler &&
pluginName !== 'mysql_native_password'
) {
const legacySwitchHandler = connection.config.authSwitchHandler;
warnLegacyAuthSwitch();
legacySwitchHandler({ pluginName, pluginData }, (err, data) => {
if (err) {
return authSwitchPluginError(err, command);
}
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
});
return;
}
if (!authPlugin) {
authPlugin = standardAuthPlugins[pluginName];
}
if (!authPlugin) {
throw new Error(
`Server requests authentication using unknown plugin ${pluginName}. See ${'TODO: add plugins doco here'} on how to configure or author authentication plugins.`
);
}
connection._authPlugin = authPlugin({ connection, command });
Promise.resolve(connection._authPlugin(pluginData))
.then((data) => {
if (data) {
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
}
})
.catch((err) => {
authSwitchPluginError(err, command);
});
}
function authSwitchRequestMoreData(packet, connection, command) {
const { data } = Packets.AuthSwitchRequestMoreData.fromPacket(packet);
if (connection.config.authSwitchHandler) {
const legacySwitchHandler = connection.config.authSwitchHandler;
warnLegacyAuthSwitch();
legacySwitchHandler({ pluginData: data }, (err, data) => {
if (err) {
return authSwitchPluginError(err, command);
}
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
});
return;
}
if (!connection._authPlugin) {
throw new Error(
'AuthPluginMoreData received but no auth plugin instance found'
);
}
Promise.resolve(connection._authPlugin(data))
.then((data) => {
if (data) {
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
}
})
.catch((err) => {
authSwitchPluginError(err, command);
});
}
module.exports = {
authSwitchRequest,
authSwitchRequestMoreData,
};

View File

@@ -1,109 +0,0 @@
'use strict';
const Command = require('./command');
const Packets = require('../packets');
const eventParsers = [];
class BinlogEventHeader {
constructor(packet) {
this.timestamp = packet.readInt32();
this.eventType = packet.readInt8();
this.serverId = packet.readInt32();
this.eventSize = packet.readInt32();
this.logPos = packet.readInt32();
this.flags = packet.readInt16();
}
}
class BinlogDump extends Command {
constructor(opts) {
super();
// this.onResult = callback;
this.opts = opts;
}
start(packet, connection) {
const newPacket = new Packets.BinlogDump(this.opts);
connection.writePacket(newPacket.toPacket(1));
return BinlogDump.prototype.binlogData;
}
binlogData(packet) {
// ok - continue consuming events
// error - error
// eof - end of binlog
if (packet.isEOF()) {
this.emit('eof');
return null;
}
// binlog event header
packet.readInt8();
const header = new BinlogEventHeader(packet);
const EventParser = eventParsers[header.eventType];
let event;
if (EventParser) {
event = new EventParser(packet);
} else {
event = {
name: 'UNKNOWN',
};
}
event.header = header;
this.emit('event', event);
return BinlogDump.prototype.binlogData;
}
}
class RotateEvent {
constructor(packet) {
this.pposition = packet.readInt32();
// TODO: read uint64 here
packet.readInt32(); // positionDword2
this.nextBinlog = packet.readString();
this.name = 'RotateEvent';
}
}
class FormatDescriptionEvent {
constructor(packet) {
this.binlogVersion = packet.readInt16();
this.serverVersion = packet.readString(50).replace(/\u0000.*/, ''); // eslint-disable-line no-control-regex
this.createTimestamp = packet.readInt32();
this.eventHeaderLength = packet.readInt8(); // should be 19
this.eventsLength = packet.readBuffer();
this.name = 'FormatDescriptionEvent';
}
}
class QueryEvent {
constructor(packet) {
const parseStatusVars = require('../packets/binlog_query_statusvars.js');
this.slaveProxyId = packet.readInt32();
this.executionTime = packet.readInt32();
const schemaLength = packet.readInt8();
this.errorCode = packet.readInt16();
const statusVarsLength = packet.readInt16();
const statusVars = packet.readBuffer(statusVarsLength);
this.schema = packet.readString(schemaLength);
packet.readInt8(); // should be zero
this.statusVars = parseStatusVars(statusVars);
this.query = packet.readString();
this.name = 'QueryEvent';
}
}
class XidEvent {
constructor(packet) {
this.binlogVersion = packet.readInt16();
this.xid = packet.readInt64();
this.name = 'XidEvent';
}
}
eventParsers[2] = QueryEvent;
eventParsers[4] = RotateEvent;
eventParsers[15] = FormatDescriptionEvent;
eventParsers[16] = XidEvent;
module.exports = BinlogDump;

View File

@@ -1,68 +0,0 @@
// This file was modified by Oracle on September 21, 2021.
// The changes involve saving additional authentication factor passwords
// in the command scope and enabling multi-factor authentication in the
// client-side when the server supports it.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
'use strict';
const Command = require('./command.js');
const Packets = require('../packets/index.js');
const ClientConstants = require('../constants/client');
const ClientHandshake = require('./client_handshake.js');
const CharsetToEncoding = require('../constants/charset_encodings.js');
class ChangeUser extends Command {
constructor(options, callback) {
super();
this.onResult = callback;
this.user = options.user;
this.password = options.password;
// "password1" is an alias of "password"
this.password1 = options.password;
this.password2 = options.password2;
this.password3 = options.password3;
this.database = options.database;
this.passwordSha1 = options.passwordSha1;
this.charsetNumber = options.charsetNumber;
this.currentConfig = options.currentConfig;
this.authenticationFactor = 0;
}
start(packet, connection) {
const newPacket = new Packets.ChangeUser({
flags: connection.config.clientFlags,
user: this.user,
database: this.database,
charsetNumber: this.charsetNumber,
password: this.password,
passwordSha1: this.passwordSha1,
authPluginData1: connection._handshakePacket.authPluginData1,
authPluginData2: connection._handshakePacket.authPluginData2,
});
this.currentConfig.user = this.user;
this.currentConfig.password = this.password;
this.currentConfig.database = this.database;
this.currentConfig.charsetNumber = this.charsetNumber;
connection.clientEncoding = CharsetToEncoding[this.charsetNumber];
// clear prepared statements cache as all statements become invalid after changeUser
connection._statements.clear();
connection.writePacket(newPacket.toPacket());
// check if the server supports multi-factor authentication
const multiFactorAuthentication =
connection.serverCapabilityFlags &
ClientConstants.MULTI_FACTOR_AUTHENTICATION;
if (multiFactorAuthentication) {
// if the server supports multi-factor authentication, we enable it in
// the client
this.authenticationFactor = 1;
}
return ChangeUser.prototype.handshakeResult;
}
}
ChangeUser.prototype.handshakeResult =
ClientHandshake.prototype.handshakeResult;
ChangeUser.prototype.calculateNativePasswordAuthToken =
ClientHandshake.prototype.calculateNativePasswordAuthToken;
module.exports = ChangeUser;

View File

@@ -1,241 +0,0 @@
// This file was modified by Oracle on June 17, 2021.
// Handshake errors are now maked as fatal and the corresponding events are
// emitted in the command instance itself.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// This file was modified by Oracle on September 21, 2021.
// Handshake workflow now supports additional authentication factors requested
// by the server.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
'use strict';
const Command = require('./command.js');
const Packets = require('../packets/index.js');
const ClientConstants = require('../constants/client.js');
const CharsetToEncoding = require('../constants/charset_encodings.js');
const auth41 = require('../auth_41.js');
function flagNames(flags) {
const res = [];
for (const c in ClientConstants) {
if (flags & ClientConstants[c]) {
res.push(c.replace(/_/g, ' ').toLowerCase());
}
}
return res;
}
class ClientHandshake extends Command {
constructor(clientFlags) {
super();
this.handshake = null;
this.clientFlags = clientFlags;
this.authenticationFactor = 0;
}
start() {
return ClientHandshake.prototype.handshakeInit;
}
sendSSLRequest(connection) {
const sslRequest = new Packets.SSLRequest(
this.clientFlags,
connection.config.charsetNumber
);
connection.writePacket(sslRequest.toPacket());
}
sendCredentials(connection) {
if (connection.config.debug) {
// eslint-disable-next-line
console.log(
'Sending handshake packet: flags:%d=(%s)',
this.clientFlags,
flagNames(this.clientFlags).join(', ')
);
}
this.user = connection.config.user;
this.password = connection.config.password;
// "password1" is an alias to the original "password" value
// to make it easier to integrate multi-factor authentication
this.password1 = connection.config.password;
// "password2" and "password3" are the 2nd and 3rd factor authentication
// passwords, which can be undefined depending on the authentication
// plugin being used
this.password2 = connection.config.password2;
this.password3 = connection.config.password3;
this.passwordSha1 = connection.config.passwordSha1;
this.database = connection.config.database;
this.authPluginName = this.handshake.authPluginName;
const handshakeResponse = new Packets.HandshakeResponse({
flags: this.clientFlags,
user: this.user,
database: this.database,
password: this.password,
passwordSha1: this.passwordSha1,
charsetNumber: connection.config.charsetNumber,
authPluginData1: this.handshake.authPluginData1,
authPluginData2: this.handshake.authPluginData2,
compress: connection.config.compress,
connectAttributes: connection.config.connectAttributes,
});
connection.writePacket(handshakeResponse.toPacket());
}
calculateNativePasswordAuthToken(authPluginData) {
// TODO: dont split into authPluginData1 and authPluginData2, instead join when 1 & 2 received
const authPluginData1 = authPluginData.slice(0, 8);
const authPluginData2 = authPluginData.slice(8, 20);
let authToken;
if (this.passwordSha1) {
authToken = auth41.calculateTokenFromPasswordSha(
this.passwordSha1,
authPluginData1,
authPluginData2
);
} else {
authToken = auth41.calculateToken(
this.password,
authPluginData1,
authPluginData2
);
}
return authToken;
}
handshakeInit(helloPacket, connection) {
this.on('error', (e) => {
connection._fatalError = e;
connection._protocolError = e;
});
this.handshake = Packets.Handshake.fromPacket(helloPacket);
if (connection.config.debug) {
// eslint-disable-next-line
console.log(
'Server hello packet: capability flags:%d=(%s)',
this.handshake.capabilityFlags,
flagNames(this.handshake.capabilityFlags).join(', ')
);
}
connection.serverCapabilityFlags = this.handshake.capabilityFlags;
connection.serverEncoding = CharsetToEncoding[this.handshake.characterSet];
connection.connectionId = this.handshake.connectionId;
const serverSSLSupport =
this.handshake.capabilityFlags & ClientConstants.SSL;
// multi factor authentication is enabled with the
// "MULTI_FACTOR_AUTHENTICATION" capability and should only be used if it
// is supported by the server
const multiFactorAuthentication =
this.handshake.capabilityFlags &
ClientConstants.MULTI_FACTOR_AUTHENTICATION;
this.clientFlags = this.clientFlags | multiFactorAuthentication;
// use compression only if requested by client and supported by server
connection.config.compress =
connection.config.compress &&
this.handshake.capabilityFlags & ClientConstants.COMPRESS;
this.clientFlags = this.clientFlags | connection.config.compress;
if (connection.config.ssl) {
// client requires SSL but server does not support it
if (!serverSSLSupport) {
const err = new Error('Server does not support secure connection');
err.code = 'HANDSHAKE_NO_SSL_SUPPORT';
err.fatal = true;
this.emit('error', err);
return false;
}
// send ssl upgrade request and immediately upgrade connection to secure
this.clientFlags |= ClientConstants.SSL;
this.sendSSLRequest(connection);
connection.startTLS((err) => {
// after connection is secure
if (err) {
// SSL negotiation error are fatal
err.code = 'HANDSHAKE_SSL_ERROR';
err.fatal = true;
this.emit('error', err);
return;
}
// rest of communication is encrypted
this.sendCredentials(connection);
});
} else {
this.sendCredentials(connection);
}
if (multiFactorAuthentication) {
// if the server supports multi-factor authentication, we enable it in
// the client
this.authenticationFactor = 1;
}
return ClientHandshake.prototype.handshakeResult;
}
handshakeResult(packet, connection) {
const marker = packet.peekByte();
// packet can be OK_Packet, ERR_Packet, AuthSwitchRequest, AuthNextFactor
// or AuthMoreData
if (marker === 0xfe || marker === 1 || marker === 0x02) {
const authSwitch = require('./auth_switch');
try {
if (marker === 1) {
authSwitch.authSwitchRequestMoreData(packet, connection, this);
} else {
// if authenticationFactor === 0, it means the server does not support
// the multi-factor authentication capability
if (this.authenticationFactor !== 0) {
// if we are past the first authentication factor, we should use the
// corresponding password (if there is one)
connection.config.password =
this[`password${this.authenticationFactor}`];
// update the current authentication factor
this.authenticationFactor += 1;
}
// if marker === 0x02, it means it is an AuthNextFactor packet,
// which is similar in structure to an AuthSwitchRequest packet,
// so, we can use it directly
authSwitch.authSwitchRequest(packet, connection, this);
}
return ClientHandshake.prototype.handshakeResult;
} catch (err) {
// Authentication errors are fatal
err.code = 'AUTH_SWITCH_PLUGIN_ERROR';
err.fatal = true;
if (this.onResult) {
this.onResult(err);
} else {
this.emit('error', err);
}
return null;
}
}
if (marker !== 0) {
const err = new Error('Unexpected packet during handshake phase');
// Unknown handshake errors are fatal
err.code = 'HANDSHAKE_UNKNOWN_ERROR';
err.fatal = true;
if (this.onResult) {
this.onResult(err);
} else {
this.emit('error', err);
}
return null;
}
// this should be called from ClientHandshake command only
// and skipped when called from ChangeUser command
if (!connection.authorized) {
connection.authorized = true;
if (connection.config.compress) {
const enableCompression =
require('../compressed_protocol.js').enableCompression;
enableCompression(connection);
}
}
if (this.onResult) {
this.onResult(null);
}
return null;
}
}
module.exports = ClientHandshake;

View File

@@ -1,18 +0,0 @@
'use strict';
const Command = require('./command');
const Packets = require('../packets/index.js');
class CloseStatement extends Command {
constructor(id) {
super();
this.id = id;
}
start(packet, connection) {
connection.writePacket(new Packets.CloseStatement(this.id).toPacket(1));
return null;
}
}
module.exports = CloseStatement;

View File

@@ -1,54 +0,0 @@
'use strict';
const EventEmitter = require('events').EventEmitter;
const Timers = require('timers');
class Command extends EventEmitter {
constructor() {
super();
this.next = null;
}
// slow. debug only
stateName() {
const state = this.next;
for (const i in this) {
if (this[i] === state && i !== 'next') {
return i;
}
}
return 'unknown name';
}
execute(packet, connection) {
if (!this.next) {
this.next = this.start;
connection._resetSequenceId();
}
if (packet && packet.isError()) {
const err = packet.asError(connection.clientEncoding);
err.sql = this.sql || this.query;
if (this.queryTimeout) {
Timers.clearTimeout(this.queryTimeout);
this.queryTimeout = null;
}
if (this.onResult) {
this.onResult(err);
this.emit('end');
} else {
this.emit('error', err);
this.emit('end');
}
return true;
}
// TODO: don't return anything from execute, it's ugly and error-prone. Listen for 'end' event in connection
this.next = this.next(packet, connection);
if (this.next) {
return false;
}
this.emit('end');
return true;
}
}
module.exports = Command;

View File

@@ -1,112 +0,0 @@
'use strict';
const Command = require('./command.js');
const Query = require('./query.js');
const Packets = require('../packets/index.js');
const getBinaryParser = require('../parsers/binary_parser.js');
const getStaticBinaryParser = require('../parsers/static_binary_parser.js');
class Execute extends Command {
constructor(options, callback) {
super();
this.statement = options.statement;
this.sql = options.sql;
this.values = options.values;
this.onResult = callback;
this.parameters = options.values;
this.insertId = 0;
this.timeout = options.timeout;
this.queryTimeout = null;
this._rows = [];
this._fields = [];
this._result = [];
this._fieldCount = 0;
this._rowParser = null;
this._executeOptions = options;
this._resultIndex = 0;
this._localStream = null;
this._unpipeStream = function () {};
this._streamFactory = options.infileStreamFactory;
this._connection = null;
}
buildParserFromFields(fields, connection) {
if (this.options.disableEval) {
return getStaticBinaryParser(fields, this.options, connection.config);
}
return getBinaryParser(fields, this.options, connection.config);
}
start(packet, connection) {
this._connection = connection;
this.options = Object.assign({}, connection.config, this._executeOptions);
this._setTimeout();
const executePacket = new Packets.Execute(
this.statement.id,
this.parameters,
connection.config.charsetNumber,
connection.config.timezone
);
//For reasons why this try-catch is here, please see
// https://github.com/sidorares/node-mysql2/pull/689
//For additional discussion, see
// 1. https://github.com/sidorares/node-mysql2/issues/493
// 2. https://github.com/sidorares/node-mysql2/issues/187
// 3. https://github.com/sidorares/node-mysql2/issues/480
try {
connection.writePacket(executePacket.toPacket(1));
} catch (error) {
this.onResult(error);
}
return Execute.prototype.resultsetHeader;
}
readField(packet, connection) {
let fields;
// disabling for now, but would be great to find reliable way to parse fields only once
// fields reported by prepare can be empty at all or just incorrect - see #169
//
// perfomance optimisation: if we already have this field parsed in statement header, use one from header
// const field = this.statement.columns.length == this._fieldCount ?
// this.statement.columns[this._receivedFieldsCount] : new Packets.ColumnDefinition(packet);
const field = new Packets.ColumnDefinition(
packet,
connection.clientEncoding
);
this._receivedFieldsCount++;
this._fields[this._resultIndex].push(field);
if (this._receivedFieldsCount === this._fieldCount) {
fields = this._fields[this._resultIndex];
this.emit('fields', fields, this._resultIndex);
return Execute.prototype.fieldsEOF;
}
return Execute.prototype.readField;
}
fieldsEOF(packet, connection) {
// check EOF
if (!packet.isEOF()) {
return connection.protocolError('Expected EOF packet');
}
this._rowParser = new (this.buildParserFromFields(
this._fields[this._resultIndex],
connection
))();
return Execute.prototype.row;
}
}
Execute.prototype.done = Query.prototype.done;
Execute.prototype.doneInsert = Query.prototype.doneInsert;
Execute.prototype.resultsetHeader = Query.prototype.resultsetHeader;
Execute.prototype._findOrCreateReadStream =
Query.prototype._findOrCreateReadStream;
Execute.prototype._streamLocalInfile = Query.prototype._streamLocalInfile;
Execute.prototype._setTimeout = Query.prototype._setTimeout;
Execute.prototype._handleTimeoutError = Query.prototype._handleTimeoutError;
Execute.prototype.row = Query.prototype.row;
Execute.prototype.stream = Query.prototype.stream;
module.exports = Execute;

View File

@@ -1,27 +0,0 @@
'use strict';
const ClientHandshake = require('./client_handshake.js');
const ServerHandshake = require('./server_handshake.js');
const Query = require('./query.js');
const Prepare = require('./prepare.js');
const CloseStatement = require('./close_statement.js');
const Execute = require('./execute.js');
const Ping = require('./ping.js');
const RegisterSlave = require('./register_slave.js');
const BinlogDump = require('./binlog_dump.js');
const ChangeUser = require('./change_user.js');
const Quit = require('./quit.js');
module.exports = {
ClientHandshake,
ServerHandshake,
Query,
Prepare,
CloseStatement,
Execute,
Ping,
RegisterSlave,
BinlogDump,
ChangeUser,
Quit,
};

View File

@@ -1,36 +0,0 @@
'use strict';
const Command = require('./command');
const CommandCode = require('../constants/commands');
const Packet = require('../packets/packet');
// TODO: time statistics?
// usefull for queue size and network latency monitoring
// store created,sent,reply timestamps
class Ping extends Command {
constructor(callback) {
super();
this.onResult = callback;
}
start(packet, connection) {
const ping = new Packet(
0,
Buffer.from([1, 0, 0, 0, CommandCode.PING]),
0,
5
);
connection.writePacket(ping);
return Ping.prototype.pingResponse;
}
pingResponse() {
// TODO: check it's OK packet. error check already done in caller
if (this.onResult) {
process.nextTick(this.onResult.bind(this));
}
return null;
}
}
module.exports = Ping;

View File

@@ -1,143 +0,0 @@
'use strict';
const Packets = require('../packets/index.js');
const Command = require('./command.js');
const CloseStatement = require('./close_statement.js');
const Execute = require('./execute.js');
class PreparedStatementInfo {
constructor(query, id, columns, parameters, connection) {
this.query = query;
this.id = id;
this.columns = columns;
this.parameters = parameters;
this.rowParser = null;
this._connection = connection;
}
close() {
return this._connection.addCommand(new CloseStatement(this.id));
}
execute(parameters, callback) {
if (typeof parameters === 'function') {
callback = parameters;
parameters = [];
}
return this._connection.addCommand(
new Execute({ statement: this, values: parameters }, callback)
);
}
}
class Prepare extends Command {
constructor(options, callback) {
super();
this.query = options.sql;
this.onResult = callback;
this.id = 0;
this.fieldCount = 0;
this.parameterCount = 0;
this.fields = [];
this.parameterDefinitions = [];
this.options = options;
}
start(packet, connection) {
const Connection = connection.constructor;
this.key = Connection.statementKey(this.options);
const statement = connection._statements.get(this.key);
if (statement) {
if (this.onResult) {
this.onResult(null, statement);
}
return null;
}
const cmdPacket = new Packets.PrepareStatement(
this.query,
connection.config.charsetNumber,
this.options.values
);
connection.writePacket(cmdPacket.toPacket(1));
return Prepare.prototype.prepareHeader;
}
prepareHeader(packet, connection) {
const header = new Packets.PreparedStatementHeader(packet);
this.id = header.id;
this.fieldCount = header.fieldCount;
this.parameterCount = header.parameterCount;
if (this.parameterCount > 0) {
return Prepare.prototype.readParameter;
}
if (this.fieldCount > 0) {
return Prepare.prototype.readField;
}
return this.prepareDone(connection);
}
readParameter(packet, connection) {
// there might be scenarios when mysql server reports more parameters than
// are actually present in the array of parameter definitions.
// if EOF packet is received we switch to "read fields" state if there are
// any fields reported by the server, otherwise we finish the command.
if (packet.isEOF()) {
if (this.fieldCount > 0) {
return Prepare.prototype.readField;
}
return this.prepareDone(connection);
}
const def = new Packets.ColumnDefinition(packet, connection.clientEncoding);
this.parameterDefinitions.push(def);
if (this.parameterDefinitions.length === this.parameterCount) {
return Prepare.prototype.parametersEOF;
}
return this.readParameter;
}
readField(packet, connection) {
if (packet.isEOF()) {
return this.prepareDone(connection);
}
const def = new Packets.ColumnDefinition(packet, connection.clientEncoding);
this.fields.push(def);
if (this.fields.length === this.fieldCount) {
return Prepare.prototype.fieldsEOF;
}
return Prepare.prototype.readField;
}
parametersEOF(packet, connection) {
if (!packet.isEOF()) {
return connection.protocolError('Expected EOF packet after parameters');
}
if (this.fieldCount > 0) {
return Prepare.prototype.readField;
}
return this.prepareDone(connection);
}
fieldsEOF(packet, connection) {
if (!packet.isEOF()) {
return connection.protocolError('Expected EOF packet after fields');
}
return this.prepareDone(connection);
}
prepareDone(connection) {
const statement = new PreparedStatementInfo(
this.query,
this.id,
this.fields,
this.parameterDefinitions,
connection
);
connection._statements.set(this.key, statement);
if (this.onResult) {
this.onResult(null, statement);
}
return null;
}
}
module.exports = Prepare;

View File

@@ -1,366 +0,0 @@
'use strict';
const process = require('process');
const Timers = require('timers');
const Readable = require('stream').Readable;
const Command = require('./command.js');
const Packets = require('../packets/index.js');
const getTextParser = require('../parsers/text_parser.js');
const staticParser = require('../parsers/static_text_parser.js');
const ServerStatus = require('../constants/server_status.js');
const EmptyPacket = new Packets.Packet(0, Buffer.allocUnsafe(4), 0, 4);
// http://dev.mysql.com/doc/internals/en/com-query.html
class Query extends Command {
constructor(options, callback) {
super();
this.sql = options.sql;
this.values = options.values;
this._queryOptions = options;
this.namedPlaceholders = options.namedPlaceholders || false;
this.onResult = callback;
this.timeout = options.timeout;
this.queryTimeout = null;
this._fieldCount = 0;
this._rowParser = null;
this._fields = [];
this._rows = [];
this._receivedFieldsCount = 0;
this._resultIndex = 0;
this._localStream = null;
this._unpipeStream = function () {};
this._streamFactory = options.infileStreamFactory;
this._connection = null;
}
then() {
const err =
"You have tried to call .then(), .catch(), or invoked await on the result of query that is not a promise, which is a programming error. Try calling con.promise().query(), or require('mysql2/promise') instead of 'mysql2' for a promise-compatible version of the query interface. To learn how to use async/await or Promises check out documentation at https://sidorares.github.io/node-mysql2/docs#using-promise-wrapper, or the mysql2 documentation at https://sidorares.github.io/node-mysql2/docs/documentation/promise-wrapper";
// eslint-disable-next-line
console.log(err);
throw new Error(err);
}
/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
start(_packet, connection) {
if (connection.config.debug) {
// eslint-disable-next-line
console.log(' Sending query command: %s', this.sql);
}
this._connection = connection;
this.options = Object.assign({}, connection.config, this._queryOptions);
this._setTimeout();
const cmdPacket = new Packets.Query(
this.sql,
connection.config.charsetNumber
);
connection.writePacket(cmdPacket.toPacket(1));
return Query.prototype.resultsetHeader;
}
done() {
this._unpipeStream();
// if all ready timeout, return null directly
if (this.timeout && !this.queryTimeout) {
return null;
}
// else clear timer
if (this.queryTimeout) {
Timers.clearTimeout(this.queryTimeout);
this.queryTimeout = null;
}
if (this.onResult) {
let rows, fields;
if (this._resultIndex === 0) {
rows = this._rows[0];
fields = this._fields[0];
} else {
rows = this._rows;
fields = this._fields;
}
if (fields) {
process.nextTick(() => {
this.onResult(null, rows, fields);
});
} else {
process.nextTick(() => {
this.onResult(null, rows);
});
}
}
return null;
}
doneInsert(rs) {
if (this._localStreamError) {
if (this.onResult) {
this.onResult(this._localStreamError, rs);
} else {
this.emit('error', this._localStreamError);
}
return null;
}
this._rows.push(rs);
this._fields.push(void 0);
this.emit('fields', void 0);
this.emit('result', rs);
if (rs.serverStatus & ServerStatus.SERVER_MORE_RESULTS_EXISTS) {
this._resultIndex++;
return this.resultsetHeader;
}
return this.done();
}
resultsetHeader(packet, connection) {
const rs = new Packets.ResultSetHeader(packet, connection);
this._fieldCount = rs.fieldCount;
if (connection.config.debug) {
// eslint-disable-next-line
console.log(
` Resultset header received, expecting ${rs.fieldCount} column definition packets`
);
}
if (this._fieldCount === 0) {
return this.doneInsert(rs);
}
if (this._fieldCount === null) {
return this._streamLocalInfile(connection, rs.infileName);
}
this._receivedFieldsCount = 0;
this._rows.push([]);
this._fields.push([]);
return this.readField;
}
_streamLocalInfile(connection, path) {
if (this._streamFactory) {
this._localStream = this._streamFactory(path);
} else {
this._localStreamError = new Error(
`As a result of LOCAL INFILE command server wants to read ${path} file, but as of v2.0 you must provide streamFactory option returning ReadStream.`
);
connection.writePacket(EmptyPacket);
return this.infileOk;
}
const onConnectionError = () => {
this._unpipeStream();
};
const onDrain = () => {
this._localStream.resume();
};
const onPause = () => {
this._localStream.pause();
};
const onData = function (data) {
const dataWithHeader = Buffer.allocUnsafe(data.length + 4);
data.copy(dataWithHeader, 4);
connection.writePacket(
new Packets.Packet(0, dataWithHeader, 0, dataWithHeader.length)
);
};
const onEnd = () => {
connection.removeListener('error', onConnectionError);
connection.writePacket(EmptyPacket);
};
const onError = (err) => {
this._localStreamError = err;
connection.removeListener('error', onConnectionError);
connection.writePacket(EmptyPacket);
};
this._unpipeStream = () => {
connection.stream.removeListener('pause', onPause);
connection.stream.removeListener('drain', onDrain);
this._localStream.removeListener('data', onData);
this._localStream.removeListener('end', onEnd);
this._localStream.removeListener('error', onError);
};
connection.stream.on('pause', onPause);
connection.stream.on('drain', onDrain);
this._localStream.on('data', onData);
this._localStream.on('end', onEnd);
this._localStream.on('error', onError);
connection.once('error', onConnectionError);
return this.infileOk;
}
readField(packet, connection) {
this._receivedFieldsCount++;
// Often there is much more data in the column definition than in the row itself
// If you set manually _fields[0] to array of ColumnDefinition's (from previous call)
// you can 'cache' result of parsing. Field packets still received, but ignored in that case
// this is the reason _receivedFieldsCount exist (otherwise we could just use current length of fields array)
if (this._fields[this._resultIndex].length !== this._fieldCount) {
const field = new Packets.ColumnDefinition(
packet,
connection.clientEncoding
);
this._fields[this._resultIndex].push(field);
if (connection.config.debug) {
/* eslint-disable no-console */
console.log(' Column definition:');
console.log(` name: ${field.name}`);
console.log(` type: ${field.columnType}`);
console.log(` flags: ${field.flags}`);
/* eslint-enable no-console */
}
}
// last field received
if (this._receivedFieldsCount === this._fieldCount) {
const fields = this._fields[this._resultIndex];
this.emit('fields', fields);
if (this.options.disableEval) {
this._rowParser = staticParser(fields, this.options, connection.config);
} else {
this._rowParser = new (getTextParser(
fields,
this.options,
connection.config
))(fields);
}
return Query.prototype.fieldsEOF;
}
return Query.prototype.readField;
}
fieldsEOF(packet, connection) {
// check EOF
if (!packet.isEOF()) {
return connection.protocolError('Expected EOF packet');
}
return this.row;
}
/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
row(packet, _connection) {
if (packet.isEOF()) {
const status = packet.eofStatusFlags();
const moreResults = status & ServerStatus.SERVER_MORE_RESULTS_EXISTS;
if (moreResults) {
this._resultIndex++;
return Query.prototype.resultsetHeader;
}
return this.done();
}
let row;
try {
row = this._rowParser.next(
packet,
this._fields[this._resultIndex],
this.options
);
} catch (err) {
this._localStreamError = err;
return this.doneInsert(null);
}
if (this.onResult) {
this._rows[this._resultIndex].push(row);
} else {
this.emit('result', row, this._resultIndex);
}
return Query.prototype.row;
}
infileOk(packet, connection) {
const rs = new Packets.ResultSetHeader(packet, connection);
return this.doneInsert(rs);
}
stream(options) {
options = options || Object.create(null);
options.objectMode = true;
const stream = new Readable({
...options,
emitClose: true,
autoDestroy: true,
read: () => {
this._connection && this._connection.resume();
},
});
// Prevent a breaking change for users that rely on `end` event
stream.once('close', () => {
if (!stream.readableEnded) {
stream.emit('end');
}
});
const onResult = (row, index) => {
if (stream.destroyed) return;
if (!stream.push(row)) {
this._connection && this._connection.pause();
}
stream.emit('result', row, index); // replicate old emitter
};
const onFields = (fields) => {
if (stream.destroyed) return;
stream.emit('fields', fields); // replicate old emitter
};
const onEnd = () => {
if (stream.destroyed) return;
stream.push(null); // pushing null, indicating EOF
};
const onError = (err) => {
stream.destroy(err);
};
stream._destroy = (err, cb) => {
this._connection && this._connection.resume();
this.removeListener('result', onResult);
this.removeListener('fields', onFields);
this.removeListener('end', onEnd);
this.removeListener('error', onError);
cb(err); // Pass on any errors
};
this.on('result', onResult);
this.on('fields', onFields);
this.on('end', onEnd);
this.on('error', onError);
return stream;
}
_setTimeout() {
if (this.timeout) {
const timeoutHandler = this._handleTimeoutError.bind(this);
this.queryTimeout = Timers.setTimeout(timeoutHandler, this.timeout);
}
}
_handleTimeoutError() {
if (this.queryTimeout) {
Timers.clearTimeout(this.queryTimeout);
this.queryTimeout = null;
}
const err = new Error('Query inactivity timeout');
err.errorno = 'PROTOCOL_SEQUENCE_TIMEOUT';
err.code = 'PROTOCOL_SEQUENCE_TIMEOUT';
err.syscall = 'query';
if (this.onResult) {
this.onResult(err);
} else {
this.emit('error', err);
}
}
}
Query.prototype.catch = Query.prototype.then;
module.exports = Query;

View File

@@ -1,29 +0,0 @@
'use strict';
const Command = require('./command.js');
const CommandCode = require('../constants/commands.js');
const Packet = require('../packets/packet.js');
class Quit extends Command {
constructor(callback) {
super();
this.onResult = callback;
}
start(packet, connection) {
connection._closing = true;
const quit = new Packet(
0,
Buffer.from([1, 0, 0, 0, CommandCode.QUIT]),
0,
5
);
if (this.onResult) {
this.onResult();
}
connection.writePacket(quit);
return null;
}
}
module.exports = Quit;

View File

@@ -1,27 +0,0 @@
'use strict';
const Command = require('./command');
const Packets = require('../packets');
class RegisterSlave extends Command {
constructor(opts, callback) {
super();
this.onResult = callback;
this.opts = opts;
}
start(packet, connection) {
const newPacket = new Packets.RegisterSlave(this.opts);
connection.writePacket(newPacket.toPacket(1));
return RegisterSlave.prototype.registerResponse;
}
registerResponse() {
if (this.onResult) {
process.nextTick(this.onResult.bind(this));
}
return null;
}
}
module.exports = RegisterSlave;

View File

@@ -1,203 +0,0 @@
'use strict';
const CommandCode = require('../constants/commands.js');
const Errors = require('../constants/errors.js');
const Command = require('./command.js');
const Packets = require('../packets/index.js');
class ServerHandshake extends Command {
constructor(args) {
super();
this.args = args;
/*
this.protocolVersion = args.protocolVersion || 10;
this.serverVersion = args.serverVersion;
this.connectionId = args.connectionId,
this.statusFlags = args.statusFlags,
this.characterSet = args.characterSet,
this.capabilityFlags = args.capabilityFlags || 512;
*/
}
start(packet, connection) {
const serverHelloPacket = new Packets.Handshake(this.args);
this.serverHello = serverHelloPacket;
serverHelloPacket.setScrambleData((err) => {
if (err) {
connection.emit('error', new Error('Error generating random bytes'));
return;
}
connection.writePacket(serverHelloPacket.toPacket(0));
});
return ServerHandshake.prototype.readClientReply;
}
readClientReply(packet, connection) {
// check auth here
const clientHelloReply = Packets.HandshakeResponse.fromPacket(packet);
// TODO check we don't have something similar already
connection.clientHelloReply = clientHelloReply;
if (this.args.authCallback) {
this.args.authCallback(
{
user: clientHelloReply.user,
database: clientHelloReply.database,
address: connection.stream.remoteAddress,
authPluginData1: this.serverHello.authPluginData1,
authPluginData2: this.serverHello.authPluginData2,
authToken: clientHelloReply.authToken,
},
(err, mysqlError) => {
// if (err)
if (!mysqlError) {
connection.writeOk();
} else {
// TODO create constants / errorToCode
// 1045 = ER_ACCESS_DENIED_ERROR
connection.writeError({
message: mysqlError.message || '',
code: mysqlError.code || 1045,
});
connection.close();
}
}
);
} else {
connection.writeOk();
}
return ServerHandshake.prototype.dispatchCommands;
}
_isStatement(query, name) {
const firstWord = query.split(' ')[0].toUpperCase();
return firstWord === name;
}
dispatchCommands(packet, connection) {
// command from client to server
let knownCommand = true;
const encoding = connection.clientHelloReply.encoding;
const commandCode = packet.readInt8();
switch (commandCode) {
case CommandCode.STMT_PREPARE:
if (connection.listeners('stmt_prepare').length) {
const query = packet.readString(undefined, encoding);
connection.emit('stmt_prepare', query);
} else {
connection.writeError({
code: Errors.HA_ERR_INTERNAL_ERROR,
message: 'No query handler for prepared statements.',
});
}
break;
case CommandCode.STMT_EXECUTE:
if (connection.listeners('stmt_execute').length) {
const { stmtId, flags, iterationCount, values } =
Packets.Execute.fromPacket(packet, encoding);
connection.emit(
'stmt_execute',
stmtId,
flags,
iterationCount,
values
);
} else {
connection.writeError({
code: Errors.HA_ERR_INTERNAL_ERROR,
message: 'No query handler for execute statements.',
});
}
break;
case CommandCode.QUIT:
if (connection.listeners('quit').length) {
connection.emit('quit');
} else {
connection.stream.end();
}
break;
case CommandCode.INIT_DB:
if (connection.listeners('init_db').length) {
const schemaName = packet.readString(undefined, encoding);
connection.emit('init_db', schemaName);
} else {
connection.writeOk();
}
break;
case CommandCode.QUERY:
if (connection.listeners('query').length) {
const query = packet.readString(undefined, encoding);
if (
this._isStatement(query, 'PREPARE') ||
this._isStatement(query, 'SET')
) {
connection.emit('stmt_prepare', query);
} else if (this._isStatement(query, 'EXECUTE')) {
connection.emit('stmt_execute', null, null, null, null, query);
} else connection.emit('query', query);
} else {
connection.writeError({
code: Errors.HA_ERR_INTERNAL_ERROR,
message: 'No query handler',
});
}
break;
case CommandCode.FIELD_LIST:
if (connection.listeners('field_list').length) {
const table = packet.readNullTerminatedString(encoding);
const fields = packet.readString(undefined, encoding);
connection.emit('field_list', table, fields);
} else {
connection.writeError({
code: Errors.ER_WARN_DEPRECATED_SYNTAX,
message:
'As of MySQL 5.7.11, COM_FIELD_LIST is deprecated and will be removed in a future version of MySQL.',
});
}
break;
case CommandCode.PING:
if (connection.listeners('ping').length) {
connection.emit('ping');
} else {
connection.writeOk();
}
break;
default:
knownCommand = false;
}
if (connection.listeners('packet').length) {
connection.emit('packet', packet.clone(), knownCommand, commandCode);
} else if (!knownCommand) {
// eslint-disable-next-line no-console
console.log('Unknown command:', commandCode);
}
return ServerHandshake.prototype.dispatchCommands;
}
}
module.exports = ServerHandshake;
// TODO: implement server-side 4.1 authentication
/*
4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
SERVER: public_seed=create_random_string()
send(public_seed)
CLIENT: recv(public_seed)
hash_stage1=sha1("password")
hash_stage2=sha1(hash_stage1)
reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
// this three steps are done in scramble()
send(reply)
SERVER: recv(reply)
hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
candidate_hash2=sha1(hash_stage1)
check(candidate_hash2==hash_stage2)
server stores sha1(sha1(password)) ( hash_stag2)
*/

View File

@@ -1,127 +0,0 @@
'use strict';
// connection mixins
// implementation of http://dev.mysql.com/doc/internals/en/compression.html
const zlib = require('zlib');
const PacketParser = require('./packet_parser.js');
function handleCompressedPacket(packet) {
// eslint-disable-next-line consistent-this, no-invalid-this
const connection = this;
const deflatedLength = packet.readInt24();
const body = packet.readBuffer();
if (deflatedLength !== 0) {
connection.inflateQueue.push((task) => {
zlib.inflate(body, (err, data) => {
if (err) {
connection._handleNetworkError(err);
return;
}
connection._bumpCompressedSequenceId(packet.numPackets);
connection._inflatedPacketsParser.execute(data);
task.done();
});
});
} else {
connection.inflateQueue.push((task) => {
connection._bumpCompressedSequenceId(packet.numPackets);
connection._inflatedPacketsParser.execute(body);
task.done();
});
}
}
function writeCompressed(buffer) {
// http://dev.mysql.com/doc/internals/en/example-several-mysql-packets.html
// note: sending a MySQL Packet of the size 2^245 to 2^241 via compression
// leads to at least one extra compressed packet.
// (this is because "length of the packet before compression" need to fit
// into 3 byte unsigned int. "length of the packet before compression" includes
// 4 byte packet header, hence 2^245)
const MAX_COMPRESSED_LENGTH = 16777210;
let start;
if (buffer.length > MAX_COMPRESSED_LENGTH) {
for (start = 0; start < buffer.length; start += MAX_COMPRESSED_LENGTH) {
writeCompressed.call(
// eslint-disable-next-line no-invalid-this
this,
buffer.slice(start, start + MAX_COMPRESSED_LENGTH)
);
}
return;
}
// eslint-disable-next-line no-invalid-this, consistent-this
const connection = this;
let packetLen = buffer.length;
const compressHeader = Buffer.allocUnsafe(7);
// seqqueue is used here because zlib async execution is routed via thread pool
// internally and when we have multiple compressed packets arriving we need
// to assemble uncompressed result sequentially
(function (seqId) {
connection.deflateQueue.push((task) => {
zlib.deflate(buffer, (err, compressed) => {
if (err) {
connection._handleFatalError(err);
return;
}
let compressedLength = compressed.length;
if (compressedLength < packetLen) {
compressHeader.writeUInt8(compressedLength & 0xff, 0);
compressHeader.writeUInt16LE(compressedLength >> 8, 1);
compressHeader.writeUInt8(seqId, 3);
compressHeader.writeUInt8(packetLen & 0xff, 4);
compressHeader.writeUInt16LE(packetLen >> 8, 5);
connection.writeUncompressed(compressHeader);
connection.writeUncompressed(compressed);
} else {
// http://dev.mysql.com/doc/internals/en/uncompressed-payload.html
// To send an uncompressed payload:
// - set length of payload before compression to 0
// - the compressed payload contains the uncompressed payload instead.
compressedLength = packetLen;
packetLen = 0;
compressHeader.writeUInt8(compressedLength & 0xff, 0);
compressHeader.writeUInt16LE(compressedLength >> 8, 1);
compressHeader.writeUInt8(seqId, 3);
compressHeader.writeUInt8(packetLen & 0xff, 4);
compressHeader.writeUInt16LE(packetLen >> 8, 5);
connection.writeUncompressed(compressHeader);
connection.writeUncompressed(buffer);
}
task.done();
});
});
})(connection.compressedSequenceId);
connection._bumpCompressedSequenceId(1);
}
function enableCompression(connection) {
connection._lastWrittenPacketId = 0;
connection._lastReceivedPacketId = 0;
connection._handleCompressedPacket = handleCompressedPacket;
connection._inflatedPacketsParser = new PacketParser((p) => {
connection.handlePacket(p);
}, 4);
connection._inflatedPacketsParser._lastPacket = 0;
connection.packetParser = new PacketParser((packet) => {
connection._handleCompressedPacket(packet);
}, 7);
connection.writeUncompressed = connection.write;
connection.write = writeCompressed;
const seqqueue = require('seq-queue');
connection.inflateQueue = seqqueue.createQueue();
connection.deflateQueue = seqqueue.createQueue();
}
module.exports = {
enableCompression: enableCompression,
};

View File

@@ -1,12 +0,0 @@
'use strict';
const BaseConnection = require('./base/connection.js');
class Connection extends BaseConnection {
promise(promiseImpl) {
const PromiseConnection = require('./promise/connection.js');
return new PromiseConnection(this, promiseImpl);
}
}
module.exports = Connection;

View File

@@ -1,294 +0,0 @@
// This file was modified by Oracle on September 21, 2021.
// New connection options for additional authentication factors were
// introduced.
// Multi-factor authentication capability is now enabled if one of these
// options is used.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
'use strict';
const { URL } = require('url');
const ClientConstants = require('./constants/client');
const Charsets = require('./constants/charsets');
const { version } = require('../package.json');
let SSLProfiles = null;
const validOptions = {
authPlugins: 1,
authSwitchHandler: 1,
bigNumberStrings: 1,
charset: 1,
charsetNumber: 1,
compress: 1,
connectAttributes: 1,
connectTimeout: 1,
database: 1,
dateStrings: 1,
debug: 1,
decimalNumbers: 1,
enableKeepAlive: 1,
flags: 1,
host: 1,
insecureAuth: 1,
infileStreamFactory: 1,
isServer: 1,
keepAliveInitialDelay: 1,
localAddress: 1,
maxPreparedStatements: 1,
multipleStatements: 1,
namedPlaceholders: 1,
nestTables: 1,
password: 1,
// with multi-factor authentication, the main password (used for the first
// authentication factor) can be provided via password1
password1: 1,
password2: 1,
password3: 1,
passwordSha1: 1,
pool: 1,
port: 1,
queryFormat: 1,
rowsAsArray: 1,
socketPath: 1,
ssl: 1,
stream: 1,
stringifyObjects: 1,
supportBigNumbers: 1,
timezone: 1,
trace: 1,
typeCast: 1,
uri: 1,
user: 1,
disableEval: 1,
// These options are used for Pool
connectionLimit: 1,
maxIdle: 1,
idleTimeout: 1,
Promise: 1,
queueLimit: 1,
waitForConnections: 1,
jsonStrings: 1,
gracefulEnd: 1,
};
class ConnectionConfig {
constructor(options) {
if (typeof options === 'string') {
options = ConnectionConfig.parseUrl(options);
} else if (options && options.uri) {
const uriOptions = ConnectionConfig.parseUrl(options.uri);
for (const key in uriOptions) {
if (!Object.prototype.hasOwnProperty.call(uriOptions, key)) continue;
if (options[key]) continue;
options[key] = uriOptions[key];
}
}
for (const key in options) {
if (!Object.prototype.hasOwnProperty.call(options, key)) continue;
if (validOptions[key] !== 1) {
// REVIEW: Should this be emitted somehow?
// eslint-disable-next-line no-console
console.error(
`Ignoring invalid configuration option passed to Connection: ${key}. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration option to a Connection`
);
}
}
this.isServer = options.isServer;
this.stream = options.stream;
this.host = options.host || 'localhost';
this.port =
(typeof options.port === 'string'
? parseInt(options.port, 10)
: options.port) || 3306;
this.localAddress = options.localAddress;
this.socketPath = options.socketPath;
this.user = options.user || undefined;
// for the purpose of multi-factor authentication, or not, the main
// password (used for the 1st authentication factor) can also be
// provided via the "password1" option
this.password = options.password || options.password1 || undefined;
this.password2 = options.password2 || undefined;
this.password3 = options.password3 || undefined;
this.passwordSha1 = options.passwordSha1 || undefined;
this.database = options.database;
this.connectTimeout = isNaN(options.connectTimeout)
? 10 * 1000
: options.connectTimeout;
this.insecureAuth = options.insecureAuth || false;
this.infileStreamFactory = options.infileStreamFactory || undefined;
this.supportBigNumbers = options.supportBigNumbers || false;
this.bigNumberStrings = options.bigNumberStrings || false;
this.decimalNumbers = options.decimalNumbers || false;
this.dateStrings = options.dateStrings || false;
this.debug = options.debug;
this.trace = options.trace !== false;
this.stringifyObjects = options.stringifyObjects || false;
this.enableKeepAlive = options.enableKeepAlive !== false;
this.keepAliveInitialDelay = options.keepAliveInitialDelay;
if (
options.timezone &&
!/^(?:local|Z|[ +-]\d\d:\d\d)$/.test(options.timezone)
) {
// strictly supports timezones specified by mysqljs/mysql:
// https://github.com/mysqljs/mysql#user-content-connection-options
// eslint-disable-next-line no-console
console.error(
`Ignoring invalid timezone passed to Connection: ${options.timezone}. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration option to a Connection`
);
// SqlStrings falls back to UTC on invalid timezone
this.timezone = 'Z';
} else {
this.timezone = options.timezone || 'local';
}
this.queryFormat = options.queryFormat;
this.pool = options.pool || undefined;
this.ssl =
typeof options.ssl === 'string'
? ConnectionConfig.getSSLProfile(options.ssl)
: options.ssl || false;
this.multipleStatements = options.multipleStatements || false;
this.rowsAsArray = options.rowsAsArray || false;
this.namedPlaceholders = options.namedPlaceholders || false;
this.nestTables =
options.nestTables === undefined ? undefined : options.nestTables;
this.typeCast = options.typeCast === undefined ? true : options.typeCast;
this.disableEval = Boolean(options.disableEval);
if (this.timezone[0] === ' ') {
// "+" is a url encoded char for space so it
// gets translated to space when giving a
// connection string..
this.timezone = `+${this.timezone.slice(1)}`;
}
if (this.ssl) {
if (typeof this.ssl !== 'object') {
throw new TypeError(
`SSL profile must be an object, instead it's a ${typeof this.ssl}`
);
}
// Default rejectUnauthorized to true
this.ssl.rejectUnauthorized = this.ssl.rejectUnauthorized !== false;
}
this.maxPacketSize = 0;
this.charsetNumber = options.charset
? ConnectionConfig.getCharsetNumber(options.charset)
: options.charsetNumber || Charsets.UTF8MB4_UNICODE_CI;
this.compress = options.compress || false;
this.authPlugins = options.authPlugins;
this.authSwitchHandler = options.authSwitchHandler;
this.clientFlags = ConnectionConfig.mergeFlags(
ConnectionConfig.getDefaultFlags(options),
options.flags || ''
);
// Default connection attributes
// https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html
const defaultConnectAttributes = {
_client_name: 'Node-MySQL-2',
_client_version: version,
};
this.connectAttributes = {
...defaultConnectAttributes,
...(options.connectAttributes || {}),
};
this.maxPreparedStatements = options.maxPreparedStatements || 16000;
this.jsonStrings = options.jsonStrings || false;
this.gracefulEnd = options.gracefulEnd || false;
}
static mergeFlags(default_flags, user_flags) {
let flags = 0x0,
i;
if (!Array.isArray(user_flags)) {
user_flags = String(user_flags || '')
.toUpperCase()
.split(/\s*,+\s*/);
}
// add default flags unless "blacklisted"
for (i in default_flags) {
if (user_flags.indexOf(`-${default_flags[i]}`) >= 0) {
continue;
}
flags |= ClientConstants[default_flags[i]] || 0x0;
}
// add user flags unless already already added
for (i in user_flags) {
if (user_flags[i][0] === '-') {
continue;
}
if (default_flags.indexOf(user_flags[i]) >= 0) {
continue;
}
flags |= ClientConstants[user_flags[i]] || 0x0;
}
return flags;
}
static getDefaultFlags(options) {
const defaultFlags = [
'LONG_PASSWORD',
'FOUND_ROWS',
'LONG_FLAG',
'CONNECT_WITH_DB',
'ODBC',
'LOCAL_FILES',
'IGNORE_SPACE',
'PROTOCOL_41',
'IGNORE_SIGPIPE',
'TRANSACTIONS',
'RESERVED',
'SECURE_CONNECTION',
'MULTI_RESULTS',
'TRANSACTIONS',
'SESSION_TRACK',
'CONNECT_ATTRS',
];
if (options && options.multipleStatements) {
defaultFlags.push('MULTI_STATEMENTS');
}
defaultFlags.push('PLUGIN_AUTH');
defaultFlags.push('PLUGIN_AUTH_LENENC_CLIENT_DATA');
return defaultFlags;
}
static getCharsetNumber(charset) {
const num = Charsets[charset.toUpperCase()];
if (num === undefined) {
throw new TypeError(`Unknown charset '${charset}'`);
}
return num;
}
static getSSLProfile(name) {
if (!SSLProfiles) {
SSLProfiles = require('./constants/ssl_profiles.js');
}
const ssl = SSLProfiles[name];
if (ssl === undefined) {
throw new TypeError(`Unknown SSL profile '${name}'`);
}
return ssl;
}
static parseUrl(url) {
const parsedUrl = new URL(url);
const options = {
host: decodeURIComponent(parsedUrl.hostname),
port: parseInt(parsedUrl.port, 10),
database: decodeURIComponent(parsedUrl.pathname.slice(1)),
user: decodeURIComponent(parsedUrl.username),
password: decodeURIComponent(parsedUrl.password),
};
parsedUrl.searchParams.forEach((value, key) => {
try {
// Try to parse this as a JSON expression first
options[key] = JSON.parse(value);
} catch (err) {
// Otherwise assume it is a plain string
options[key] = value;
}
});
return options;
}
}
module.exports = ConnectionConfig;

View File

@@ -1,316 +0,0 @@
'use strict';
// see tools/generate-charset-mapping.js
// basicalliy result of "SHOW COLLATION" query
module.exports = [
'utf8',
'big5',
'latin2',
'dec8',
'cp850',
'latin1',
'hp8',
'koi8r',
'latin1',
'latin2',
'swe7',
'ascii',
'eucjp',
'sjis',
'cp1251',
'latin1',
'hebrew',
'utf8',
'tis620',
'euckr',
'latin7',
'latin2',
'koi8u',
'cp1251',
'gb2312',
'greek',
'cp1250',
'latin2',
'gbk',
'cp1257',
'latin5',
'latin1',
'armscii8',
'cesu8',
'cp1250',
'ucs2',
'cp866',
'keybcs2',
'macintosh',
'macroman',
'cp852',
'latin7',
'latin7',
'macintosh',
'cp1250',
'utf8',
'utf8',
'latin1',
'latin1',
'latin1',
'cp1251',
'cp1251',
'cp1251',
'macroman',
'utf16',
'utf16',
'utf16-le',
'cp1256',
'cp1257',
'cp1257',
'utf32',
'utf32',
'utf16-le',
'binary',
'armscii8',
'ascii',
'cp1250',
'cp1256',
'cp866',
'dec8',
'greek',
'hebrew',
'hp8',
'keybcs2',
'koi8r',
'koi8u',
'cesu8',
'latin2',
'latin5',
'latin7',
'cp850',
'cp852',
'swe7',
'cesu8',
'big5',
'euckr',
'gb2312',
'gbk',
'sjis',
'tis620',
'ucs2',
'eucjp',
'geostd8',
'geostd8',
'latin1',
'cp932',
'cp932',
'eucjpms',
'eucjpms',
'cp1250',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf16',
'utf8',
'utf8',
'utf8',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'ucs2',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'ucs2',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf32',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'cesu8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'cesu8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'gb18030',
'gb18030',
'gb18030',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
'utf8',
];

View File

@@ -1,317 +0,0 @@
'use strict';
exports.BIG5_CHINESE_CI = 1;
exports.LATIN2_CZECH_CS = 2;
exports.DEC8_SWEDISH_CI = 3;
exports.CP850_GENERAL_CI = 4;
exports.LATIN1_GERMAN1_CI = 5;
exports.HP8_ENGLISH_CI = 6;
exports.KOI8R_GENERAL_CI = 7;
exports.LATIN1_SWEDISH_CI = 8;
exports.LATIN2_GENERAL_CI = 9;
exports.SWE7_SWEDISH_CI = 10;
exports.ASCII_GENERAL_CI = 11;
exports.UJIS_JAPANESE_CI = 12;
exports.SJIS_JAPANESE_CI = 13;
exports.CP1251_BULGARIAN_CI = 14;
exports.LATIN1_DANISH_CI = 15;
exports.HEBREW_GENERAL_CI = 16;
exports.TIS620_THAI_CI = 18;
exports.EUCKR_KOREAN_CI = 19;
exports.LATIN7_ESTONIAN_CS = 20;
exports.LATIN2_HUNGARIAN_CI = 21;
exports.KOI8U_GENERAL_CI = 22;
exports.CP1251_UKRAINIAN_CI = 23;
exports.GB2312_CHINESE_CI = 24;
exports.GREEK_GENERAL_CI = 25;
exports.CP1250_GENERAL_CI = 26;
exports.LATIN2_CROATIAN_CI = 27;
exports.GBK_CHINESE_CI = 28;
exports.CP1257_LITHUANIAN_CI = 29;
exports.LATIN5_TURKISH_CI = 30;
exports.LATIN1_GERMAN2_CI = 31;
exports.ARMSCII8_GENERAL_CI = 32;
exports.UTF8_GENERAL_CI = 33;
exports.CP1250_CZECH_CS = 34;
exports.UCS2_GENERAL_CI = 35;
exports.CP866_GENERAL_CI = 36;
exports.KEYBCS2_GENERAL_CI = 37;
exports.MACCE_GENERAL_CI = 38;
exports.MACROMAN_GENERAL_CI = 39;
exports.CP852_GENERAL_CI = 40;
exports.LATIN7_GENERAL_CI = 41;
exports.LATIN7_GENERAL_CS = 42;
exports.MACCE_BIN = 43;
exports.CP1250_CROATIAN_CI = 44;
exports.UTF8MB4_GENERAL_CI = 45;
exports.UTF8MB4_BIN = 46;
exports.LATIN1_BIN = 47;
exports.LATIN1_GENERAL_CI = 48;
exports.LATIN1_GENERAL_CS = 49;
exports.CP1251_BIN = 50;
exports.CP1251_GENERAL_CI = 51;
exports.CP1251_GENERAL_CS = 52;
exports.MACROMAN_BIN = 53;
exports.UTF16_GENERAL_CI = 54;
exports.UTF16_BIN = 55;
exports.UTF16LE_GENERAL_CI = 56;
exports.CP1256_GENERAL_CI = 57;
exports.CP1257_BIN = 58;
exports.CP1257_GENERAL_CI = 59;
exports.UTF32_GENERAL_CI = 60;
exports.UTF32_BIN = 61;
exports.UTF16LE_BIN = 62;
exports.BINARY = 63;
exports.ARMSCII8_BIN = 64;
exports.ASCII_BIN = 65;
exports.CP1250_BIN = 66;
exports.CP1256_BIN = 67;
exports.CP866_BIN = 68;
exports.DEC8_BIN = 69;
exports.GREEK_BIN = 70;
exports.HEBREW_BIN = 71;
exports.HP8_BIN = 72;
exports.KEYBCS2_BIN = 73;
exports.KOI8R_BIN = 74;
exports.KOI8U_BIN = 75;
exports.UTF8_TOLOWER_CI = 76;
exports.LATIN2_BIN = 77;
exports.LATIN5_BIN = 78;
exports.LATIN7_BIN = 79;
exports.CP850_BIN = 80;
exports.CP852_BIN = 81;
exports.SWE7_BIN = 82;
exports.UTF8_BIN = 83;
exports.BIG5_BIN = 84;
exports.EUCKR_BIN = 85;
exports.GB2312_BIN = 86;
exports.GBK_BIN = 87;
exports.SJIS_BIN = 88;
exports.TIS620_BIN = 89;
exports.UCS2_BIN = 90;
exports.UJIS_BIN = 91;
exports.GEOSTD8_GENERAL_CI = 92;
exports.GEOSTD8_BIN = 93;
exports.LATIN1_SPANISH_CI = 94;
exports.CP932_JAPANESE_CI = 95;
exports.CP932_BIN = 96;
exports.EUCJPMS_JAPANESE_CI = 97;
exports.EUCJPMS_BIN = 98;
exports.CP1250_POLISH_CI = 99;
exports.UTF16_UNICODE_CI = 101;
exports.UTF16_ICELANDIC_CI = 102;
exports.UTF16_LATVIAN_CI = 103;
exports.UTF16_ROMANIAN_CI = 104;
exports.UTF16_SLOVENIAN_CI = 105;
exports.UTF16_POLISH_CI = 106;
exports.UTF16_ESTONIAN_CI = 107;
exports.UTF16_SPANISH_CI = 108;
exports.UTF16_SWEDISH_CI = 109;
exports.UTF16_TURKISH_CI = 110;
exports.UTF16_CZECH_CI = 111;
exports.UTF16_DANISH_CI = 112;
exports.UTF16_LITHUANIAN_CI = 113;
exports.UTF16_SLOVAK_CI = 114;
exports.UTF16_SPANISH2_CI = 115;
exports.UTF16_ROMAN_CI = 116;
exports.UTF16_PERSIAN_CI = 117;
exports.UTF16_ESPERANTO_CI = 118;
exports.UTF16_HUNGARIAN_CI = 119;
exports.UTF16_SINHALA_CI = 120;
exports.UTF16_GERMAN2_CI = 121;
exports.UTF16_CROATIAN_CI = 122;
exports.UTF16_UNICODE_520_CI = 123;
exports.UTF16_VIETNAMESE_CI = 124;
exports.UCS2_UNICODE_CI = 128;
exports.UCS2_ICELANDIC_CI = 129;
exports.UCS2_LATVIAN_CI = 130;
exports.UCS2_ROMANIAN_CI = 131;
exports.UCS2_SLOVENIAN_CI = 132;
exports.UCS2_POLISH_CI = 133;
exports.UCS2_ESTONIAN_CI = 134;
exports.UCS2_SPANISH_CI = 135;
exports.UCS2_SWEDISH_CI = 136;
exports.UCS2_TURKISH_CI = 137;
exports.UCS2_CZECH_CI = 138;
exports.UCS2_DANISH_CI = 139;
exports.UCS2_LITHUANIAN_CI = 140;
exports.UCS2_SLOVAK_CI = 141;
exports.UCS2_SPANISH2_CI = 142;
exports.UCS2_ROMAN_CI = 143;
exports.UCS2_PERSIAN_CI = 144;
exports.UCS2_ESPERANTO_CI = 145;
exports.UCS2_HUNGARIAN_CI = 146;
exports.UCS2_SINHALA_CI = 147;
exports.UCS2_GERMAN2_CI = 148;
exports.UCS2_CROATIAN_CI = 149;
exports.UCS2_UNICODE_520_CI = 150;
exports.UCS2_VIETNAMESE_CI = 151;
exports.UCS2_GENERAL_MYSQL500_CI = 159;
exports.UTF32_UNICODE_CI = 160;
exports.UTF32_ICELANDIC_CI = 161;
exports.UTF32_LATVIAN_CI = 162;
exports.UTF32_ROMANIAN_CI = 163;
exports.UTF32_SLOVENIAN_CI = 164;
exports.UTF32_POLISH_CI = 165;
exports.UTF32_ESTONIAN_CI = 166;
exports.UTF32_SPANISH_CI = 167;
exports.UTF32_SWEDISH_CI = 168;
exports.UTF32_TURKISH_CI = 169;
exports.UTF32_CZECH_CI = 170;
exports.UTF32_DANISH_CI = 171;
exports.UTF32_LITHUANIAN_CI = 172;
exports.UTF32_SLOVAK_CI = 173;
exports.UTF32_SPANISH2_CI = 174;
exports.UTF32_ROMAN_CI = 175;
exports.UTF32_PERSIAN_CI = 176;
exports.UTF32_ESPERANTO_CI = 177;
exports.UTF32_HUNGARIAN_CI = 178;
exports.UTF32_SINHALA_CI = 179;
exports.UTF32_GERMAN2_CI = 180;
exports.UTF32_CROATIAN_CI = 181;
exports.UTF32_UNICODE_520_CI = 182;
exports.UTF32_VIETNAMESE_CI = 183;
exports.UTF8_UNICODE_CI = 192;
exports.UTF8_ICELANDIC_CI = 193;
exports.UTF8_LATVIAN_CI = 194;
exports.UTF8_ROMANIAN_CI = 195;
exports.UTF8_SLOVENIAN_CI = 196;
exports.UTF8_POLISH_CI = 197;
exports.UTF8_ESTONIAN_CI = 198;
exports.UTF8_SPANISH_CI = 199;
exports.UTF8_SWEDISH_CI = 200;
exports.UTF8_TURKISH_CI = 201;
exports.UTF8_CZECH_CI = 202;
exports.UTF8_DANISH_CI = 203;
exports.UTF8_LITHUANIAN_CI = 204;
exports.UTF8_SLOVAK_CI = 205;
exports.UTF8_SPANISH2_CI = 206;
exports.UTF8_ROMAN_CI = 207;
exports.UTF8_PERSIAN_CI = 208;
exports.UTF8_ESPERANTO_CI = 209;
exports.UTF8_HUNGARIAN_CI = 210;
exports.UTF8_SINHALA_CI = 211;
exports.UTF8_GERMAN2_CI = 212;
exports.UTF8_CROATIAN_CI = 213;
exports.UTF8_UNICODE_520_CI = 214;
exports.UTF8_VIETNAMESE_CI = 215;
exports.UTF8_GENERAL_MYSQL500_CI = 223;
exports.UTF8MB4_UNICODE_CI = 224;
exports.UTF8MB4_ICELANDIC_CI = 225;
exports.UTF8MB4_LATVIAN_CI = 226;
exports.UTF8MB4_ROMANIAN_CI = 227;
exports.UTF8MB4_SLOVENIAN_CI = 228;
exports.UTF8MB4_POLISH_CI = 229;
exports.UTF8MB4_ESTONIAN_CI = 230;
exports.UTF8MB4_SPANISH_CI = 231;
exports.UTF8MB4_SWEDISH_CI = 232;
exports.UTF8MB4_TURKISH_CI = 233;
exports.UTF8MB4_CZECH_CI = 234;
exports.UTF8MB4_DANISH_CI = 235;
exports.UTF8MB4_LITHUANIAN_CI = 236;
exports.UTF8MB4_SLOVAK_CI = 237;
exports.UTF8MB4_SPANISH2_CI = 238;
exports.UTF8MB4_ROMAN_CI = 239;
exports.UTF8MB4_PERSIAN_CI = 240;
exports.UTF8MB4_ESPERANTO_CI = 241;
exports.UTF8MB4_HUNGARIAN_CI = 242;
exports.UTF8MB4_SINHALA_CI = 243;
exports.UTF8MB4_GERMAN2_CI = 244;
exports.UTF8MB4_CROATIAN_CI = 245;
exports.UTF8MB4_UNICODE_520_CI = 246;
exports.UTF8MB4_VIETNAMESE_CI = 247;
exports.GB18030_CHINESE_CI = 248;
exports.GB18030_BIN = 249;
exports.GB18030_UNICODE_520_CI = 250;
exports.UTF8_GENERAL50_CI = 253; // deprecated
exports.UTF8MB4_0900_AI_CI = 255;
exports.UTF8MB4_DE_PB_0900_AI_CI = 256;
exports.UTF8MB4_IS_0900_AI_CI = 257;
exports.UTF8MB4_LV_0900_AI_CI = 258;
exports.UTF8MB4_RO_0900_AI_CI = 259;
exports.UTF8MB4_SL_0900_AI_CI = 260;
exports.UTF8MB4_PL_0900_AI_CI = 261;
exports.UTF8MB4_ET_0900_AI_CI = 262;
exports.UTF8MB4_ES_0900_AI_CI = 263;
exports.UTF8MB4_SV_0900_AI_CI = 264;
exports.UTF8MB4_TR_0900_AI_CI = 265;
exports.UTF8MB4_CS_0900_AI_CI = 266;
exports.UTF8MB4_DA_0900_AI_CI = 267;
exports.UTF8MB4_LT_0900_AI_CI = 268;
exports.UTF8MB4_SK_0900_AI_CI = 269;
exports.UTF8MB4_ES_TRAD_0900_AI_CI = 270;
exports.UTF8MB4_LA_0900_AI_CI = 271;
exports.UTF8MB4_EO_0900_AI_CI = 273;
exports.UTF8MB4_HU_0900_AI_CI = 274;
exports.UTF8MB4_HR_0900_AI_CI = 275;
exports.UTF8MB4_VI_0900_AI_CI = 277;
exports.UTF8MB4_0900_AS_CS = 278;
exports.UTF8MB4_DE_PB_0900_AS_CS = 279;
exports.UTF8MB4_IS_0900_AS_CS = 280;
exports.UTF8MB4_LV_0900_AS_CS = 281;
exports.UTF8MB4_RO_0900_AS_CS = 282;
exports.UTF8MB4_SL_0900_AS_CS = 283;
exports.UTF8MB4_PL_0900_AS_CS = 284;
exports.UTF8MB4_ET_0900_AS_CS = 285;
exports.UTF8MB4_ES_0900_AS_CS = 286;
exports.UTF8MB4_SV_0900_AS_CS = 287;
exports.UTF8MB4_TR_0900_AS_CS = 288;
exports.UTF8MB4_CS_0900_AS_CS = 289;
exports.UTF8MB4_DA_0900_AS_CS = 290;
exports.UTF8MB4_LT_0900_AS_CS = 291;
exports.UTF8MB4_SK_0900_AS_CS = 292;
exports.UTF8MB4_ES_TRAD_0900_AS_CS = 293;
exports.UTF8MB4_LA_0900_AS_CS = 294;
exports.UTF8MB4_EO_0900_AS_CS = 296;
exports.UTF8MB4_HU_0900_AS_CS = 297;
exports.UTF8MB4_HR_0900_AS_CS = 298;
exports.UTF8MB4_VI_0900_AS_CS = 300;
exports.UTF8MB4_JA_0900_AS_CS = 303;
exports.UTF8MB4_JA_0900_AS_CS_KS = 304;
exports.UTF8MB4_0900_AS_CI = 305;
exports.UTF8MB4_RU_0900_AI_CI = 306;
exports.UTF8MB4_RU_0900_AS_CS = 307;
exports.UTF8MB4_ZH_0900_AS_CS = 308;
exports.UTF8MB4_0900_BIN = 309;
// short aliases
exports.BIG5 = exports.BIG5_CHINESE_CI;
exports.DEC8 = exports.DEC8_SWEDISH_CI;
exports.CP850 = exports.CP850_GENERAL_CI;
exports.HP8 = exports.HP8_ENGLISH_CI;
exports.KOI8R = exports.KOI8R_GENERAL_CI;
exports.LATIN1 = exports.LATIN1_SWEDISH_CI;
exports.LATIN2 = exports.LATIN2_GENERAL_CI;
exports.SWE7 = exports.SWE7_SWEDISH_CI;
exports.ASCII = exports.ASCII_GENERAL_CI;
exports.UJIS = exports.UJIS_JAPANESE_CI;
exports.SJIS = exports.SJIS_JAPANESE_CI;
exports.HEBREW = exports.HEBREW_GENERAL_CI;
exports.TIS620 = exports.TIS620_THAI_CI;
exports.EUCKR = exports.EUCKR_KOREAN_CI;
exports.KOI8U = exports.KOI8U_GENERAL_CI;
exports.GB2312 = exports.GB2312_CHINESE_CI;
exports.GREEK = exports.GREEK_GENERAL_CI;
exports.CP1250 = exports.CP1250_GENERAL_CI;
exports.GBK = exports.GBK_CHINESE_CI;
exports.LATIN5 = exports.LATIN5_TURKISH_CI;
exports.ARMSCII8 = exports.ARMSCII8_GENERAL_CI;
exports.UTF8 = exports.UTF8_GENERAL_CI;
exports.UCS2 = exports.UCS2_GENERAL_CI;
exports.CP866 = exports.CP866_GENERAL_CI;
exports.KEYBCS2 = exports.KEYBCS2_GENERAL_CI;
exports.MACCE = exports.MACCE_GENERAL_CI;
exports.MACROMAN = exports.MACROMAN_GENERAL_CI;
exports.CP852 = exports.CP852_GENERAL_CI;
exports.LATIN7 = exports.LATIN7_GENERAL_CI;
exports.UTF8MB4 = exports.UTF8MB4_GENERAL_CI;
exports.CP1251 = exports.CP1251_GENERAL_CI;
exports.UTF16 = exports.UTF16_GENERAL_CI;
exports.UTF16LE = exports.UTF16LE_GENERAL_CI;
exports.CP1256 = exports.CP1256_GENERAL_CI;
exports.CP1257 = exports.CP1257_GENERAL_CI;
exports.UTF32 = exports.UTF32_GENERAL_CI;
exports.CP932 = exports.CP932_JAPANESE_CI;
exports.EUCJPMS = exports.EUCJPMS_JAPANESE_CI;
exports.GB18030 = exports.GB18030_CHINESE_CI;
exports.GEOSTD8 = exports.GEOSTD8_GENERAL_CI;

View File

@@ -1,39 +0,0 @@
// This file was modified by Oracle on September 21, 2021.
// New capability for multi-factor authentication based on mandatory session
// trackers, that are signaled with an extra single-byte prefix on new
// versions of the MySQL server.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
'use strict';
// Manually extracted from mysql-5.5.23/include/mysql_com.h
exports.LONG_PASSWORD = 0x00000001; /* new more secure passwords */
exports.FOUND_ROWS = 0x00000002; /* found instead of affected rows */
exports.LONG_FLAG = 0x00000004; /* get all column flags */
exports.CONNECT_WITH_DB = 0x00000008; /* one can specify db on connect */
exports.NO_SCHEMA = 0x00000010; /* don't allow database.table.column */
exports.COMPRESS = 0x00000020; /* can use compression protocol */
exports.ODBC = 0x00000040; /* odbc client */
exports.LOCAL_FILES = 0x00000080; /* can use LOAD DATA LOCAL */
exports.IGNORE_SPACE = 0x00000100; /* ignore spaces before '' */
exports.PROTOCOL_41 = 0x00000200; /* new 4.1 protocol */
exports.INTERACTIVE = 0x00000400; /* this is an interactive client */
exports.SSL = 0x00000800; /* switch to ssl after handshake */
exports.IGNORE_SIGPIPE = 0x00001000; /* IGNORE sigpipes */
exports.TRANSACTIONS = 0x00002000; /* client knows about transactions */
exports.RESERVED = 0x00004000; /* old flag for 4.1 protocol */
exports.SECURE_CONNECTION = 0x00008000; /* new 4.1 authentication */
exports.MULTI_STATEMENTS = 0x00010000; /* enable/disable multi-stmt support */
exports.MULTI_RESULTS = 0x00020000; /* enable/disable multi-results */
exports.PS_MULTI_RESULTS = 0x00040000; /* multi-results in ps-protocol */
exports.PLUGIN_AUTH = 0x00080000; /* client supports plugin authentication */
exports.CONNECT_ATTRS = 0x00100000; /* permits connection attributes */
exports.PLUGIN_AUTH_LENENC_CLIENT_DATA = 0x00200000; /* Understands length-encoded integer for auth response data in Protocol::HandshakeResponse41. */
exports.CAN_HANDLE_EXPIRED_PASSWORDS = 0x00400000; /* Announces support for expired password extension. */
exports.SESSION_TRACK = 0x00800000; /* Can set SERVER_SESSION_STATE_CHANGED in the Status Flags and send session-state change data after a OK packet. */
exports.DEPRECATE_EOF = 0x01000000; /* Can send OK after a Text Resultset. */
exports.SSL_VERIFY_SERVER_CERT = 0x40000000;
exports.REMEMBER_OPTIONS = 0x80000000;
exports.MULTI_FACTOR_AUTHENTICATION = 0x10000000; /* multi-factor authentication */

View File

@@ -1,36 +0,0 @@
'use strict';
module.exports = {
SLEEP: 0x00, // deprecated
QUIT: 0x01,
INIT_DB: 0x02,
QUERY: 0x03,
FIELD_LIST: 0x04,
CREATE_DB: 0x05,
DROP_DB: 0x06,
REFRESH: 0x07,
SHUTDOWN: 0x08,
STATISTICS: 0x09,
PROCESS_INFO: 0x0a, // deprecated
CONNECT: 0x0b, // deprecated
PROCESS_KILL: 0x0c,
DEBUG: 0x0d,
PING: 0x0e,
TIME: 0x0f, // deprecated
DELAYED_INSERT: 0x10, // deprecated
CHANGE_USER: 0x11,
BINLOG_DUMP: 0x12,
TABLE_DUMP: 0x13,
CONNECT_OUT: 0x14,
REGISTER_SLAVE: 0x15,
STMT_PREPARE: 0x16,
STMT_EXECUTE: 0x17,
STMT_SEND_LONG_DATA: 0x18,
STMT_CLOSE: 0x19,
STMT_RESET: 0x1a,
SET_OPTION: 0x1b,
STMT_FETCH: 0x1c,
DAEMON: 0x1d, // deprecated
BINLOG_DUMP_GTID: 0x1e,
UNKNOWN: 0xff, // bad!
};

View File

@@ -1,8 +0,0 @@
'use strict';
module.exports = {
NO_CURSOR: 0,
READ_ONLY: 1,
FOR_UPDATE: 2,
SCROLLABLE: 3,
};

View File

@@ -1,50 +0,0 @@
'use strict';
// inverse of charset_encodings
// given encoding, get matching mysql charset number
module.exports = {
big5: 1,
latin2: 2,
dec8: 3,
cp850: 4,
latin1: 5,
hp8: 6,
koi8r: 7,
swe7: 10,
ascii: 11,
eucjp: 12,
sjis: 13,
cp1251: 14,
hebrew: 16,
tis620: 18,
euckr: 19,
latin7: 20,
koi8u: 22,
gb2312: 24,
greek: 25,
cp1250: 26,
gbk: 28,
cp1257: 29,
latin5: 30,
armscii8: 32,
cesu8: 33,
ucs2: 35,
cp866: 36,
keybcs2: 37,
macintosh: 38,
macroman: 39,
cp852: 40,
utf8: 45,
utf8mb4: 45,
utf16: 54,
utf16le: 56,
cp1256: 57,
utf32: 60,
binary: 63,
geostd8: 92,
cp932: 95,
eucjpms: 97,
gb18030: 248,
utf8mb3: 192,
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +0,0 @@
'use strict';
// Manually extracted from mysql-5.5.23/include/mysql_com.h
exports.NOT_NULL = 1; /* Field can't be NULL */
exports.PRI_KEY = 2; /* Field is part of a primary key */
exports.UNIQUE_KEY = 4; /* Field is part of a unique key */
exports.MULTIPLE_KEY = 8; /* Field is part of a key */
exports.BLOB = 16; /* Field is a blob */
exports.UNSIGNED = 32; /* Field is unsigned */
exports.ZEROFILL = 64; /* Field is zerofill */
exports.BINARY = 128; /* Field is binary */
/* The following are only sent to new clients */
exports.ENUM = 256; /* field is an enum */
exports.AUTO_INCREMENT = 512; /* field is a autoincrement field */
exports.TIMESTAMP = 1024; /* Field is a timestamp */
exports.SET = 2048; /* field is a set */
exports.NO_DEFAULT_VALUE = 4096; /* Field doesn't have default value */
exports.ON_UPDATE_NOW = 8192; /* Field is set to NOW on UPDATE */
exports.NUM = 32768; /* Field is num (for clients) */

View File

@@ -1,44 +0,0 @@
'use strict';
// Manually extracted from mysql-5.5.23/include/mysql_com.h
/**
Is raised when a multi-statement transaction
has been started, either explicitly, by means
of BEGIN or COMMIT AND CHAIN, or
implicitly, by the first transactional
statement, when autocommit=off.
*/
exports.SERVER_STATUS_IN_TRANS = 1;
exports.SERVER_STATUS_AUTOCOMMIT = 2; /* Server in auto_commit mode */
exports.SERVER_MORE_RESULTS_EXISTS = 8; /* Multi query - next query exists */
exports.SERVER_QUERY_NO_GOOD_INDEX_USED = 16;
exports.SERVER_QUERY_NO_INDEX_USED = 32;
/**
The server was able to fulfill the clients request and opened a
read-only non-scrollable cursor for a query. This flag comes
in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands.
*/
exports.SERVER_STATUS_CURSOR_EXISTS = 64;
/**
This flag is sent when a read-only cursor is exhausted, in reply to
COM_STMT_FETCH command.
*/
exports.SERVER_STATUS_LAST_ROW_SENT = 128;
exports.SERVER_STATUS_DB_DROPPED = 256; /* A database was dropped */
exports.SERVER_STATUS_NO_BACKSLASH_ESCAPES = 512;
/**
Sent to the client if after a prepared statement reprepare
we discovered that the new statement returns a different
number of result set columns.
*/
exports.SERVER_STATUS_METADATA_CHANGED = 1024;
exports.SERVER_QUERY_WAS_SLOW = 2048;
/**
To mark ResultSet containing output parameter values.
*/
exports.SERVER_PS_OUT_PARAMS = 4096;
exports.SERVER_STATUS_IN_TRANS_READONLY = 0x2000; // in a read-only transaction
exports.SERVER_SESSION_STATE_CHANGED = 0x4000;

View File

@@ -1,11 +0,0 @@
'use strict';
exports.SYSTEM_VARIABLES = 0;
exports.SCHEMA = 1;
exports.STATE_CHANGE = 2;
exports.STATE_GTIDS = 3;
exports.TRANSACTION_CHARACTERISTICS = 4;
exports.TRANSACTION_STATE = 5;
exports.FIRST_KEY = exports.SYSTEM_VARIABLES;
exports.LAST_KEY = exports.TRANSACTION_STATE;

View File

@@ -1,11 +0,0 @@
'use strict';
const awsCaBundle = require('aws-ssl-profiles');
/**
* @deprecated
* Please, use [**aws-ssl-profiles**](https://github.com/mysqljs/aws-ssl-profiles).
*/
exports['Amazon RDS'] = {
ca: awsCaBundle.ca,
};

View File

@@ -1,64 +0,0 @@
'use strict';
module.exports = {
0x00: 'DECIMAL', // aka DECIMAL
0x01: 'TINY', // aka TINYINT, 1 byte
0x02: 'SHORT', // aka SMALLINT, 2 bytes
0x03: 'LONG', // aka INT, 4 bytes
0x04: 'FLOAT', // aka FLOAT, 4-8 bytes
0x05: 'DOUBLE', // aka DOUBLE, 8 bytes
0x06: 'NULL', // NULL (used for prepared statements, I think)
0x07: 'TIMESTAMP', // aka TIMESTAMP
0x08: 'LONGLONG', // aka BIGINT, 8 bytes
0x09: 'INT24', // aka MEDIUMINT, 3 bytes
0x0a: 'DATE', // aka DATE
0x0b: 'TIME', // aka TIME
0x0c: 'DATETIME', // aka DATETIME
0x0d: 'YEAR', // aka YEAR, 1 byte (don't ask)
0x0e: 'NEWDATE', // aka ?
0x0f: 'VARCHAR', // aka VARCHAR (?)
0x10: 'BIT', // aka BIT, 1-8 byte
0xf5: 'JSON',
0xf6: 'NEWDECIMAL', // aka DECIMAL
0xf7: 'ENUM', // aka ENUM
0xf8: 'SET', // aka SET
0xf9: 'TINY_BLOB', // aka TINYBLOB, TINYTEXT
0xfa: 'MEDIUM_BLOB', // aka MEDIUMBLOB, MEDIUMTEXT
0xfb: 'LONG_BLOB', // aka LONGBLOG, LONGTEXT
0xfc: 'BLOB', // aka BLOB, TEXT
0xfd: 'VAR_STRING', // aka VARCHAR, VARBINARY
0xfe: 'STRING', // aka CHAR, BINARY
0xff: 'GEOMETRY', // aka GEOMETRY
};
// Manually extracted from mysql-5.5.23/include/mysql_com.h
// some more info here: http://dev.mysql.com/doc/refman/5.5/en/c-api-prepared-statement-type-codes.html
module.exports.DECIMAL = 0x00; // aka DECIMAL (http://dev.mysql.com/doc/refman/5.0/en/precision-math-decimal-changes.html)
module.exports.TINY = 0x01; // aka TINYINT, 1 byte
module.exports.SHORT = 0x02; // aka SMALLINT, 2 bytes
module.exports.LONG = 0x03; // aka INT, 4 bytes
module.exports.FLOAT = 0x04; // aka FLOAT, 4-8 bytes
module.exports.DOUBLE = 0x05; // aka DOUBLE, 8 bytes
module.exports.NULL = 0x06; // NULL (used for prepared statements, I think)
module.exports.TIMESTAMP = 0x07; // aka TIMESTAMP
module.exports.LONGLONG = 0x08; // aka BIGINT, 8 bytes
module.exports.INT24 = 0x09; // aka MEDIUMINT, 3 bytes
module.exports.DATE = 0x0a; // aka DATE
module.exports.TIME = 0x0b; // aka TIME
module.exports.DATETIME = 0x0c; // aka DATETIME
module.exports.YEAR = 0x0d; // aka YEAR, 1 byte (don't ask)
module.exports.NEWDATE = 0x0e; // aka ?
module.exports.VARCHAR = 0x0f; // aka VARCHAR (?)
module.exports.BIT = 0x10; // aka BIT, 1-8 byte
module.exports.VECTOR = 0xf2;
module.exports.JSON = 0xf5;
module.exports.NEWDECIMAL = 0xf6; // aka DECIMAL
module.exports.ENUM = 0xf7; // aka ENUM
module.exports.SET = 0xf8; // aka SET
module.exports.TINY_BLOB = 0xf9; // aka TINYBLOB, TINYTEXT
module.exports.MEDIUM_BLOB = 0xfa; // aka MEDIUMBLOB, MEDIUMTEXT
module.exports.LONG_BLOB = 0xfb; // aka LONGBLOG, LONGTEXT
module.exports.BLOB = 0xfc; // aka BLOB, TEXT
module.exports.VAR_STRING = 0xfd; // aka VARCHAR, VARBINARY
module.exports.STRING = 0xfe; // aka CHAR, BINARY
module.exports.GEOMETRY = 0xff; // aka GEOMETRY

View File

@@ -1,10 +0,0 @@
'use strict';
const Connection = require('./connection.js');
const ConnectionConfig = require('./connection_config.js');
function createConnection(opts) {
return new Connection({ config: new ConnectionConfig(opts) });
}
module.exports = createConnection;

Some files were not shown because too many files have changed in this diff Show More