const express = require('express'); const { chromium } = require('playwright'); const cors = require('cors'); const { NodeVM } = require('vm2'); const axios = require('axios'); const app = express(); const PORT = process.env.PORT || 7860; app.set('json spaces', 2); app.use(cors()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use((req, res, next) => { console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`); next(); }); app.get('/', (req, res) => { res.json({ success: true, endpoints: { playwright_v1: 'POST /v1', playwright_v2: 'POST /v2', playwright_v3: 'POST /v3' }, timestamp: new Date().toISOString() }); }); app.post('/v1', async (req, res) => { const { code, timeout = 300000 } = req.body; if (!code) { return res.status(400).json({ error: { message: 'Code is required', type: 'invalid_request_error' } }); } let output = []; const originalLog = console.log; console.log = (...args) => { const message = args.map(arg => (typeof arg === 'object' ? JSON.stringify(arg) : arg)).join(' '); output.push(message); originalLog.apply(console, args); }; const vm = new NodeVM({ console: 'inherit', sandbox: {}, require: { external: true, builtin: ['fs', 'path'], root: './', mock: { playwright: { chromium }, }, }, }); const script = ` module.exports = async () => { ${code} }; `; let runCode; try { runCode = vm.run(script, 'sandbox.js'); } catch (error) { console.log = originalLog; return res.status(500).json({ error: { message: 'Failed to run code', details: error.message, type: 'execution_error' } }); } try { await runCode(); const startTime = Date.now(); while (output.length === 0 && Date.now() - startTime < timeout) { await new Promise(resolve => setTimeout(resolve, 1000)); } const result = output.length > 0 ? output.pop() : 'No output found.'; console.log = originalLog; res.json({ data: result }); } catch (err) { console.log = originalLog; res.status(500).json({ error: { message: 'Error while executing code', details: err.message, type: 'execution_error' } }); } }); app.post('/v2', async (req, res) => { const { code, timeout = 300000 } = req.body; if (!code) { return res.status(400).json({ error: { message: 'Code is required', type: 'invalid_request_error' } }); } let output = []; const originalLog = console.log; console.log = (...args) => { const message = args.map(arg => (typeof arg === 'object' ? JSON.stringify(arg) : arg)).join(' '); output.push(message); originalLog.apply(console, args); }; let runCode; try { runCode = eval(` (async () => { ${code} })(); `); } catch (error) { console.log = originalLog; return res.status(500).json({ error: { message: 'Failed to run code', details: error.message, type: 'execution_error' } }); } try { await runCode; const startTime = Date.now(); while (output.length === 0 && Date.now() - startTime < timeout) { await new Promise(resolve => setTimeout(resolve, 1000)); } const result = output.length > 0 ? output.pop() : 'No output found.'; console.log = originalLog; res.json({ data: result }); } catch (err) { console.log = originalLog; res.status(500).json({ error: { message: 'Error while executing code', details: err.message, type: 'execution_error' } }); } }); app.post('/v3', async (req, res) => { const { code, language = 'javascript' } = req.body; if (!code) { return res.status(400).json({ error: { message: 'Code is required', type: 'invalid_request_error' } }); } const MAX_RETRIES = 3; let lastMessage = null; let lastDetails = null; for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) { try { const { data: cf } = await axios.post('https://rynekoo-cf.hf.space/action', { url: 'https://try.playwright.tech/', siteKey: '0x4AAAAAAA_K0T_2LZ0rgUtv', mode: 'turnstile-min' }); if (!cf?.data?.token) throw new Error('Failed to get cf token.'); const { data } = await axios.post('https://try.playwright.tech/service/control/run', { code, language, token: cf.data.token }, { headers: { origin: 'https://try.playwright.tech', referer: 'https://try.playwright.tech/', 'user-agent': 'Mozilla/5.0 (Linux; Android 15; SM-F958 Build/AP3A.240905.015) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.86 Mobile Safari/537.36' } }); const isTimeout = data?.error === 'Execution timeout!'; const isProtocolError = typeof data?.output === 'string' && data.output.includes('Protocol error'); if ((isTimeout || isProtocolError) && attempt < MAX_RETRIES) { lastMessage = data?.error || 'Error while executing code'; lastDetails = data?.output || null; continue; } return res.json({ data: data.output }); } catch (error) { const errData = error.response?.data; const isTimeout = errData?.error === 'Execution timeout!'; const isProtocolError = typeof errData?.output === 'string' && errData.output.includes('Protocol error'); lastMessage = errData?.error || 'Error while executing code'; lastDetails = errData?.output || null; if ((isTimeout || isProtocolError) && attempt < MAX_RETRIES) { continue; } return res.status(500).json({ error: { message: lastMessage, details: lastDetails, type: 'execution_error' } }); } } res.status(500).json({ error: { message: lastMessage, details: lastDetails, type: 'execution_error' } }); }); app.use((err, req, res, next) => { console.error('Error:', err.message); res.status(err.status || 500).json({ error: { message: err.message || 'Internal server error', type: 'api_error' } }); }); app.use((req, res) => { res.status(404).json({ error: { message: 'Not found', type: 'invalid_request_error' } }); }); function startServer() { app.listen(PORT, () => { console.log(`Playwright API Server running on http://localhost:${PORT}`); console.log('\nAvailable endpoints:'); console.log(` POST http://localhost:${PORT}/v1`); console.log(` POST http://localhost:${PORT}/v2`); console.log(` POST http://localhost:${PORT}/v3`); }); } process.on('SIGINT', () => { console.log('\nShutting down...'); process.exit(0); }); startServer();