Skip to content

Latest commit

 

History

History
368 lines (299 loc) · 8.91 KB

File metadata and controls

368 lines (299 loc) · 8.91 KB

AutoWebhook Usage Examples

Here you will find several examples demonstrating how to use the AutoWebhook library with its multi-tunnel capabilities.

Example 1: Basic Usage (Single Tunnel)

This example shows how to get a single public URL using the new configuration format.

// examples/basic.ts
import { AutoWebhook } from 'autowebhook';

async function main() {
  const webhook = new AutoWebhook({
    tunnels: [{ name: 'my-app', provider: 'ngrok', port: 3000 }]
  });

  try {
    // .start() now returns an array of all tunnel URLs
    const [url] = await webhook.start();

    if (url) {
      console.log('✨ Your webhook is ready:', url);
    }
    console.log('Press Ctrl+C to exit.');

  } catch (error) { 
    console.error('Failed to start AutoWebhook:', error);
  }
}

main();

Example 2: Integration with a Telegram Bot (grammy)

This example shows how to set up a webhook for a bot using the new API.

// examples/telegram-bot.ts
import { AutoWebhook } from 'autowebhook';
import { Bot, webhookCallback } from 'grammy';
import express from 'express';

// --- Configuration ---
const BOT_TOKEN = process.env.BOT_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN';
const PORT = 3000;

async function setupBot() {
  // 1. Initialize AutoWebhook with a single tunnel
  const autowebhook = new AutoWebhook({
    tunnels: [{ name: 'telegram-bot', provider: 'ngrok', port: PORT }]
  });

  // 2. Create a bot instance
  const bot = new Bot(BOT_TOKEN);

  // 3. Set up bot logic
  bot.command('start', (ctx) => ctx.reply('Hi! I am running via AutoWebhook!'));
  bot.on('message', (ctx) => ctx.reply('Received your message!'));

  // 4. Start the tunnel and get the URL
  const [webhookUrl] = await autowebhook.start();
  console.log(`Webhook URL: ${webhookUrl}`);

  // 5. Set up a web server to handle incoming updates from Telegram
  const server = express();
  server.use(express.json());
  server.use(`/webhook`, webhookCallback(bot, 'express'));

  server.listen(PORT, async () => {
    // 6. Set the webhook in Telegram
    await bot.api.setWebhook(`${webhookUrl}/webhook`);
    console.log(`Bot started! Server is listening on port ${PORT}`);
  });
}

setupBot().catch(console.error);

Example 3: Advanced Usage with Multiple Tunnels and Events

This example demonstrates how to start multiple tunnels (one ngrok and one localhost.run) and listen for lifecycle events.

// examples/multi-tunnel.ts
import { AutoWebhook } from 'autowebhook';

const webhook = new AutoWebhook({
  tunnels: [
    {
      name: 'ngrok-main',
      provider: 'ngrok',
      port: 8080,
      ngrok: { region: 'eu' } // Provider-specific config
    },
    {
      name: 'lhr-backup',
      provider: 'localhost.run',
      port: 8080
    }
  ],
  healthCheck: {
    interval: 15000, // Check every 15 seconds
    maxFailures: 2,  // Restart a tunnel after 2 failures
  },
});

// Event: A tunnel is ready and has a public URL
webhook.on('tunnelReady', (name, url) => {
  console.log(`✅ Tunnel "${name}" is ready: ${url}`);
});

// Event: A tunnel has gone down and will be restarted
webhook.on('tunnelDown', (name, error) => {
  console.warn(`⚠️ Tunnel "${name}" is down and will be restarted. Reason: ${error.message}`);
});

// Event: A global error occurred (e.g., failed to start all tunnels)
webhook.on('error', (error) => {
  console.error(`❌ A critical error occurred:`, error);
});

async function run() {
  try {
    const urls = await webhook.start();
    console.log('All tunnels started and ready:', urls);
    // You can now use the array of URLs for your load balancer or A/B tests
  } catch (err) {
    console.error('Failed to start tunnels:', err);
  }
}

run();

Example 4: Advanced ngrok Configuration (TCP Tunnel)

This example shows how to create a TCP tunnel for services like SSH or databases, and how to restrict access using an IP whitelist.

// examples/tcp-tunnel.ts
import { AutoWebhook } from 'autowebhook';

const webhook = new AutoWebhook({
  tunnels: [
    {
      name: 'ssh-tunnel',
      provider: 'ngrok',
      port: 22, // Your local SSH port
      ngrok: {
        proto: 'tcp', // Specify TCP protocol
        region: 'eu',
        allow_cidr: 'YOUR_IP_ADDRESS/32', // Whitelist your IP
      }
    }
  ],
});

webhook.on('tunnelReady', (name, url) => {
  console.log(`✅ TCP Tunnel "${name}" is ready: ${url}`);
  console.log(`You can now connect via: ssh user@${url.replace('tcp://', '')}`);
});

async function run() {
  try {
    await webhook.start();
  } catch (err) {
    console.error('Failed to start tunnels:', err);
  }
}

run();

Example 5: Using with Different Package Managers and Module Systems

This example shows different ways to import and use AutoWebhook depending on your setup.

// ESM (TypeScript/modern Node.js)
import { AutoWebhook } from 'autowebhook';

const webhook = new AutoWebhook({
  tunnels: [{ name: 'my-app', provider: 'ngrok', port: 3000 }]
});
// CommonJS (traditional Node.js)
const { AutoWebhook } = require('autowebhook');

const webhook = new AutoWebhook({
  tunnels: [{ name: 'my-app', provider: 'ngrok', port: 3000 }]
});
// With Bun
import { AutoWebhook } from 'autowebhook';

// Bun supports top-level await
const webhook = new AutoWebhook({
  tunnels: [{ name: 'my-app', provider: 'ngrok', port: 3000 }]
});

const [url] = await webhook.start();
console.log(`Running at: ${url}`);

Best Practices

Error Handling

  1. Always use try-catch blocks with async/await

    try {
      const [url] = await webhook.start();
      console.log('Webhook ready:', url);
    } catch (error) {
      console.error('Failed to start webhook:', error);
    }
  2. Listen for critical events

    webhook.on('error', (error) => {
      // Log to your error tracking service
      errorTracker.capture(error);
    });
    
    webhook.on('tunnelDown', (name, error) => {
      // Notify your monitoring system
      monitor.alert(`Tunnel ${name} is down: ${error.message}`);
    });
  3. Implement graceful shutdown

    ['SIGINT', 'SIGTERM'].forEach(signal => {
      process.on(signal, async () => {
        console.log('Shutting down...');
        await webhook.stop();
        process.exit(0);
      });
    });

Performance Tips

  1. Optimize health checks

    const webhook = new AutoWebhook({
      tunnels: [{ name: 'api', provider: 'ngrok', port: 3000 }],
      healthCheck: {
        interval: 30000,    // Check every 30s instead of default 20s
        timeout: 5000,      // Fail health check after 5s
        maxFailures: 2      // Restart after 2 failures
      }
    });
  2. Use regional endpoints

    // Choose the closest region to your users
    const webhook = new AutoWebhook({
      tunnels: [{
        name: 'eu-tunnel',
        provider: 'ngrok',
        port: 3000,
        ngrok: { region: 'eu' }
      }]
    });

Security Considerations

  1. IP Whitelisting

    const webhook = new AutoWebhook({
      tunnels: [{
        name: 'secure-tunnel',
        provider: 'ngrok',
        port: 3000,
        ngrok: {
          allow_cidr: ['123.123.123.123/32', '10.0.0.0/24']
        }
      }]
    });
  2. Basic Authentication

    const webhook = new AutoWebhook({
      tunnels: [{
        name: 'protected-tunnel',
        provider: 'ngrok',
        port: 3000,
        ngrok: {
          basic_auth: 'username:password'
        }
      }]
    });

Example 6: Error Handling and Graceful Shutdown

This example demonstrates proper error handling and cleanup.

// examples/error-handling.ts
import { AutoWebhook } from 'autowebhook';

const webhook = new AutoWebhook({
  tunnels: [
    { name: 'primary', provider: 'ngrok', port: 3000 },
    { name: 'backup', provider: 'localhost.run', port: 3000 }
  ],
  healthCheck: {
    enabled: true,
    interval: 30000,
    maxFailures: 3
  }
});

// Handle individual tunnel events
webhook.on('tunnelReady', (name, url) => {
  console.log(`✅ Tunnel '${name}' ready: ${url}`);
});

webhook.on('tunnelDown', (name, error) => {
  console.warn(`⚠️ Tunnel '${name}' down: ${error.message}`);
  // You could implement fallback logic here
});

webhook.on('error', (error) => {
  console.error('❌ AutoWebhook error:', error);
});

async function main() {
  try {
    const urls = await webhook.start();
    console.log('🚀 All tunnels started:', urls);
    
    // Your application logic here
    console.log('Application running... Press Ctrl+C to stop');
    
  } catch (error) {
    console.error('💥 Failed to start tunnels:', error);
    process.exit(1);
  }
}

// Graceful shutdown
process.on('SIGINT', async () => {
  console.log('\n🛑 Shutting down gracefully...');
  try {
    await webhook.stop();
    console.log('✅ All tunnels stopped');
    process.exit(0);
  } catch (error) {
    console.error('❌ Error during shutdown:', error);
    process.exit(1);
  }
});

main();