/
oinktech
/
readmef
Обзор
Документация
Войти
/
oinktech
/
readmef
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
master
server/providers/gitverse.js
130 строк
4 KB
TwixoffStudio
Create: package-lock.json, README.md, app.js, index.html, styles.css, index.js, aggregate.js, cache.js, readmeBuilder.js, svg.js, theme.js, base.js, github.js, gitverse.js, index.js, routes.js, .env.example, LICENSE, package.json
05 июл 2026, 13:09
Верифицирован
05 июл 2026, 13:09
dc3c4b9
Код
Авторство
О чём код?
'use strict'; const fetch = require('node-fetch'); const BaseProvider = require('./base'); const DEFAULT_BASE = process.env.GITVERSE_API_BASE || 'https://api.gitverse.ru'; function headers(token) { const h = { Accept: 'application/vnd.gitverse.object+json;version=latest', 'User-Agent': 'ReadmeForge', }; if (token) h.Authorization = `Bearer ${token}`; return h; } class GitVerseProvider extends BaseProvider { constructor(token, opts = {}) { super(token, opts); this.base = opts.apiBase || DEFAULT_BASE; } async gv(path, opts = {}) { const res = await fetch(`${this.base}${path}`, { ...opts, headers: { ...headers(this.token), ...(opts.headers || {}) }, }); if (!res.ok) { const body = await res.text().catch(() => ''); const err = new Error(`GitVerse API ${res.status}: ${body.slice(0, 300)}`); err.status = res.status; throw err; } if (res.status === 204) return null; return res.json(); } async getViewer() { // GitVerse — Gitea-совместимая платформа VK, /user отдаёт текущего пользователя const u = await this.gv('/user'); return { login: u.login || u.username, name: u.full_name || u.login || u.username, avatarUrl: u.avatar_url, bio: u.description || u.bio || '', htmlUrl: u.html_url || `https://gitverse.ru/${u.login || u.username}`, followers: u.followers_count || 0, publicRepos: u.public_repos || u.repos_count || 0, company: '', location: u.location || '', blog: u.website || '', }; } async listRepos() { const data = await this.gv('/user/repos?limit=100'); const list = Array.isArray(data) ? data : data.data || []; return list.map((r) => ({ name: r.name, fullName: r.full_name, description: r.description || '', language: r.language || null, stars: r.stargazers_count || 0, forks: r.forks_count || 0, updatedAt: r.pushed_at || r.updated_at, private: r.private, htmlUrl: r.html_url || `https://gitverse.ru/${r.full_name}`, fork: r.fork || false, topics: r.topics || [], })); } async getFileSha(owner, repo, path) { try { const data = await this.gv(`/repos/${owner}/${repo}/contents/${encodeURIComponent(path)}`); return data && data.sha ? data.sha : null; } catch (e) { if (e.status === 404) return null; throw e; } } async putFile(owner, repo, path, content, message, sha) { const body = { message, content: Buffer.from(content, 'utf8').toString('base64'), }; if (sha) body.sha = sha; return this.gv(`/repos/${owner}/${repo}/contents/${encodeURIComponent(path)}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); } /** У публичного API GitVerse пока нет документированной ленты событий — * возвращаем пусто, чтобы heatmap просто отрисовался пустой сеткой, * без падения всего процесса сборки README. */ async getPublicEvents() { return []; } async ensureRepo(name) { try { const viewer = await this.getViewer(); return await this.gv(`/repos/${viewer.login}/${name}`); } catch (e) { if (e.status !== 404) throw e; // Best-effort: у Gitea-совместимых API создание репозитория обычно // POST /user/repos. Если у GitVerse эндпоинт отличается — просим // пользователя один раз создать репозиторий вручную. try { return await this.gv('/user/repos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, description: 'Профильный README — ReadmeForge', auto_init: true }), }); } catch (e2) { const err = new Error( `Не удалось автоматически создать репозиторий "${name}" на GitVerse. ` + `Создайте репозиторий с таким именем вручную один раз и повторите публикацию.` ); err.status = 422; throw err; } } } } module.exports = GitVerseProvider;