import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as net from 'net'; import { SmartProxy } from '../ts/index.js'; tap.test('should handle async handler that sets up listeners after delay', async () => { const proxy = new SmartProxy({ routes: [{ name: 'delayed-setup-handler', match: { ports: 7777 }, action: { type: 'socket-handler', socketHandler: async (socket, context) => { // Simulate async work BEFORE setting up listeners await new Promise(resolve => setTimeout(resolve, 50)); // Now set up the listener - with the race condition, this would miss initial data socket.on('data', (data) => { const message = data.toString().trim(); socket.write(`RECEIVED: ${message}\n`); if (message === 'close') { socket.end(); } }); // Send ready message socket.write('HANDLER READY\n'); } } }], enableDetailedLogging: false }); await proxy.start(); // Test connection const client = new net.Socket(); let response = ''; client.on('data', (data) => { response += data.toString(); }); await new Promise((resolve, reject) => { client.connect(7777, 'localhost', () => { // Send initial data immediately - this tests the race condition client.write('initial-message\n'); resolve(); }); client.on('error', reject); }); // Wait for handler setup and initial data processing await new Promise(resolve => setTimeout(resolve, 150)); // Send another message to verify handler is working client.write('test-message\n'); // Wait for response await new Promise(resolve => setTimeout(resolve, 50)); // Send close command client.write('close\n'); // Wait for connection to close await new Promise(resolve => { client.on('close', () => resolve(undefined)); }); console.log('Response:', response); // Should have received the ready message expect(response).toContain('HANDLER READY'); // Should have received the initial message (this would fail with race condition) expect(response).toContain('RECEIVED: initial-message'); // Should have received the test message expect(response).toContain('RECEIVED: test-message'); await proxy.stop(); }); export default tap.start();