decharge-scout 4.6.0 โ 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard/api/agentone/fleet-submit.js +112 -0
- package/dashboard/lib/schema.sql +36 -0
- package/dashboard/vercel.json +4 -0
- package/debug-fleet-api.js +109 -0
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/fleet.js +2 -0
- package/test-api.js +2 -2
- package/test-both-apis.js +225 -0
- package/test-live-apis.js +133 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel API Endpoint - Fleet Data Submission
|
|
3
|
+
*
|
|
4
|
+
* POST /api/agentone/fleet-submit
|
|
5
|
+
* Receives fleet optimization data and stores it in Supabase
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createClient } from '@supabase/supabase-js';
|
|
9
|
+
|
|
10
|
+
export const config = {
|
|
11
|
+
runtime: 'edge',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default async function handler(req) {
|
|
15
|
+
// CORS headers
|
|
16
|
+
const headers = {
|
|
17
|
+
'Access-Control-Allow-Origin': '*',
|
|
18
|
+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
19
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Handle OPTIONS request for CORS
|
|
24
|
+
if (req.method === 'OPTIONS') {
|
|
25
|
+
return new Response(null, { status: 200, headers });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Only allow POST
|
|
29
|
+
if (req.method !== 'POST') {
|
|
30
|
+
return new Response(
|
|
31
|
+
JSON.stringify({ error: 'Method not allowed' }),
|
|
32
|
+
{ status: 405, headers }
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const data = await req.json();
|
|
38
|
+
|
|
39
|
+
// Validate required fields for fleet submissions
|
|
40
|
+
if (!data.type || data.type !== 'fleet') {
|
|
41
|
+
return new Response(
|
|
42
|
+
JSON.stringify({ error: 'Invalid submission type. Expected "fleet"' }),
|
|
43
|
+
{ status: 400, headers }
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!data.agent_name || !data.location || !data.timestamp || !data.fleet_size || !data.summary) {
|
|
48
|
+
return new Response(
|
|
49
|
+
JSON.stringify({ error: 'Missing required fields for fleet submission' }),
|
|
50
|
+
{ status: 400, headers }
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Initialize Supabase client
|
|
55
|
+
const supabase = createClient(
|
|
56
|
+
process.env.SUPABASE_URL,
|
|
57
|
+
process.env.SUPABASE_ANON_KEY
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Insert fleet submission
|
|
61
|
+
const { error: fleetError } = await supabase
|
|
62
|
+
.from('fleet_submissions')
|
|
63
|
+
.insert({
|
|
64
|
+
agent_name: data.agent_name,
|
|
65
|
+
wallet: data.wallet,
|
|
66
|
+
location: data.location,
|
|
67
|
+
timestamp: new Date(data.timestamp).toISOString(),
|
|
68
|
+
fleet_size: data.fleet_size,
|
|
69
|
+
total_distance_km: data.summary.total_distance_km,
|
|
70
|
+
total_cost_usd: data.summary.total_cost_usd,
|
|
71
|
+
savings_percent: data.summary.savings_percent,
|
|
72
|
+
co2_saved_kg: data.summary.co2_saved_kg,
|
|
73
|
+
duration_hours: data.summary.duration_hours,
|
|
74
|
+
route_geojson: data.route,
|
|
75
|
+
stops: data.stops,
|
|
76
|
+
simulation_basis: data.simulation_basis || 'weather-based simulation',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
if (fleetError) throw fleetError;
|
|
80
|
+
|
|
81
|
+
// Update agent heartbeat (upsert)
|
|
82
|
+
const { error: heartbeatError } = await supabase
|
|
83
|
+
.from('agent_heartbeat')
|
|
84
|
+
.upsert(
|
|
85
|
+
{
|
|
86
|
+
agent_name: data.agent_name,
|
|
87
|
+
location: data.location,
|
|
88
|
+
last_seen: new Date().toISOString(),
|
|
89
|
+
},
|
|
90
|
+
{ onConflict: 'agent_name' }
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (heartbeatError) throw heartbeatError;
|
|
94
|
+
|
|
95
|
+
return new Response(
|
|
96
|
+
JSON.stringify({
|
|
97
|
+
success: true,
|
|
98
|
+
message: 'Fleet data submitted successfully',
|
|
99
|
+
}),
|
|
100
|
+
{ status: 200, headers }
|
|
101
|
+
);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error('Fleet submission error:', error);
|
|
104
|
+
return new Response(
|
|
105
|
+
JSON.stringify({
|
|
106
|
+
error: 'Internal server error',
|
|
107
|
+
message: error.message,
|
|
108
|
+
}),
|
|
109
|
+
{ status: 500, headers }
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
package/dashboard/lib/schema.sql
CHANGED
|
@@ -65,3 +65,39 @@ FROM agent_submissions
|
|
|
65
65
|
WHERE created_at > NOW() - INTERVAL '24 hours'
|
|
66
66
|
GROUP BY DATE_TRUNC('hour', created_at)
|
|
67
67
|
ORDER BY hour DESC;
|
|
68
|
+
|
|
69
|
+
-- Table: fleet_submissions
|
|
70
|
+
-- Stores fleet optimization submissions
|
|
71
|
+
CREATE TABLE IF NOT EXISTS fleet_submissions (
|
|
72
|
+
id SERIAL PRIMARY KEY,
|
|
73
|
+
agent_name VARCHAR(255) NOT NULL,
|
|
74
|
+
wallet VARCHAR(255),
|
|
75
|
+
location VARCHAR(255) NOT NULL,
|
|
76
|
+
timestamp TIMESTAMP NOT NULL,
|
|
77
|
+
fleet_size INTEGER NOT NULL,
|
|
78
|
+
total_distance_km INTEGER NOT NULL,
|
|
79
|
+
total_cost_usd DECIMAL(10, 2) NOT NULL,
|
|
80
|
+
savings_percent INTEGER NOT NULL,
|
|
81
|
+
co2_saved_kg INTEGER NOT NULL,
|
|
82
|
+
duration_hours INTEGER NOT NULL,
|
|
83
|
+
route_geojson JSONB,
|
|
84
|
+
stops JSONB,
|
|
85
|
+
simulation_basis VARCHAR(255),
|
|
86
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
-- Indexes for fleet queries
|
|
90
|
+
CREATE INDEX idx_fleet_created_at ON fleet_submissions(created_at DESC);
|
|
91
|
+
CREATE INDEX idx_fleet_agent ON fleet_submissions(agent_name);
|
|
92
|
+
CREATE INDEX idx_fleet_location ON fleet_submissions(location);
|
|
93
|
+
|
|
94
|
+
-- View: Fleet stats (last 24h)
|
|
95
|
+
CREATE OR REPLACE VIEW fleet_stats_daily AS
|
|
96
|
+
SELECT
|
|
97
|
+
COUNT(*) as total_fleets,
|
|
98
|
+
SUM(fleet_size) as total_vehicles,
|
|
99
|
+
SUM(total_distance_km) as total_distance,
|
|
100
|
+
AVG(savings_percent) as avg_savings,
|
|
101
|
+
SUM(co2_saved_kg) as total_co2_saved
|
|
102
|
+
FROM fleet_submissions
|
|
103
|
+
WHERE created_at > NOW() - INTERVAL '24 hours';
|
package/dashboard/vercel.json
CHANGED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Debug Fleet API Call
|
|
5
|
+
*
|
|
6
|
+
* This script simulates what fleet.js sends to help debug why data isn't saving
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fetch from 'node-fetch';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
|
|
12
|
+
const API_URL = 'https://decharge-scout.vercel.app/api/agentone/fleet-submit';
|
|
13
|
+
|
|
14
|
+
// Simulate the exact payload fleet.js sends
|
|
15
|
+
const testPayload = {
|
|
16
|
+
type: 'fleet',
|
|
17
|
+
agent_name: 'DebugAgent-' + Date.now(),
|
|
18
|
+
wallet: 'TestWallet123',
|
|
19
|
+
location: 'New York โ Boston',
|
|
20
|
+
timestamp: Date.now(),
|
|
21
|
+
fleet_size: 10,
|
|
22
|
+
route: {
|
|
23
|
+
type: 'LineString',
|
|
24
|
+
coordinates: [
|
|
25
|
+
[-74.0060, 40.7128], // New York
|
|
26
|
+
[-71.0589, 42.3601] // Boston
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
stops: [
|
|
30
|
+
{
|
|
31
|
+
lat: 41.5,
|
|
32
|
+
lon: -72.5,
|
|
33
|
+
time: '3AM-4AM',
|
|
34
|
+
price: 0.025,
|
|
35
|
+
savings: 80,
|
|
36
|
+
location: 'Hartford, CT',
|
|
37
|
+
segmentId: 1
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
summary: {
|
|
41
|
+
total_distance_km: 350,
|
|
42
|
+
total_cost_usd: 150.00,
|
|
43
|
+
savings_percent: 78,
|
|
44
|
+
co2_saved_kg: 45,
|
|
45
|
+
duration_hours: 4
|
|
46
|
+
},
|
|
47
|
+
simulation_basis: 'Task1 simulation + OSRM routing'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
console.log(chalk.cyan('\n๐ Fleet API Debug Tool\n'));
|
|
51
|
+
console.log(chalk.blue('Testing endpoint:', API_URL));
|
|
52
|
+
console.log(chalk.gray('\nPayload being sent:'));
|
|
53
|
+
console.log(chalk.gray(JSON.stringify(testPayload, null, 2)));
|
|
54
|
+
console.log(chalk.gray('\n' + '='.repeat(60) + '\n'));
|
|
55
|
+
|
|
56
|
+
async function testAPI() {
|
|
57
|
+
try {
|
|
58
|
+
console.log(chalk.yellow('โณ Sending request...'));
|
|
59
|
+
|
|
60
|
+
const response = await fetch(API_URL, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: {
|
|
63
|
+
'Content-Type': 'application/json'
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify(testPayload)
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
console.log(chalk.blue(`\n๐ก Response Status: ${response.status} ${response.statusText}`));
|
|
69
|
+
|
|
70
|
+
const responseText = await response.text();
|
|
71
|
+
console.log(chalk.blue('๐ Response Body:'));
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const responseJson = JSON.parse(responseText);
|
|
75
|
+
console.log(chalk.white(JSON.stringify(responseJson, null, 2)));
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.log(chalk.white(responseText));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (response.ok) {
|
|
81
|
+
console.log(chalk.green('\nโ
SUCCESS! Data should be in Supabase now.'));
|
|
82
|
+
console.log(chalk.gray('Check the fleet_submissions table in Supabase.'));
|
|
83
|
+
} else {
|
|
84
|
+
console.log(chalk.red('\nโ FAILED! API rejected the request.'));
|
|
85
|
+
console.log(chalk.yellow('\nCommon issues:'));
|
|
86
|
+
console.log(chalk.gray('- 404: API endpoint not deployed to Vercel'));
|
|
87
|
+
console.log(chalk.gray('- 400: Validation error (check response body above)'));
|
|
88
|
+
console.log(chalk.gray('- 500: Server error (table missing, env vars, etc.)'));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Show headers for debugging
|
|
92
|
+
console.log(chalk.gray('\n๐ Response Headers:'));
|
|
93
|
+
response.headers.forEach((value, key) => {
|
|
94
|
+
console.log(chalk.gray(` ${key}: ${value}`));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.log(chalk.red('\nโ Network Error!'));
|
|
99
|
+
console.log(chalk.red('Error:', error.message));
|
|
100
|
+
console.log(chalk.yellow('\nThis usually means:'));
|
|
101
|
+
console.log(chalk.gray('- No internet connection'));
|
|
102
|
+
console.log(chalk.gray('- DNS resolution failed'));
|
|
103
|
+
console.log(chalk.gray('- Vercel deployment not accessible'));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
testAPI().then(() => {
|
|
108
|
+
console.log(chalk.gray('\n' + '='.repeat(60) + '\n'));
|
|
109
|
+
});
|
package/index.js
CHANGED
|
@@ -511,7 +511,7 @@ async function runQueryCycle(wallet, agentName, location, options) {
|
|
|
511
511
|
// Submit to DeCharge Scout dashboard
|
|
512
512
|
try {
|
|
513
513
|
const dashboardSpinner = ora('Submitting to DeCharge Scout dashboard...').start();
|
|
514
|
-
const apiUrl = 'https://decharge-scout.vercel.app/api/
|
|
514
|
+
const apiUrl = 'https://decharge-scout.vercel.app/api/submit';
|
|
515
515
|
|
|
516
516
|
console.log(chalk.blue(`\n๐ Dashboard API URL: ${apiUrl}`));
|
|
517
517
|
console.log(chalk.gray(`๐ค Submitting data...`));
|
package/package.json
CHANGED
package/src/fleet.js
CHANGED
|
@@ -404,7 +404,9 @@ export async function runFleetOptimization(options) {
|
|
|
404
404
|
console.log(chalk.cyan('\n๐บ๏ธ Your fleet optimization has been added as a new layer on the AgentOne global map!'));
|
|
405
405
|
console.log(chalk.blue(' View at: https://decharge-scout.vercel.app/agentone\n'));
|
|
406
406
|
} else {
|
|
407
|
+
const errorBody = await response.text();
|
|
407
408
|
dashboardSpinner.warn(chalk.yellow(`โ ๏ธ Dashboard API returned: ${response.status}`));
|
|
409
|
+
console.log(chalk.red(` Error details: ${errorBody}`));
|
|
408
410
|
}
|
|
409
411
|
} catch (error) {
|
|
410
412
|
console.log(chalk.yellow(`โ ๏ธ Dashboard submission failed: ${error.message}`));
|
package/test-api.js
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
import fetch from 'node-fetch';
|
|
11
11
|
import chalk from 'chalk';
|
|
12
12
|
|
|
13
|
-
const DASHBOARD_API_URL = 'https://decharge-scout.vercel.app/
|
|
14
|
-
const STATS_API_URL = 'https://decharge-scout.vercel.app/
|
|
13
|
+
const DASHBOARD_API_URL = 'https://decharge-scout.vercel.app/api/submit';
|
|
14
|
+
const STATS_API_URL = 'https://decharge-scout.vercel.app/api/stats';
|
|
15
15
|
|
|
16
16
|
// Sample test data
|
|
17
17
|
const testData = {
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Comprehensive API Test Script
|
|
5
|
+
*
|
|
6
|
+
* Tests both regular submit and fleet-submit endpoints
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fetch from 'node-fetch';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
|
|
12
|
+
const SUBMIT_API_URL = 'https://decharge-scout.vercel.app/api/submit';
|
|
13
|
+
const FLEET_SUBMIT_API_URL = 'https://decharge-scout.vercel.app/api/agentone/fleet-submit';
|
|
14
|
+
const STATS_API_URL = 'https://decharge-scout.vercel.app/api/stats';
|
|
15
|
+
|
|
16
|
+
// Sample regular submission data
|
|
17
|
+
const regularSubmissionData = {
|
|
18
|
+
agent_name: `TestAgent-${Math.random().toString(36).substring(7).toUpperCase()}`,
|
|
19
|
+
location: 'Test City, TX, US',
|
|
20
|
+
timestamp: Date.now(),
|
|
21
|
+
results: {
|
|
22
|
+
cheapest_window: '2AM-3AM',
|
|
23
|
+
price: 0.0299,
|
|
24
|
+
savings: 75.5,
|
|
25
|
+
data_points: 24
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Sample fleet submission data
|
|
30
|
+
const fleetSubmissionData = {
|
|
31
|
+
type: 'fleet',
|
|
32
|
+
agent_name: `FleetAgent-${Math.random().toString(36).substring(7).toUpperCase()}`,
|
|
33
|
+
wallet: 'TestWallet123',
|
|
34
|
+
location: 'New York โ Boston',
|
|
35
|
+
timestamp: Date.now(),
|
|
36
|
+
fleet_size: 10,
|
|
37
|
+
route: {
|
|
38
|
+
type: 'LineString',
|
|
39
|
+
coordinates: [
|
|
40
|
+
[-74.0060, 40.7128], // New York
|
|
41
|
+
[-71.0589, 42.3601] // Boston
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
stops: [
|
|
45
|
+
{
|
|
46
|
+
lat: 41.5,
|
|
47
|
+
lon: -72.5,
|
|
48
|
+
time: '3AM-4AM',
|
|
49
|
+
price: 0.025,
|
|
50
|
+
savings: 80,
|
|
51
|
+
location: 'Hartford, CT',
|
|
52
|
+
segmentId: 1
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
summary: {
|
|
56
|
+
total_distance_km: 350,
|
|
57
|
+
total_cost_usd: 150.00,
|
|
58
|
+
savings_percent: 78,
|
|
59
|
+
co2_saved_kg: 45,
|
|
60
|
+
duration_hours: 4
|
|
61
|
+
},
|
|
62
|
+
simulation_basis: 'Test simulation'
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
console.log(chalk.cyan.bold('\n๐งช Comprehensive API Test Suite\n'));
|
|
66
|
+
console.log(chalk.gray('=' .repeat(60)));
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Test 1: Regular Submit Endpoint
|
|
70
|
+
*/
|
|
71
|
+
async function testRegularSubmit() {
|
|
72
|
+
console.log(chalk.blue('\n๐ TEST 1: Regular Submit Endpoint'));
|
|
73
|
+
console.log(chalk.gray(` URL: ${SUBMIT_API_URL}`));
|
|
74
|
+
console.log(chalk.gray(` Agent: ${regularSubmissionData.agent_name}`));
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const response = await fetch(SUBMIT_API_URL, {
|
|
78
|
+
method: 'POST',
|
|
79
|
+
headers: {
|
|
80
|
+
'Content-Type': 'application/json',
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify(regularSubmissionData)
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const responseText = await response.text();
|
|
86
|
+
|
|
87
|
+
console.log(chalk.blue(`\n ๐ฅ Status: ${response.status}`));
|
|
88
|
+
console.log(chalk.blue(` ๐ฅ Response: ${responseText}`));
|
|
89
|
+
|
|
90
|
+
if (response.ok) {
|
|
91
|
+
console.log(chalk.green('\n โ
Regular submit: PASS'));
|
|
92
|
+
return { success: true, agent: regularSubmissionData.agent_name };
|
|
93
|
+
} else {
|
|
94
|
+
console.log(chalk.red('\n โ Regular submit: FAIL'));
|
|
95
|
+
return { success: false, error: responseText };
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.log(chalk.red(`\n โ Error: ${error.message}`));
|
|
99
|
+
return { success: false, error: error.message };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Test 2: Fleet Submit Endpoint
|
|
105
|
+
*/
|
|
106
|
+
async function testFleetSubmit() {
|
|
107
|
+
console.log(chalk.blue('\n\n๐ TEST 2: Fleet Submit Endpoint'));
|
|
108
|
+
console.log(chalk.gray(` URL: ${FLEET_SUBMIT_API_URL}`));
|
|
109
|
+
console.log(chalk.gray(` Agent: ${fleetSubmissionData.agent_name}`));
|
|
110
|
+
console.log(chalk.gray(` Fleet size: ${fleetSubmissionData.fleet_size} EVs`));
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const response = await fetch(FLEET_SUBMIT_API_URL, {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
headers: {
|
|
116
|
+
'Content-Type': 'application/json',
|
|
117
|
+
},
|
|
118
|
+
body: JSON.stringify(fleetSubmissionData)
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const responseText = await response.text();
|
|
122
|
+
|
|
123
|
+
console.log(chalk.blue(`\n ๐ฅ Status: ${response.status}`));
|
|
124
|
+
console.log(chalk.blue(` ๐ฅ Response: ${responseText}`));
|
|
125
|
+
|
|
126
|
+
if (response.ok) {
|
|
127
|
+
console.log(chalk.green('\n โ
Fleet submit: PASS'));
|
|
128
|
+
return { success: true, agent: fleetSubmissionData.agent_name };
|
|
129
|
+
} else {
|
|
130
|
+
console.log(chalk.red('\n โ Fleet submit: FAIL'));
|
|
131
|
+
return { success: false, error: responseText };
|
|
132
|
+
}
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.log(chalk.red(`\n โ Error: ${error.message}`));
|
|
135
|
+
return { success: false, error: error.message };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Test 3: Stats Endpoint
|
|
141
|
+
*/
|
|
142
|
+
async function testStats() {
|
|
143
|
+
console.log(chalk.blue('\n\n๐ TEST 3: Stats Endpoint'));
|
|
144
|
+
console.log(chalk.gray(` URL: ${STATS_API_URL}`));
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
const response = await fetch(STATS_API_URL);
|
|
148
|
+
const data = await response.json();
|
|
149
|
+
|
|
150
|
+
console.log(chalk.blue(`\n ๐ฅ Status: ${response.status}`));
|
|
151
|
+
|
|
152
|
+
if (response.ok) {
|
|
153
|
+
console.log(chalk.green('\n โ
Stats endpoint: PASS'));
|
|
154
|
+
console.log(chalk.magenta(` ๐ Active Agents: ${data.activeAgents}`));
|
|
155
|
+
console.log(chalk.magenta(` ๐ Total Submissions: ${data.totalSubmissions}`));
|
|
156
|
+
console.log(chalk.magenta(` ๐ Locations tracked: ${data.locations?.length || 0}`));
|
|
157
|
+
return { success: true, data };
|
|
158
|
+
} else {
|
|
159
|
+
console.log(chalk.red('\n โ Stats endpoint: FAIL'));
|
|
160
|
+
return { success: false, error: await response.text() };
|
|
161
|
+
}
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.log(chalk.red(`\n โ Error: ${error.message}`));
|
|
164
|
+
return { success: false, error: error.message };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Main test runner
|
|
170
|
+
*/
|
|
171
|
+
async function main() {
|
|
172
|
+
console.log(chalk.yellow('\n๐ Starting comprehensive API tests...\n'));
|
|
173
|
+
|
|
174
|
+
// Run all tests
|
|
175
|
+
const regularResult = await testRegularSubmit();
|
|
176
|
+
await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds
|
|
177
|
+
|
|
178
|
+
const fleetResult = await testFleetSubmit();
|
|
179
|
+
await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds
|
|
180
|
+
|
|
181
|
+
const statsResult = await testStats();
|
|
182
|
+
|
|
183
|
+
// Summary
|
|
184
|
+
console.log(chalk.gray('\n' + '=' .repeat(60)));
|
|
185
|
+
console.log(chalk.cyan.bold('\n๐ Test Summary:\n'));
|
|
186
|
+
|
|
187
|
+
console.log(regularResult.success
|
|
188
|
+
? chalk.green(' โ
Regular submit endpoint: PASS')
|
|
189
|
+
: chalk.red(' โ Regular submit endpoint: FAIL'));
|
|
190
|
+
|
|
191
|
+
console.log(fleetResult.success
|
|
192
|
+
? chalk.green(' โ
Fleet submit endpoint: PASS')
|
|
193
|
+
: chalk.red(' โ Fleet submit endpoint: FAIL'));
|
|
194
|
+
|
|
195
|
+
console.log(statsResult.success
|
|
196
|
+
? chalk.green(' โ
Stats endpoint: PASS')
|
|
197
|
+
: chalk.red(' โ Stats endpoint: FAIL'));
|
|
198
|
+
|
|
199
|
+
const allPassed = regularResult.success && fleetResult.success && statsResult.success;
|
|
200
|
+
|
|
201
|
+
if (allPassed) {
|
|
202
|
+
console.log(chalk.green.bold('\n๐ All tests passed! Both endpoints are working!\n'));
|
|
203
|
+
console.log(chalk.blue(' ๐ View dashboard: https://decharge-scout.vercel.app/agentone\n'));
|
|
204
|
+
console.log(chalk.yellow(' ๐ Check Supabase for:'));
|
|
205
|
+
console.log(chalk.gray(` - Regular submission: ${regularResult.agent}`));
|
|
206
|
+
console.log(chalk.gray(` - Fleet submission: ${fleetResult.agent}\n`));
|
|
207
|
+
} else {
|
|
208
|
+
console.log(chalk.red.bold('\nโ ๏ธ Some tests failed. Check errors above.\n'));
|
|
209
|
+
|
|
210
|
+
if (!regularResult.success || !fleetResult.success) {
|
|
211
|
+
console.log(chalk.yellow(' Common issues:'));
|
|
212
|
+
console.log(chalk.gray(' 1. Supabase tables not created (run schema.sql)'));
|
|
213
|
+
console.log(chalk.gray(' 2. Missing Vercel environment variables'));
|
|
214
|
+
console.log(chalk.gray(' 3. Need to redeploy Vercel after changes'));
|
|
215
|
+
console.log(chalk.gray(' 4. Check Vercel logs: vercel logs\n'));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.log(chalk.gray('=' .repeat(60) + '\n'));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
main().catch(error => {
|
|
223
|
+
console.error(chalk.red('Fatal error:'), error);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Simple Live API Test - Hit both endpoints
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import https from 'https';
|
|
8
|
+
|
|
9
|
+
const SUBMIT_API = 'https://decharge-scout.vercel.app/api/submit';
|
|
10
|
+
const FLEET_API = 'https://decharge-scout.vercel.app/api/agentone/fleet-submit';
|
|
11
|
+
|
|
12
|
+
// Test data for regular submit
|
|
13
|
+
const regularData = {
|
|
14
|
+
agent_name: `TestAgent-${Date.now()}`,
|
|
15
|
+
location: 'Test City, TX, US',
|
|
16
|
+
timestamp: Date.now(),
|
|
17
|
+
results: {
|
|
18
|
+
cheapest_window: '2AM-3AM',
|
|
19
|
+
price: 0.0299,
|
|
20
|
+
savings: 75.5,
|
|
21
|
+
data_points: 24
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Test data for fleet submit
|
|
26
|
+
const fleetData = {
|
|
27
|
+
type: 'fleet',
|
|
28
|
+
agent_name: `FleetAgent-${Date.now()}`,
|
|
29
|
+
wallet: 'TestWallet123',
|
|
30
|
+
location: 'New York โ Boston',
|
|
31
|
+
timestamp: Date.now(),
|
|
32
|
+
fleet_size: 10,
|
|
33
|
+
route: {
|
|
34
|
+
type: 'LineString',
|
|
35
|
+
coordinates: [[-74.0060, 40.7128], [-71.0589, 42.3601]]
|
|
36
|
+
},
|
|
37
|
+
stops: [{
|
|
38
|
+
lat: 41.5,
|
|
39
|
+
lon: -72.5,
|
|
40
|
+
time: '3AM-4AM',
|
|
41
|
+
price: 0.025,
|
|
42
|
+
savings: 80,
|
|
43
|
+
location: 'Hartford, CT',
|
|
44
|
+
segmentId: 1
|
|
45
|
+
}],
|
|
46
|
+
summary: {
|
|
47
|
+
total_distance_km: 350,
|
|
48
|
+
total_cost_usd: 150.00,
|
|
49
|
+
savings_percent: 78,
|
|
50
|
+
co2_saved_kg: 45,
|
|
51
|
+
duration_hours: 4
|
|
52
|
+
},
|
|
53
|
+
simulation_basis: 'Test simulation'
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
function hitAPI(url, data, name) {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
const urlObj = new URL(url);
|
|
59
|
+
const postData = JSON.stringify(data);
|
|
60
|
+
|
|
61
|
+
const options = {
|
|
62
|
+
hostname: urlObj.hostname,
|
|
63
|
+
path: urlObj.pathname,
|
|
64
|
+
method: 'POST',
|
|
65
|
+
headers: {
|
|
66
|
+
'Content-Type': 'application/json',
|
|
67
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
console.log(`\n๐ต Testing ${name}...`);
|
|
72
|
+
console.log(` URL: ${url}`);
|
|
73
|
+
console.log(` Data: ${JSON.stringify(data, null, 2).substring(0, 200)}...`);
|
|
74
|
+
|
|
75
|
+
const req = https.request(options, (res) => {
|
|
76
|
+
let body = '';
|
|
77
|
+
res.on('data', (chunk) => body += chunk);
|
|
78
|
+
res.on('end', () => {
|
|
79
|
+
console.log(`\n Status: ${res.statusCode}`);
|
|
80
|
+
console.log(` Response: ${body}`);
|
|
81
|
+
|
|
82
|
+
if (res.statusCode === 200 || res.statusCode === 201) {
|
|
83
|
+
console.log(` โ
${name} PASSED`);
|
|
84
|
+
resolve({ success: true, status: res.statusCode, body });
|
|
85
|
+
} else {
|
|
86
|
+
console.log(` โ ${name} FAILED`);
|
|
87
|
+
resolve({ success: false, status: res.statusCode, body });
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
req.on('error', (error) => {
|
|
93
|
+
console.log(` โ ${name} ERROR: ${error.message}`);
|
|
94
|
+
reject(error);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
req.write(postData);
|
|
98
|
+
req.end();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function main() {
|
|
103
|
+
console.log('๐งช Testing Both APIs\n');
|
|
104
|
+
console.log('='.repeat(60));
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
// Test 1: Regular Submit
|
|
108
|
+
const regularResult = await hitAPI(SUBMIT_API, regularData, 'Regular Submit API');
|
|
109
|
+
|
|
110
|
+
// Wait 2 seconds
|
|
111
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
112
|
+
|
|
113
|
+
// Test 2: Fleet Submit
|
|
114
|
+
const fleetResult = await hitAPI(FLEET_API, fleetData, 'Fleet Submit API');
|
|
115
|
+
|
|
116
|
+
// Summary
|
|
117
|
+
console.log('\n' + '='.repeat(60));
|
|
118
|
+
console.log('\n๐ RESULTS:\n');
|
|
119
|
+
console.log(regularResult.success ? 'โ
Regular Submit: WORKING' : 'โ Regular Submit: FAILED');
|
|
120
|
+
console.log(fleetResult.success ? 'โ
Fleet Submit: WORKING' : 'โ Fleet Submit: FAILED');
|
|
121
|
+
|
|
122
|
+
if (regularResult.success && fleetResult.success) {
|
|
123
|
+
console.log('\n๐ Both APIs are working correctly!\n');
|
|
124
|
+
} else {
|
|
125
|
+
console.log('\nโ ๏ธ Some APIs failed - check errors above\n');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error('\nโ Fatal error:', error.message);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
main();
|