/** * Engine client — единая точка вызовов к zeropost-engine */ const ENGINE_URL = process.env.ENGINE_URL || 'http://127.0.0.1:3040'; const ENGINE_SECRET = process.env.ENGINE_SECRET || 'zeropost_internal_2026'; async function call(path, options = {}) { const { userId, body, method = 'GET' } = options; const headers = { 'Content-Type': 'application/json', 'x-internal-secret': ENGINE_SECRET, }; if (userId) headers['x-user-id'] = String(userId); const url = `${ENGINE_URL}${path}`; const res = await fetch(url, { method, headers, body: body ? JSON.stringify(body) : undefined, cache: 'no-store', }); if (!res.ok) { const err = await res.json().catch(() => ({ error: res.statusText })); const e = new Error(err.error || `Engine ${res.status}`); e.status = res.status; e.code = err.code; throw e; } return res.json(); } export const engine = { // Channels listChannels: (userId) => call('/api/channels/', { userId }), getChannel: (userId, id) => call(`/api/channels/${id}`, { userId }), createChannel: (userId, data) => call('/api/channels/', { userId, method: 'POST', body: data }), updateChannel: (userId, id, data) => call(`/api/channels/${id}`, { userId, method: 'PATCH', body: data }), deleteChannel: (userId, id) => call(`/api/channels/${id}`, { userId, method: 'DELETE' }), // Generation generate: (userId, data) => call('/api/generate/', { userId, method: 'POST', body: data }), getJob: (userId, id) => call(`/api/generate/${id}`, { userId }), transformPost: (userId, data) => call('/api/generate/transform', { userId, method: 'POST', body: data }), generatePostImage: (userId, data) => call('/api/generate/post-image', { userId, method: 'POST', body: data }), topicsIdeas: (userId, data) => call('/api/generate/topics-ideas', { userId, method: 'POST', body: data }), getImageStyles: () => call('/api/generate/image-styles'), // User posts (черновики / запланированные / опубликованные) listUserPosts: (userId, params = {}) => { const qs = new URLSearchParams(params).toString(); return call(`/api/user-posts${qs ? '?' + qs : ''}`, { userId }); }, savePost: (userId, data) => call('/api/user-posts', { userId, method: 'POST', body: data }), getPost: (userId, id) => call(`/api/user-posts/${id}`, { userId }), updatePost: (userId, id, data) => call(`/api/user-posts/${id}`, { userId, method: 'PATCH', body: data }), deletePost: (userId, id) => call(`/api/user-posts/${id}`, { userId, method: 'DELETE' }), publishPost: (userId, id) => call(`/api/user-posts/${id}/publish`, { userId, method: 'POST' }), // Photo search photoSearchProfiles: () => call('/api/photo-search/profiles'), photoSearchQuota: () => call('/api/photo-search/quota'), photoSearchByQuery: (data) => call('/api/photo-search/by-query', { method: 'POST', body: data }), // Settings (admin) listSettings: (category) => { const qs = category ? `?category=${encodeURIComponent(category)}` : ''; return call(`/api/settings/admin${qs}`); }, updateSetting: (key, value) => call(`/api/settings/admin/${encodeURIComponent(key)}`, { method: 'PUT', body: { value } }), invalidateSettingsCache: () => call('/api/settings/admin/invalidate', { method: 'POST' }), // AI usage (admin) usageSummary: (params = {}) => { const qs = new URLSearchParams(params).toString(); return call(`/api/usage/summary${qs ? '?' + qs : ''}`); }, usageRecent: (limit = 20) => call(`/api/usage/recent?limit=${limit}`), // Editor notes listNotes: () => call('/api/notes?limit=100'), createNote: (data) => call('/api/notes', { method: 'POST', body: data }), updateNote: (id, data) => call(`/api/notes/${id}`, { method: 'PATCH', body: data }), deleteNote: (id) => call(`/api/notes/${id}`, { method: 'DELETE' }), // Calendar getCalendar: (userId, params = {}) => { const qs = new URLSearchParams(params).toString(); return call(`/api/calendar${qs ? '?' + qs : ''}`, { userId }); }, // Metrics getChannelMetrics: (channelId, params = {}) => { const qs = new URLSearchParams(params).toString(); return call(`/api/metrics/channel/${channelId}${qs ? '?' + qs : ''}`); }, getBestTime: (channelId, params = {}) => { const qs = new URLSearchParams(params).toString(); return call(`/api/metrics/best-time/${channelId}${qs ? '?' + qs : ''}`); }, getUserPostMetrics: (userId, channelId, params = {}) => { const qs = new URLSearchParams(params).toString(); return call(`/api/metrics/user-posts/${channelId}${qs ? '?' + qs : ''}`, { userId }); }, collectMetrics: () => call('/api/metrics/collect', { method: 'POST' }), generateFromUrl: (userId, data) => call('/api/generate/from-url', { userId, method: 'POST', body: data }), updateUserPostSchedule: (userId, id, scheduledAt) => call(`/api/user-posts/${id}`, { userId, method: 'PATCH', body: { scheduled_at: scheduledAt } }), };