You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							197 lines
						
					
					
						
							5.9 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							197 lines
						
					
					
						
							5.9 KiB
						
					
					
				
								#!/usr/bin/env node
							 | 
						|
								/**
							 | 
						|
								 * Test API Server with Project Seeding
							 | 
						|
								 * 
							 | 
						|
								 * A simple Express server that:
							 | 
						|
								 * 1. Provides the plansLastUpdatedBetween endpoint for prefetch testing
							 | 
						|
								 * 2. Automatically seeds test projects on startup
							 | 
						|
								 * 3. Returns seeded project data in API responses
							 | 
						|
								 * 
							 | 
						|
								 * Usage:
							 | 
						|
								 *   node scripts/test-api-server-with-seed.js [port]
							 | 
						|
								 * 
							 | 
						|
								 * Then in Android emulator, configure:
							 | 
						|
								 *   api.serverMode = "localhost"
							 | 
						|
								 *   api.servers.localhost.android = "http://10.0.2.2:3000"
							 | 
						|
								 * 
							 | 
						|
								 * @author Matthew Raymer
							 | 
						|
								 * @version 1.0.0
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								const express = require('express');
							 | 
						|
								const { generateAllTestProjects, getMockApiResponse, DEFAULT_TEST_PROJECT_IDS } = require('./seed-test-projects');
							 | 
						|
								
							 | 
						|
								const PORT = process.argv[2] || 3000;
							 | 
						|
								const app = express();
							 | 
						|
								
							 | 
						|
								// Store seeded projects in memory
							 | 
						|
								let seededProjects = [];
							 | 
						|
								
							 | 
						|
								// Middleware
							 | 
						|
								app.use(express.json());
							 | 
						|
								app.use((req, res, next) => {
							 | 
						|
								  console.log(`📥 ${req.method} ${req.path}`);
							 | 
						|
								  next();
							 | 
						|
								});
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Seed test projects on startup
							 | 
						|
								 */
							 | 
						|
								function seedProjects(projectIds = DEFAULT_TEST_PROJECT_IDS) {
							 | 
						|
								  // Validate plan IDs are valid URIs
							 | 
						|
								  const invalidIds = projectIds.filter(id => !id.match(/^[A-Za-z][A-Za-z0-9+.-]+:/));
							 | 
						|
								  if (invalidIds.length > 0) {
							 | 
						|
								    console.error('');
							 | 
						|
								    console.error('❌ ERROR: Invalid plan handle ID format!');
							 | 
						|
								    console.error('   Plan handle IDs must be valid URIs (RFC 3986).');
							 | 
						|
								    console.error('   Expected format: https://endorser.ch/entity/{ULID}');
							 | 
						|
								    console.error(`   Invalid IDs: ${invalidIds.join(', ')}`);
							 | 
						|
								    console.error('');
							 | 
						|
								    console.error('   Valid examples:');
							 | 
						|
								    console.error('     https://endorser.ch/entity/01GQBE7Q0RQQAGJMEEW6RSGKTF');
							 | 
						|
								    console.error('     http://example.com/project/123');
							 | 
						|
								    console.error('     did:ethr:0x1234...');
							 | 
						|
								    console.error('');
							 | 
						|
								    process.exit(1);
							 | 
						|
								  }
							 | 
						|
								  
							 | 
						|
								  seededProjects = generateAllTestProjects(projectIds);
							 | 
						|
								  console.log(`🌱 Seeded ${seededProjects.length} test projects with valid URI format:`);
							 | 
						|
								  seededProjects.forEach((project, index) => {
							 | 
						|
								    console.log(`   ${index + 1}. ${project.planSummary.handleId} - ${project.planSummary.name}`);
							 | 
						|
								  });
							 | 
						|
								  
							 | 
						|
								  console.log('');
							 | 
						|
								  console.log('📝 Note: These are auto-generated test IDs.');
							 | 
						|
								  console.log('   For testing with real projects, use IDs from your TimeSafari database.');
							 | 
						|
								  console.log('   Update: test-apps/daily-notification-test/src/config/test-user-zero.ts');
							 | 
						|
								  console.log('');
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * POST /api/v2/report/plansLastUpdatedBetween
							 | 
						|
								 * 
							 | 
						|
								 * Endpoint that the plugin calls for starred projects prefetch
							 | 
						|
								 */
							 | 
						|
								app.post('/api/v2/report/plansLastUpdatedBetween', (req, res) => {
							 | 
						|
								  const { planIds, afterId } = req.body;
							 | 
						|
								
							 | 
						|
								  console.log('📥 Prefetch request received:', {
							 | 
						|
								    planIds: planIds || 'not provided',
							 | 
						|
								    afterId: afterId || 'none',
							 | 
						|
								    authorization: req.headers.authorization ? 'present' : 'missing',
							 | 
						|
								    timestamp: new Date().toISOString()
							 | 
						|
								  });
							 | 
						|
								
							 | 
						|
								  // Filter seeded projects to only those requested
							 | 
						|
								  let filteredProjects = seededProjects;
							 | 
						|
								  if (planIds && Array.isArray(planIds) && planIds.length > 0) {
							 | 
						|
								    filteredProjects = seededProjects.filter(p =>
							 | 
						|
								      planIds.includes(p.planSummary.handleId)
							 | 
						|
								    );
							 | 
						|
								    console.log(`   Filtered to ${filteredProjects.length} projects matching planIds`);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // Filter by afterId if provided
							 | 
						|
								  if (afterId) {
							 | 
						|
								    const afterIndex = filteredProjects.findIndex(p => p.planSummary.jwtId === afterId);
							 | 
						|
								    if (afterIndex >= 0) {
							 | 
						|
								      filteredProjects = filteredProjects.slice(afterIndex + 1);
							 | 
						|
								      console.log(`   Filtered to ${filteredProjects.length} projects after ${afterId}`);
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // Generate response
							 | 
						|
								  const response = {
							 | 
						|
								    data: filteredProjects,
							 | 
						|
								    hitLimit: false,
							 | 
						|
								    pagination: {
							 | 
						|
								      hasMore: false,
							 | 
						|
								      nextAfterId: filteredProjects.length > 0
							 | 
						|
								        ? filteredProjects[filteredProjects.length - 1].planSummary.jwtId
							 | 
						|
								        : null
							 | 
						|
								    }
							 | 
						|
								  };
							 | 
						|
								
							 | 
						|
								  console.log(`📤 Sending ${response.data.length} projects in response`);
							 | 
						|
								
							 | 
						|
								  res.json(response);
							 | 
						|
								});
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * GET /api/test/projects
							 | 
						|
								 * 
							 | 
						|
								 * View all seeded projects (for debugging)
							 | 
						|
								 */
							 | 
						|
								app.get('/api/test/projects', (req, res) => {
							 | 
						|
								  res.json({
							 | 
						|
								    projects: seededProjects,
							 | 
						|
								    count: seededProjects.length,
							 | 
						|
								    timestamp: new Date().toISOString()
							 | 
						|
								  });
							 | 
						|
								});
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * POST /api/test/seed-projects
							 | 
						|
								 * 
							 | 
						|
								 * Reseed test projects (useful for resetting)
							 | 
						|
								 */
							 | 
						|
								app.post('/api/test/seed-projects', (req, res) => {
							 | 
						|
								  const { projectIds } = req.body;
							 | 
						|
								  const idsToUse = projectIds || DEFAULT_TEST_PROJECT_IDS;
							 | 
						|
								  
							 | 
						|
								  seedProjects(idsToUse);
							 | 
						|
								  
							 | 
						|
								  res.json({
							 | 
						|
								    success: true,
							 | 
						|
								    message: `Seeded ${seededProjects.length} test projects`,
							 | 
						|
								    count: seededProjects.length,
							 | 
						|
								    projectIds: idsToUse
							 | 
						|
								  });
							 | 
						|
								});
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * GET /api/test/health
							 | 
						|
								 * 
							 | 
						|
								 * Health check endpoint
							 | 
						|
								 */
							 | 
						|
								app.get('/api/test/health', (req, res) => {
							 | 
						|
								  res.json({
							 | 
						|
								    status: 'ok',
							 | 
						|
								    server: 'test-api-server-with-seed',
							 | 
						|
								    port: PORT,
							 | 
						|
								    projectsSeeded: seededProjects.length,
							 | 
						|
								    timestamp: new Date().toISOString()
							 | 
						|
								  });
							 | 
						|
								});
							 | 
						|
								
							 | 
						|
								// Start server
							 | 
						|
								// Allow plan IDs to be passed as command line argument
							 | 
						|
								const planIdsArg = process.argv[3];
							 | 
						|
								const planIdsToUse = planIdsArg ? planIdsArg.split(',') : DEFAULT_TEST_PROJECT_IDS;
							 | 
						|
								
							 | 
						|
								seedProjects(planIdsToUse); // Seed on startup
							 | 
						|
								
							 | 
						|
								app.listen(PORT, () => {
							 | 
						|
								  console.log('');
							 | 
						|
								  console.log('🧪 Test API Server with Project Seeding');
							 | 
						|
								  console.log('========================================');
							 | 
						|
								  console.log(`📡 Server running on http://localhost:${PORT}`);
							 | 
						|
								  console.log(`📱 Android emulator URL: http://10.0.2.2:${PORT}`);
							 | 
						|
								  console.log('');
							 | 
						|
								  console.log('Endpoints:');
							 | 
						|
								  console.log(`  POST /api/v2/report/plansLastUpdatedBetween - Main prefetch endpoint`);
							 | 
						|
								  console.log(`  GET  /api/test/projects - View all seeded projects`);
							 | 
						|
								  console.log(`  POST /api/test/seed-projects - Reseed projects`);
							 | 
						|
								  console.log(`  GET  /api/test/health - Health check`);
							 | 
						|
								  console.log('');
							 | 
						|
								  console.log('✅ Ready for prefetch testing!');
							 | 
						|
								  console.log('');
							 | 
						|
								});
							 | 
						|
								
							 | 
						|
								// Handle graceful shutdown
							 | 
						|
								process.on('SIGINT', () => {
							 | 
						|
								  console.log('\n👋 Shutting down test API server...');
							 | 
						|
								  process.exit(0);
							 | 
						|
								});
							 | 
						|
								
							 | 
						|
								
							 |