Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
12 lines
2.5 KiB
JavaScript
12 lines
2.5 KiB
JavaScript
/** portal/webmaker/api.mjs — Webmaker 연동 라우트: 내 프로젝트 목록(/api/webmaker/projects), AI Wallet(/api/webmaker/wallet), 연동 상태(운영자 /internal/ops/webmaker). SSO 진입은 portal/sites/api.mjs 의 /sso/webmaker. */
|
|
import { requireGroup } from '../auth/guard.mjs';
|
|
import { HttpError } from '../../lib/http.mjs';
|
|
import { verifyCtx } from '../../lib/serviceauth.mjs';
|
|
import { loginFor } from './adapter.mjs';
|
|
export async function register(app, deps) {
|
|
const wm = () => { if (!deps.webmaker) throw new HttpError(503, 'service_unreachable', 'Webmaker 연동이 설정되지 않았습니다'); return deps.webmaker; };
|
|
app.get('/api/webmaker/projects', async (ctx) => { requireGroup(ctx); try { const projects = await wm().listProjects(loginFor(ctx.user, ctx.group)); const linked = new Set(deps.store.all('SELECT webmaker_project_id FROM sites WHERE group_id=? AND webmaker_project_id IS NOT NULL AND lifecycle<>\'deleted\'', ctx.group.id).map((r) => r.webmaker_project_id)); return { ok: true, projects: projects.map((p) => ({ ...p, link: p.link || (linked.has(p.id) ? { siteId: deps.store.get('SELECT id FROM sites WHERE webmaker_project_id=?', p.id)?.id } : null) })) }; } catch (e) { if (e.code === 'service_unreachable') return ctx.json({ ok: false, error: 'service_unreachable', message: 'Webmaker 에 연결할 수 없습니다(정보 확인 지연)' }, 503); throw e; } });
|
|
app.get('/api/webmaker/wallet', async (ctx) => { requireGroup(ctx); try { const w = await wm().credits(loginFor(ctx.user, ctx.group)); return { ok: true, wallet: w.credit, unit: w.unit, note: 'AI Wallet 은 AI 생성·수정 비용에만 쓰이며 호스팅 디스크·트래픽·메일 사용량과 분리됩니다' }; } catch (e) { if (e.code === 'service_unreachable') return ctx.json({ ok: false, error: 'service_unreachable', message: 'Webmaker 에 연결할 수 없습니다(정보 확인 지연)' }, 503); throw e; } });
|
|
app.get('/internal/ops/webmaker', async (ctx) => { const v = await verifyCtx(ctx, (id) => (['hal', 'portal'].includes(id) ? deps.vault.get('service:' + id) : null)); if (!v.ok) throw new HttpError(401, 'service_auth_failed', v.reason); let health = null; try { health = await wm().health(); } catch (e) { health = { ok: false, error: e.code || e.message }; } return { ok: true, health, provisioning: deps.webmaker ? deps.webmaker.provisioningInfo() : null, ssoIssued24h: deps.store.get('SELECT COUNT(*) AS n FROM sso_tickets WHERE issued_at>?', new Date(Date.now() - 86400000).toISOString()).n }; });
|
|
}
|