99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
/**
|
|
* 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<PostizConfig | null> {
|
|
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<Response> {
|
|
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 };
|
|
}
|