/** * Postiz API client — reads per-space credentials from module settings * and forwards authenticated requests to the Postiz public API. * * Follows the same pattern as listmonk-proxy.ts. */ import { loadCommunity, getDocumentData } from "../../../server/community-store"; export interface PostizConfig { url: string; apiKey: string; } /** Read Postiz credentials from the space's module settings. */ export async function getPostizConfig(spaceSlug: string): Promise { await loadCommunity(spaceSlug); const data = getDocumentData(spaceSlug); if (!data) return null; const settings = data.meta.moduleSettings?.rsocials; if (!settings) return null; const url = settings.postizUrl as string | undefined; const apiKey = settings.postizApiKey as string | undefined; if (!url || !apiKey) return null; return { url: url.replace(/\/+$/, ''), apiKey }; } /** Make an authenticated request to the Postiz API. */ export async function postizFetch( config: PostizConfig, path: string, opts: RequestInit = {}, ): Promise { const headers = new Headers(opts.headers); headers.set("Authorization", `Bearer ${config.apiKey}`); if (!headers.has("Content-Type") && opts.body) { headers.set("Content-Type", "application/json"); } return fetch(`${config.url}${path}`, { ...opts, headers }); } /** GET /public/v1/integrations — list connected social channels. */ export async function getIntegrations(config: PostizConfig) { const res = await postizFetch(config, "/public/v1/integrations"); if (!res.ok) throw new Error(`Postiz integrations error: ${res.status}`); return res.json(); } /** POST /public/v1/posts — create a single post (draft, schedule, or now). */ export async function createPost( config: PostizConfig, payload: { content: string; integrationIds: string[]; type: 'draft' | 'schedule' | 'now'; scheduledAt?: string; group?: string; }, ) { const res = await postizFetch(config, "/public/v1/posts", { method: "POST", body: JSON.stringify(payload), }); if (!res.ok) { const text = await res.text().catch(() => ''); throw new Error(`Postiz createPost error: ${res.status} ${text}`); } return res.json(); } /** Create a thread — sends multiple grouped posts sharing a group ID. */ export async function createThread( config: PostizConfig, tweets: string[], opts: { integrationIds: string[]; type: 'draft' | 'schedule' | 'now'; scheduledAt?: string; }, ) { const group = `thread-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`; const results = []; for (const content of tweets) { const result = await createPost(config, { content, integrationIds: opts.integrationIds, type: opts.type, scheduledAt: opts.scheduledAt, group, }); results.push(result); } return { group, posts: results }; }