Introduce token-based author authentication (register/verify API), skill forking with EditGate protection, tag metadata on skills, and download/push stats. Enhanced push scripts with token auth and per-skill filtering. Updated UI with stats, tags, and author info on skill cards.
47 lines
1.3 KiB
JavaScript
47 lines
1.3 KiB
JavaScript
import fs from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
|
|
const STATS_FILE = path.resolve(process.env.STATS_FILE || "data/stats.json");
|
|
async function readStore() {
|
|
try {
|
|
const raw = await fs.readFile(STATS_FILE, "utf-8");
|
|
return JSON.parse(raw);
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|
|
async function writeStore(store) {
|
|
const dir = path.dirname(STATS_FILE);
|
|
await fs.mkdir(dir, { recursive: true });
|
|
const tmp = STATS_FILE + ".tmp";
|
|
await fs.writeFile(tmp, JSON.stringify(store, null, 2), "utf-8");
|
|
await fs.rename(tmp, STATS_FILE);
|
|
}
|
|
function ensure(store, slug) {
|
|
if (!store[slug]) {
|
|
store[slug] = { downloads: 0, pushes: 0, lastPushedAt: null };
|
|
}
|
|
return store[slug];
|
|
}
|
|
async function recordDownload(slug) {
|
|
const store = await readStore();
|
|
ensure(store, slug).downloads++;
|
|
await writeStore(store);
|
|
}
|
|
async function recordPush(slug) {
|
|
const store = await readStore();
|
|
const entry = ensure(store, slug);
|
|
entry.pushes++;
|
|
entry.lastPushedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
await writeStore(store);
|
|
}
|
|
async function getStatsForSlug(slug) {
|
|
const store = await readStore();
|
|
return store[slug] || { downloads: 0, pushes: 0, lastPushedAt: null };
|
|
}
|
|
async function getAllStats() {
|
|
return readStore();
|
|
}
|
|
|
|
export { recordDownload as a, getAllStats as b, getStatsForSlug as g, recordPush as r };
|