packages/devtools-server/src/serve-api.ts
import type { Express } from "express";
import { json } from "express";
import uniq from "lodash/uniq";
import {
AvailablePackageType,
Feed,
PackageType,
} from "@refinedev/devtools-shared";
import { Data } from "./create-db";
import { getFeed } from "./feed/get-feed";
import { getAllPackages } from "./packages/get-all-packages";
import { getAvailablePackages } from "./packages/get-available-packages";
import { updatePackage } from "./packages/update-package";
import { getLatestPackageData } from "./packages/get-latest-package-data";
import { getProjectIdFromPackageJson } from "./project-id/get-project-id-from-package-json";
import { updateProjectId } from "./project-id/update-project-id";
export const serveApi = (app: Express, db: Data) => {
app.use("/api", json());
app.get("/api/connected-app", (_, res) => {
res.json({ url: db.connectedApp });
});
app.get("/api/activities", (req, res) => {
const { offset = 0, limit = db.activities.length } = req.query;
res.setHeader("x-total-count", db.activities.length);
res.json({
data: db.activities.slice(Number(offset), Number(limit)),
});
});
app.get("/api/activities/reset", (_, res) => {
db.activities = [];
res.json({ success: true });
});
app.get("/api/unique-trace-items", (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept",
);
const traceItems = db.activities.flatMap(
(activity) =>
activity.trace?.map((t) => t.function).filter(Boolean) ?? [],
) as string[];
const uniqueTraceItems = uniq(traceItems);
res.setHeader("x-total-count", uniqueTraceItems.length);
res.json({ data: uniqueTraceItems });
});
let cachedInstalledPackages: PackageType[] | null = null;
app.get("/api/installed-packages", async (req, res) => {
const { force } = req.query ?? {};
if (!cachedInstalledPackages || force) {
cachedInstalledPackages = await getAllPackages();
}
res.header("x-total-count", `${cachedInstalledPackages.length}`);
res.json({ data: cachedInstalledPackages });
});
let cachedAvailablePackages: AvailablePackageType[] | null = null;
app.get("/api/available-packages", async (_, res) => {
if (!cachedAvailablePackages) {
cachedAvailablePackages = await getAvailablePackages();
}
res.header("x-total-count", `${cachedAvailablePackages.length}`);
res.json({ data: cachedAvailablePackages });
});
const cachedLatestPackages = new Map<string, any>();
app.get("/api/packages/:packageName/latest", async (req, res) => {
const { packageName } = req.params ?? {};
if (!packageName) {
res.status(400).json({ error: "Package name is required" });
return;
}
if (!cachedLatestPackages.has(packageName)) {
const latest = await getLatestPackageData(packageName);
cachedLatestPackages.set(packageName, latest);
}
return res.json({ data: cachedLatestPackages.get(packageName) });
});
app.post("/api/packages/install", async (req, res) => {
const { packages } = req.body ?? {};
if (packages?.length === 0) {
res.status(400).json({ error: "Package name is required" });
return;
}
const success = await updatePackage(packages as string[]);
if (success) {
cachedInstalledPackages = null;
cachedAvailablePackages = null;
res.status(200).json({ success: true });
} else {
res.status(400).json({
success: false,
error: "Failed to update package",
});
}
});
let cachedFeed: Feed | null = null;
app.get("/api/feed", async (req, res) => {
if (!cachedFeed) {
cachedFeed = await getFeed();
}
res.header("x-total-count", `${cachedFeed.length}`);
res.json({ data: cachedFeed });
});
app.get("/api/project-id/status", async (_, res) => {
const projectId = await getProjectIdFromPackageJson();
if (projectId) {
res.status(200).json({ projectId });
return;
}
if (projectId === false) {
res.status(404).json({ projectId: null });
return;
}
res.status(500).json({ projectId: null });
return;
});
app.post("/api/project-id/update", async (req, res) => {
const { projectId } = req.body ?? {};
if (!projectId) {
res.status(400).json({ error: "Project ID is required" });
return;
}
const success = await updateProjectId(projectId);
if (success) {
res.status(200).json({ success: true });
return;
}
res.status(500).json({
success: false,
error: "Failed to update project ID",
});
return;
});
};