mirror of
https://github.com/vega-org/vega-providers.git
synced 2026-04-17 15:41:45 +00:00
feat: add auto-dev environment with build and server functionality
This commit is contained in:
220
auto-dev.js
Normal file
220
auto-dev.js
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const { spawn } = require("child_process");
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
// Colors for console output
|
||||||
|
const colors = {
|
||||||
|
reset: "\x1b[0m",
|
||||||
|
bright: "\x1b[1m",
|
||||||
|
green: "\x1b[32m",
|
||||||
|
red: "\x1b[31m",
|
||||||
|
yellow: "\x1b[33m",
|
||||||
|
blue: "\x1b[34m",
|
||||||
|
magenta: "\x1b[35m",
|
||||||
|
cyan: "\x1b[36m",
|
||||||
|
};
|
||||||
|
|
||||||
|
const log = {
|
||||||
|
info: (msg) => console.log(`${colors.blue}ℹ${colors.reset} ${msg}`),
|
||||||
|
success: (msg) => console.log(`${colors.green}✅${colors.reset} ${msg}`),
|
||||||
|
error: (msg) => console.log(`${colors.red}❌${colors.reset} ${msg}`),
|
||||||
|
warning: (msg) => console.log(`${colors.yellow}⚠️${colors.reset} ${msg}`),
|
||||||
|
server: (msg) => console.log(`${colors.cyan}🌐${colors.reset} ${msg}`),
|
||||||
|
watch: (msg) => console.log(`${colors.magenta}👀${colors.reset} ${msg}`),
|
||||||
|
};
|
||||||
|
|
||||||
|
class AutoDev {
|
||||||
|
constructor() {
|
||||||
|
this.processes = new Map();
|
||||||
|
this.isShuttingDown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkDependencies() {
|
||||||
|
log.info("Checking dependencies...");
|
||||||
|
|
||||||
|
const requiredPackages = ["nodemon", "concurrently", "express", "cors"];
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync("package.json", "utf8"));
|
||||||
|
|
||||||
|
const missing = requiredPackages.filter(
|
||||||
|
(pkg) =>
|
||||||
|
!packageJson.dependencies?.[pkg] && !packageJson.devDependencies?.[pkg]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (missing.length > 0) {
|
||||||
|
log.error(`Missing packages: ${missing.join(", ")}`);
|
||||||
|
log.info("Installing missing packages...");
|
||||||
|
await this.runCommand("npm", ["install", ...missing, "--save-dev"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.success("All dependencies are installed");
|
||||||
|
}
|
||||||
|
|
||||||
|
async runCommand(command, args, options = {}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const child = spawn(command, args, {
|
||||||
|
stdio: "inherit",
|
||||||
|
shell: true,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on("close", (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(new Error(`Command failed with code ${code}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on("error", reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async initialBuild() {
|
||||||
|
log.info("Running initial build...");
|
||||||
|
try {
|
||||||
|
await this.runCommand("node", ["build-simple.js"]);
|
||||||
|
log.success("Initial build completed");
|
||||||
|
} catch (error) {
|
||||||
|
log.error("Initial build failed:", error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startWatcher() {
|
||||||
|
log.watch("Starting file watcher...");
|
||||||
|
|
||||||
|
const watcher = spawn("npx", ["nodemon"], {
|
||||||
|
stdio: ["inherit", "pipe", "pipe"],
|
||||||
|
shell: true,
|
||||||
|
env: { ...process.env, NODE_ENV: "development" },
|
||||||
|
});
|
||||||
|
|
||||||
|
watcher.stdout.on("data", (data) => {
|
||||||
|
const output = data.toString().trim();
|
||||||
|
if (output) {
|
||||||
|
console.log(`${colors.magenta}[WATCH]${colors.reset} ${output}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watcher.stderr.on("data", (data) => {
|
||||||
|
const output = data.toString().trim();
|
||||||
|
if (output) {
|
||||||
|
console.log(`${colors.yellow}[WATCH]${colors.reset} ${output}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watcher.on("close", (code) => {
|
||||||
|
if (!this.isShuttingDown) {
|
||||||
|
log.error(`Watcher exited with code ${code}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.processes.set("watcher", watcher);
|
||||||
|
return watcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
startDevServer() {
|
||||||
|
log.server("Starting development server...");
|
||||||
|
|
||||||
|
const server = spawn("node", ["dev-server.js"], {
|
||||||
|
stdio: ["inherit", "pipe", "pipe"],
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
server.stdout.on("data", (data) => {
|
||||||
|
const output = data.toString().trim();
|
||||||
|
if (output) {
|
||||||
|
console.log(`${colors.cyan}[SERVER]${colors.reset} ${output}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.stderr.on("data", (data) => {
|
||||||
|
const output = data.toString().trim();
|
||||||
|
if (output) {
|
||||||
|
console.log(`${colors.red}[SERVER]${colors.reset} ${output}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("close", (code) => {
|
||||||
|
if (!this.isShuttingDown) {
|
||||||
|
log.error(`Server exited with code ${code}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.processes.set("server", server);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
setupSignalHandlers() {
|
||||||
|
const cleanup = () => {
|
||||||
|
if (this.isShuttingDown) return;
|
||||||
|
this.isShuttingDown = true;
|
||||||
|
|
||||||
|
console.log("\n");
|
||||||
|
log.info("Shutting down auto-dev environment...");
|
||||||
|
|
||||||
|
for (const [name, process] of this.processes) {
|
||||||
|
log.info(`Stopping ${name}...`);
|
||||||
|
process.kill("SIGTERM");
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
log.success("Auto-dev environment stopped");
|
||||||
|
process.exit(0);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
process.on("SIGINT", cleanup);
|
||||||
|
process.on("SIGTERM", cleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
console.log(`
|
||||||
|
${colors.bright}🚀 Vega Providers Auto-Development Environment${colors.reset}
|
||||||
|
|
||||||
|
${colors.cyan}Features:${colors.reset}
|
||||||
|
• 👀 Auto-watch TypeScript files in /providers
|
||||||
|
• 🔨 Auto-rebuild on file changes
|
||||||
|
• 🌐 Development server with hot-reload
|
||||||
|
• 📊 Real-time build feedback
|
||||||
|
|
||||||
|
${colors.yellow}Press Ctrl+C to stop${colors.reset}
|
||||||
|
`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Setup signal handlers
|
||||||
|
this.setupSignalHandlers();
|
||||||
|
|
||||||
|
// Check dependencies
|
||||||
|
await this.checkDependencies();
|
||||||
|
|
||||||
|
// Initial build
|
||||||
|
await this.initialBuild();
|
||||||
|
|
||||||
|
// Start watcher and server
|
||||||
|
this.startWatcher();
|
||||||
|
|
||||||
|
// Wait a bit before starting server
|
||||||
|
setTimeout(() => {
|
||||||
|
this.startDevServer();
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
log.success("Auto-development environment is running!");
|
||||||
|
log.info(
|
||||||
|
"Make changes to your providers and watch them rebuild automatically"
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
log.error("Failed to start auto-dev environment:", error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLI interface
|
||||||
|
if (require.main === module) {
|
||||||
|
const autoDev = new AutoDev();
|
||||||
|
autoDev.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AutoDev;
|
||||||
181
build-simple.js
Normal file
181
build-simple.js
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const { execSync } = require("child_process");
|
||||||
|
|
||||||
|
// Build configuration
|
||||||
|
const PROVIDERS_DIR = "./providers";
|
||||||
|
const DIST_DIR = "./dist";
|
||||||
|
|
||||||
|
// Colors for console output
|
||||||
|
const colors = {
|
||||||
|
reset: "\x1b[0m",
|
||||||
|
bright: "\x1b[1m",
|
||||||
|
green: "\x1b[32m",
|
||||||
|
red: "\x1b[31m",
|
||||||
|
yellow: "\x1b[33m",
|
||||||
|
blue: "\x1b[34m",
|
||||||
|
magenta: "\x1b[35m",
|
||||||
|
cyan: "\x1b[36m",
|
||||||
|
};
|
||||||
|
|
||||||
|
const log = {
|
||||||
|
info: (msg) => console.log(`${colors.blue}ℹ${colors.reset} ${msg}`),
|
||||||
|
success: (msg) => console.log(`${colors.green}✅${colors.reset} ${msg}`),
|
||||||
|
error: (msg) => console.log(`${colors.red}❌${colors.reset} ${msg}`),
|
||||||
|
warning: (msg) => console.log(`${colors.yellow}⚠️${colors.reset} ${msg}`),
|
||||||
|
build: (msg) => console.log(`${colors.magenta}🔨${colors.reset} ${msg}`),
|
||||||
|
file: (msg) => console.log(`${colors.cyan}📄${colors.reset} ${msg}`),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple and efficient provider builder
|
||||||
|
*/
|
||||||
|
class ProviderBuilder {
|
||||||
|
constructor() {
|
||||||
|
this.startTime = Date.now();
|
||||||
|
this.providers = [];
|
||||||
|
this.manifest = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean the dist directory
|
||||||
|
*/
|
||||||
|
cleanDist() {
|
||||||
|
if (fs.existsSync(DIST_DIR)) {
|
||||||
|
fs.rmSync(DIST_DIR, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
fs.mkdirSync(DIST_DIR, { recursive: true });
|
||||||
|
log.success("Cleaned dist directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discover all provider directories
|
||||||
|
*/
|
||||||
|
discoverProviders() {
|
||||||
|
const items = fs.readdirSync(PROVIDERS_DIR, { withFileTypes: true });
|
||||||
|
|
||||||
|
this.providers = items
|
||||||
|
.filter((item) => item.isDirectory())
|
||||||
|
.filter((item) => !item.name.startsWith("."))
|
||||||
|
.map((item) => item.name);
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
`Found ${this.providers.length} providers: ${this.providers.join(", ")}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile all TypeScript files using tsconfig.json
|
||||||
|
*/
|
||||||
|
compileAllProviders() {
|
||||||
|
log.build("Compiling TypeScript files...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use TypeScript to compile all files according to tsconfig.json
|
||||||
|
execSync("npx tsc", {
|
||||||
|
stdio: "pipe",
|
||||||
|
encoding: "utf8",
|
||||||
|
});
|
||||||
|
|
||||||
|
log.success("TypeScript compilation completed");
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
log.error("TypeScript compilation failed:");
|
||||||
|
if (error.stdout) {
|
||||||
|
console.log(error.stdout);
|
||||||
|
}
|
||||||
|
if (error.stderr) {
|
||||||
|
console.log(error.stderr);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Organize compiled files by provider
|
||||||
|
*/
|
||||||
|
organizeFiles() {
|
||||||
|
log.build("Organizing compiled files...");
|
||||||
|
|
||||||
|
for (const provider of this.providers) {
|
||||||
|
const providerSrcDir = path.join(PROVIDERS_DIR, provider);
|
||||||
|
const providerDistDir = path.join(DIST_DIR, provider);
|
||||||
|
|
||||||
|
// Create provider dist directory
|
||||||
|
if (!fs.existsSync(providerDistDir)) {
|
||||||
|
fs.mkdirSync(providerDistDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy compiled JS files
|
||||||
|
const files = [
|
||||||
|
"catalog.js",
|
||||||
|
"posts.js",
|
||||||
|
"meta.js",
|
||||||
|
"stream.js",
|
||||||
|
"episodes.js",
|
||||||
|
];
|
||||||
|
let fileCount = 0;
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const srcFile = path.join(DIST_DIR, provider, file);
|
||||||
|
const destFile = path.join(providerDistDir, file);
|
||||||
|
|
||||||
|
if (fs.existsSync(srcFile)) {
|
||||||
|
// File already in the right place
|
||||||
|
fileCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileCount > 0) {
|
||||||
|
log.success(` ${provider}: ${fileCount} modules ready`);
|
||||||
|
} else {
|
||||||
|
log.warning(` ${provider}: No modules found`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build everything
|
||||||
|
*/
|
||||||
|
build() {
|
||||||
|
const isWatchMode = process.env.NODE_ENV === "development";
|
||||||
|
|
||||||
|
if (isWatchMode) {
|
||||||
|
console.log(
|
||||||
|
`\n${colors.cyan}🔄 Auto-build triggered${
|
||||||
|
colors.reset
|
||||||
|
} ${new Date().toLocaleTimeString()}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`\n${colors.bright}🚀 Starting provider build...${colors.reset}\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cleanDist();
|
||||||
|
this.discoverProviders();
|
||||||
|
|
||||||
|
const compiled = this.compileAllProviders();
|
||||||
|
if (!compiled) {
|
||||||
|
log.error("Build failed due to compilation errors");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.organizeFiles();
|
||||||
|
|
||||||
|
const buildTime = Date.now() - this.startTime;
|
||||||
|
log.success(`Build completed in ${buildTime}ms`);
|
||||||
|
|
||||||
|
if (isWatchMode) {
|
||||||
|
console.log(`${colors.green}👀 Watching for changes...${colors.reset}\n`);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`${colors.bright}✨ Build completed successfully!${colors.reset}\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the build
|
||||||
|
const builder = new ProviderBuilder();
|
||||||
|
builder.build();
|
||||||
178
dev-server.js
Normal file
178
dev-server.js
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
const express = require("express");
|
||||||
|
const cors = require("cors");
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
const { execSync } = require("child_process");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local development server for testing providers
|
||||||
|
*/
|
||||||
|
class DevServer {
|
||||||
|
constructor() {
|
||||||
|
this.app = express();
|
||||||
|
this.port = 3001;
|
||||||
|
this.distDir = path.join(__dirname, "dist");
|
||||||
|
|
||||||
|
this.setupMiddleware();
|
||||||
|
this.setupRoutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
setupMiddleware() {
|
||||||
|
// Enable CORS for mobile app
|
||||||
|
this.app.use(
|
||||||
|
cors({
|
||||||
|
origin: "*",
|
||||||
|
methods: ["GET", "POST", "OPTIONS"],
|
||||||
|
allowedHeaders: ["Content-Type", "Authorization"],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Serve static files from dist directory
|
||||||
|
this.app.use("/dist", express.static(this.distDir));
|
||||||
|
|
||||||
|
// JSON parsing
|
||||||
|
this.app.use(express.json());
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
this.app.use((req, res, next) => {
|
||||||
|
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setupRoutes() {
|
||||||
|
// Serve manifest.json
|
||||||
|
this.app.get("/manifest.json", (req, res) => {
|
||||||
|
const manifestPath = path.join(this.distDir, "manifest.json");
|
||||||
|
|
||||||
|
if (fs.existsSync(manifestPath)) {
|
||||||
|
res.sendFile(manifestPath);
|
||||||
|
} else {
|
||||||
|
res.status(404).json({ error: "Manifest not found. Run build first." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Serve individual provider files
|
||||||
|
this.app.get("/dist/:provider/:file", (req, res) => {
|
||||||
|
const { provider, file } = req.params;
|
||||||
|
const filePath = path.join(this.distDir, provider, file);
|
||||||
|
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
res.sendFile(filePath);
|
||||||
|
} else {
|
||||||
|
res.status(404).json({
|
||||||
|
error: `File not found: ${provider}/${file}`,
|
||||||
|
hint: "Make sure to run build first",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build endpoint - trigger rebuild
|
||||||
|
this.app.post("/build", (req, res) => {
|
||||||
|
try {
|
||||||
|
console.log("🔨 Triggering rebuild...");
|
||||||
|
execSync("node build.js", { stdio: "inherit" });
|
||||||
|
res.json({ success: true, message: "Build completed" });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Build failed:", error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Status endpoint
|
||||||
|
this.app.get("/status", (req, res) => {
|
||||||
|
const providers = this.getAvailableProviders();
|
||||||
|
res.json({
|
||||||
|
status: "running",
|
||||||
|
port: this.port,
|
||||||
|
providers: providers.length,
|
||||||
|
providerList: providers,
|
||||||
|
buildTime: this.getBuildTime(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// List available providers
|
||||||
|
this.app.get("/providers", (req, res) => {
|
||||||
|
const providers = this.getAvailableProviders();
|
||||||
|
res.json(providers);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Health check
|
||||||
|
this.app.get("/health", (req, res) => {
|
||||||
|
res.json({ status: "healthy", timestamp: new Date().toISOString() });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 404 handler
|
||||||
|
this.app.use((req, res) => {
|
||||||
|
res.status(404).json({
|
||||||
|
error: "Not found",
|
||||||
|
availableEndpoints: [
|
||||||
|
"GET /manifest.json",
|
||||||
|
"GET /dist/:provider/:file",
|
||||||
|
"POST /build",
|
||||||
|
"GET /status",
|
||||||
|
"GET /providers",
|
||||||
|
"GET /health",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getAvailableProviders() {
|
||||||
|
if (!fs.existsSync(this.distDir)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs
|
||||||
|
.readdirSync(this.distDir, { withFileTypes: true })
|
||||||
|
.filter((item) => item.isDirectory())
|
||||||
|
.map((item) => item.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
getBuildTime() {
|
||||||
|
const manifestPath = path.join(this.distDir, "manifest.json");
|
||||||
|
if (fs.existsSync(manifestPath)) {
|
||||||
|
const stats = fs.statSync(manifestPath);
|
||||||
|
return stats.mtime.toISOString();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.app.listen(this.port, "0.0.0.0", () => {
|
||||||
|
console.log(`
|
||||||
|
🚀 Vega Providers Dev Server Started!
|
||||||
|
|
||||||
|
📡 Server URL: http://localhost:${this.port}
|
||||||
|
📱 Mobile URL: http://<your-ip>:${this.port}
|
||||||
|
|
||||||
|
📋 Available endpoints:
|
||||||
|
• GET /manifest.json - Provider manifest
|
||||||
|
• GET /dist/:provider/:file - Provider modules
|
||||||
|
• POST /build - Trigger rebuild
|
||||||
|
• GET /status - Server status
|
||||||
|
• GET /providers - List providers
|
||||||
|
• GET /health - Health check
|
||||||
|
|
||||||
|
💡 Usage:
|
||||||
|
1. Run 'node build.js' to build providers
|
||||||
|
2. Update vega app to use: http://localhost:${this.port}
|
||||||
|
3. Test your providers!
|
||||||
|
|
||||||
|
🔄 Auto-rebuild: POST to /build to rebuild after changes
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Check if build exists
|
||||||
|
if (!fs.existsSync(this.distDir)) {
|
||||||
|
console.log('\n⚠️ No build found. Run "node build.js" first!\n');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
const server = new DevServer();
|
||||||
|
server.start();
|
||||||
248
test-providers.js
Normal file
248
test-providers.js
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
const axios = require("axios");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider testing utility
|
||||||
|
*/
|
||||||
|
class ProviderTester {
|
||||||
|
constructor(serverUrl = "http://localhost:3001") {
|
||||||
|
this.serverUrl = serverUrl;
|
||||||
|
this.axios = axios.create({
|
||||||
|
baseURL: serverUrl,
|
||||||
|
timeout: 10000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test server connectivity
|
||||||
|
*/
|
||||||
|
async testConnection() {
|
||||||
|
try {
|
||||||
|
const response = await this.axios.get("/health");
|
||||||
|
console.log("✅ Server connection OK");
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ Server connection failed:", error.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test manifest endpoint
|
||||||
|
*/
|
||||||
|
async testManifest() {
|
||||||
|
try {
|
||||||
|
const response = await this.axios.get("/manifest.json");
|
||||||
|
const providers = response.data;
|
||||||
|
|
||||||
|
console.log(`✅ Manifest OK - Found ${providers.length} providers:`);
|
||||||
|
providers.forEach((p) => {
|
||||||
|
console.log(` 📦 ${p.display_name} (${p.value}) v${p.version}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return providers;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ Manifest test failed:", error.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test individual provider modules
|
||||||
|
*/
|
||||||
|
async testProvider(providerName) {
|
||||||
|
console.log(`\n🧪 Testing provider: ${providerName}`);
|
||||||
|
|
||||||
|
const modules = ["catalog", "posts", "meta", "stream", "episodes"];
|
||||||
|
const results = {};
|
||||||
|
|
||||||
|
for (const module of modules) {
|
||||||
|
try {
|
||||||
|
const response = await this.axios.get(
|
||||||
|
`/dist/${providerName}/${module}.js`
|
||||||
|
);
|
||||||
|
results[module] = {
|
||||||
|
success: true,
|
||||||
|
size: response.data.length,
|
||||||
|
hasExports: response.data.includes("exports."),
|
||||||
|
};
|
||||||
|
console.log(` ✅ ${module}.js (${results[module].size} bytes)`);
|
||||||
|
} catch (error) {
|
||||||
|
results[module] = {
|
||||||
|
success: false,
|
||||||
|
error: error.response?.status === 404 ? "Not found" : error.message,
|
||||||
|
};
|
||||||
|
const isOptional = module === "episodes";
|
||||||
|
const icon = isOptional ? "⚠️ " : "❌";
|
||||||
|
console.log(
|
||||||
|
` ${icon} ${module}.js - ${results[module].error}${
|
||||||
|
isOptional ? " (optional)" : ""
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test all providers
|
||||||
|
*/
|
||||||
|
async testAllProviders() {
|
||||||
|
console.log("🚀 Starting comprehensive provider test...\n");
|
||||||
|
|
||||||
|
// Test connection
|
||||||
|
const connected = await this.testConnection();
|
||||||
|
if (!connected) return;
|
||||||
|
|
||||||
|
// Test manifest
|
||||||
|
const providers = await this.testManifest();
|
||||||
|
if (!providers) return;
|
||||||
|
|
||||||
|
// Test each provider
|
||||||
|
const results = {};
|
||||||
|
for (const provider of providers) {
|
||||||
|
results[provider.value] = await this.testProvider(provider.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Summary
|
||||||
|
console.log("\n📊 Test Summary:");
|
||||||
|
console.log("=".repeat(50));
|
||||||
|
|
||||||
|
let totalProviders = 0;
|
||||||
|
let passedProviders = 0;
|
||||||
|
|
||||||
|
for (const [providerName, modules] of Object.entries(results)) {
|
||||||
|
totalProviders++;
|
||||||
|
const requiredModules = ["catalog", "posts", "meta", "stream"];
|
||||||
|
const passedRequired = requiredModules.every(
|
||||||
|
(mod) => modules[mod]?.success
|
||||||
|
);
|
||||||
|
|
||||||
|
if (passedRequired) {
|
||||||
|
passedProviders++;
|
||||||
|
console.log(`✅ ${providerName} - All required modules OK`);
|
||||||
|
} else {
|
||||||
|
console.log(`❌ ${providerName} - Missing required modules`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`\n📈 Results: ${passedProviders}/${totalProviders} providers passed`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (passedProviders === totalProviders) {
|
||||||
|
console.log("🎉 All providers are ready for testing!");
|
||||||
|
} else {
|
||||||
|
console.log("⚠️ Some providers need attention before testing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger rebuild on server
|
||||||
|
*/
|
||||||
|
async rebuild() {
|
||||||
|
try {
|
||||||
|
console.log("🔨 Triggering rebuild...");
|
||||||
|
const response = await this.axios.post("/build");
|
||||||
|
console.log("✅ Rebuild completed");
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
"❌ Rebuild failed:",
|
||||||
|
error.response?.data?.error || error.message
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get server status
|
||||||
|
*/
|
||||||
|
async getStatus() {
|
||||||
|
try {
|
||||||
|
const response = await this.axios.get("/status");
|
||||||
|
const status = response.data;
|
||||||
|
|
||||||
|
console.log("📊 Server Status:");
|
||||||
|
console.log(` 🟢 Status: ${status.status}`);
|
||||||
|
console.log(` 🔌 Port: ${status.port}`);
|
||||||
|
console.log(` 📦 Providers: ${status.providers}`);
|
||||||
|
console.log(` 🕐 Last Build: ${status.buildTime || "Never"}`);
|
||||||
|
|
||||||
|
if (status.providerList.length > 0) {
|
||||||
|
console.log(" 📋 Available Providers:");
|
||||||
|
status.providerList.forEach((p) => console.log(` • ${p}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ Failed to get status:", error.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI interface
|
||||||
|
*/
|
||||||
|
async function main() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const command = args[0] || "test";
|
||||||
|
const providerName = args[1];
|
||||||
|
|
||||||
|
const tester = new ProviderTester();
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case "test":
|
||||||
|
if (providerName) {
|
||||||
|
await tester.testProvider(providerName);
|
||||||
|
} else {
|
||||||
|
await tester.testAllProviders();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "status":
|
||||||
|
await tester.getStatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "rebuild":
|
||||||
|
await tester.rebuild();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "connection":
|
||||||
|
await tester.testConnection();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "manifest":
|
||||||
|
await tester.testManifest();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.log(`
|
||||||
|
Usage: node test-providers.js [command] [provider]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
test [provider] - Test all providers or specific provider
|
||||||
|
status - Show server status
|
||||||
|
rebuild - Trigger rebuild
|
||||||
|
connection - Test server connection
|
||||||
|
manifest - Test manifest endpoint
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
node test-providers.js # Test all providers
|
||||||
|
node test-providers.js test vega # Test specific provider
|
||||||
|
node test-providers.js status # Show status
|
||||||
|
node test-providers.js rebuild # Rebuild and test
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
main().catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ProviderTester;
|
||||||
Reference in New Issue
Block a user