experiments in a post-browser web
1#!/usr/bin/env node
2
3/**
4 * Railway Log Verification Helper
5 *
6 * Checks Railway logs for sync markers from e2e tests.
7 *
8 * Usage:
9 * node backend/tests/verify-railway-logs.js [marker]
10 * yarn test:sync:verify-logs [marker]
11 *
12 * Examples:
13 * # Check for a specific test run
14 * node backend/tests/verify-railway-logs.js "E2E-TEST-1737481234567"
15 *
16 * # Check for recent sync activity
17 * node backend/tests/verify-railway-logs.js
18 *
19 * Note: Requires Railway CLI to be installed and linked to the project.
20 * cd backend/server && railway link -p amusing-courtesy
21 */
22
23import { spawn } from 'child_process';
24import { dirname, join } from 'path';
25import { fileURLToPath } from 'url';
26
27const __dirname = dirname(fileURLToPath(import.meta.url));
28const SERVER_DIR = join(__dirname, '..', 'server');
29
30const marker = process.argv[2] || 'Sync Item Received';
31const lineCount = process.argv[3] || '100';
32
33console.log('='.repeat(60));
34console.log('Railway Log Verification');
35console.log('='.repeat(60));
36console.log(`Searching for: ${marker}`);
37console.log(`Log lines: ${lineCount}`);
38console.log('');
39
40function runCommand(command, args, options = {}) {
41 return new Promise((resolve, reject) => {
42 const proc = spawn(command, args, {
43 cwd: options.cwd || process.cwd(),
44 stdio: ['pipe', 'pipe', 'pipe'],
45 });
46
47 let stdout = '';
48 let stderr = '';
49
50 proc.stdout.on('data', (data) => {
51 stdout += data.toString();
52 });
53
54 proc.stderr.on('data', (data) => {
55 stderr += data.toString();
56 });
57
58 proc.on('close', (code) => {
59 if (code === 0) {
60 resolve(stdout);
61 } else {
62 reject(new Error(`Command failed with code ${code}: ${stderr}`));
63 }
64 });
65
66 proc.on('error', (err) => {
67 reject(err);
68 });
69 });
70}
71
72async function checkRailwayCli() {
73 try {
74 await runCommand('which', ['railway']);
75 return true;
76 } catch {
77 return false;
78 }
79}
80
81async function fetchRailwayLogs() {
82 console.log('Fetching Railway logs...');
83 console.log('');
84
85 try {
86 const logs = await runCommand('railway', [
87 'logs',
88 '-n', lineCount,
89 '--service', 'peek-node'
90 ], { cwd: SERVER_DIR });
91
92 return logs;
93 } catch (error) {
94 console.error('Failed to fetch Railway logs:', error.message);
95 console.error('');
96 console.error('Make sure you have Railway CLI installed and linked:');
97 console.error(' 1. Install: npm install -g @railway/cli');
98 console.error(' 2. Login: railway login');
99 console.error(' 3. Link: cd backend/server && railway link -p amusing-courtesy');
100 console.error('');
101 process.exit(1);
102 }
103}
104
105async function main() {
106 // Check Railway CLI is installed
107 const hasRailway = await checkRailwayCli();
108 if (!hasRailway) {
109 console.error('Railway CLI not found.');
110 console.error('');
111 console.error('Install with: npm install -g @railway/cli');
112 console.error('');
113 process.exit(1);
114 }
115
116 // Fetch logs
117 const logs = await fetchRailwayLogs();
118
119 // Filter for marker
120 const lines = logs.split('\n');
121 const matchingLines = lines.filter(line =>
122 line.includes(marker)
123 );
124
125 if (matchingLines.length === 0) {
126 console.log(`No log entries found matching: ${marker}`);
127 console.log('');
128 console.log('This could mean:');
129 console.log(' 1. The test items haven\'t been synced yet');
130 console.log(' 2. The server hasn\'t been deployed with sync logging');
131 console.log(' 3. The logs have rotated past the search window');
132 console.log('');
133 console.log('Full logs (last 20 lines):');
134 console.log('-'.repeat(60));
135 console.log(lines.slice(-20).join('\n'));
136 console.log('-'.repeat(60));
137 process.exit(1);
138 }
139
140 console.log(`Found ${matchingLines.length} matching log entries:`);
141 console.log('-'.repeat(60));
142
143 // Group by sync blocks
144 let inBlock = false;
145 let currentBlock = [];
146
147 for (const line of lines) {
148 if (line.includes('=== Sync Item Received ===')) {
149 inBlock = true;
150 currentBlock = [line];
151 } else if (line.includes('==========================')) {
152 currentBlock.push(line);
153 inBlock = false;
154
155 // Check if this block matches our marker
156 const blockText = currentBlock.join('\n');
157 if (blockText.includes(marker)) {
158 console.log(blockText);
159 console.log('');
160 }
161 currentBlock = [];
162 } else if (inBlock) {
163 currentBlock.push(line);
164 } else if (line.includes(marker)) {
165 // Non-block match
166 console.log(line);
167 }
168 }
169
170 console.log('-'.repeat(60));
171 console.log('');
172 console.log(`Total matches: ${matchingLines.length}`);
173 console.log('');
174 console.log('='.repeat(60));
175}
176
177main().catch((error) => {
178 console.error('Error:', error.message);
179 process.exit(1);
180});