import type { Ghost } from './classes.ghost.js'; import * as plugins from './ghost.plugins.js'; export interface IAuthor { id: string; name: string; slug: string; profile_image?: string; cover_image?: string; bio?: string; website?: string; location?: string; facebook?: string; twitter?: string; meta_title?: string; meta_description?: string; url: string; } export interface ITag { id: string; name: string; slug: string; description?: string; feature_image?: string; visibility: string; og_image?: string; og_title?: string; og_description?: string; twitter_image?: string; twitter_title?: string; twitter_description?: string; meta_title?: string; meta_description?: string; codeinjection_head?: string; codeinjection_foot?: string; canonical_url?: string; accent_color?: string; url: string; } export interface IPost { id: string; uuid: string; title: string; slug: string; html: string; comment_id: string; feature_image?: string; featured: boolean; visibility: string; created_at: string; updated_at: string; published_at: string; custom_excerpt?: string; codeinjection_head?: string | null; codeinjection_foot?: string | null; custom_template?: string | null; canonical_url?: string | null; url: string; excerpt?: string; reading_time: number; access: boolean; comments: boolean; og_image?: string | null; og_title?: string | null; og_description?: string | null; twitter_image?: string | null; twitter_title?: string | null; twitter_description?: string | null; meta_title?: string | null; meta_description?: string | null; email_subject?: string | null; frontmatter?: string | null; feature_image_alt?: string | null; feature_image_caption?: string | null; authors: IAuthor[]; tags: ITag[]; primary_author: IAuthor; primary_tag: ITag; [key: string]: any; // To allow for additional properties } export class Post { public ghostInstanceRef: Ghost; public postData: IPost; constructor(ghostInstanceRefArg: Ghost, postData: IPost) { this.ghostInstanceRef = ghostInstanceRefArg; this.postData = postData; } public getId(): string { return this.postData.id; } public getTitle(): string { return this.postData.title; } public getHtml(): string { return this.postData.html; } public getExcerpt(): string { return this.postData.excerpt || this.generateExcerpt(); } public getFeatureImage(): string | undefined { return this.postData.feature_image; } public getAuthor(): IAuthor { return this.postData.primary_author; } public toJson(): IPost { return this.postData; } public async update(postData: Partial): Promise { try { // Only send fields that should be updated, not the entire post object with nested relations const updatePayload: any = { id: this.postData.id, updated_at: this.postData.updated_at, // Required for conflict detection ...postData }; // Remove read-only or computed fields that shouldn't be sent delete updatePayload.uuid; delete updatePayload.comment_id; delete updatePayload.url; delete updatePayload.excerpt; delete updatePayload.reading_time; delete updatePayload.created_at; // Don't send created_at in updates delete updatePayload.primary_author; delete updatePayload.primary_tag; delete updatePayload.count; delete updatePayload.email; delete updatePayload.newsletter; // Remove nested objects if they're not being updated if (!postData.authors) delete updatePayload.authors; if (!postData.tags) delete updatePayload.tags; if (!postData.tiers) delete updatePayload.tiers; const updatedPostData = await this.ghostInstanceRef.adminApi.posts.edit(updatePayload); this.postData = updatedPostData; return this; } catch (error) { throw error; } } public async delete(): Promise { try { await this.ghostInstanceRef.adminApi.posts.delete({ id: this.getId() }); } catch (error) { throw error; } } private generateExcerpt(length: number = 100): string { const plainText = this.postData.html.replace(/<[^>]+>/g, ''); // Strip HTML tags return plainText.length > length ? plainText.substring(0, length) + '...' : plainText; } }