715 lines
20 KiB
Markdown
715 lines
20 KiB
Markdown
# @apiclient.xyz/ghost 👻
|
|
|
|
> The **unofficial** TypeScript-first Ghost CMS API client that actually makes sense
|
|
|
|
A modern, fully-typed API client for Ghost CMS that wraps both the Content and Admin APIs into an elegant, developer-friendly interface. Built with TypeScript, designed for humans.
|
|
|
|
## 🚀 Why This Library?
|
|
|
|
- **🎯 TypeScript Native** - Full type safety for all Ghost API operations
|
|
- **🔥 Dual API Support** - Unified interface for both Content and Admin APIs
|
|
- **⚡ Modern Async/Await** - No callback hell, just clean promises
|
|
- **🌐 Universal Compatibility** - Native fetch implementation works in Node.js, Deno, Bun, and browsers
|
|
- **🎨 Elegant API** - Intuitive methods that match your mental model
|
|
- **🔍 Smart Filtering** - Built-in minimatch support for flexible queries
|
|
- **🏷️ Complete Tag Support** - Fetch ALL tags (including zero-count), filter by visibility (internal/external)
|
|
- **🔄 Multi-Instance Sync** - Synchronize content across multiple Ghost sites
|
|
- **💪 Production Ready** - Battle-tested with comprehensive error handling
|
|
|
|
## 📦 Installation
|
|
|
|
```bash
|
|
npm install @apiclient.xyz/ghost
|
|
```
|
|
|
|
Or with pnpm:
|
|
|
|
```bash
|
|
pnpm install @apiclient.xyz/ghost
|
|
```
|
|
|
|
## 🎯 Quick Start
|
|
|
|
```typescript
|
|
import { Ghost } from '@apiclient.xyz/ghost';
|
|
|
|
const ghost = new Ghost({
|
|
baseUrl: 'https://your-ghost-site.com',
|
|
contentApiKey: 'your_content_api_key',
|
|
adminApiKey: 'your_admin_api_key'
|
|
});
|
|
|
|
const posts = await ghost.getPosts();
|
|
posts.forEach(post => console.log(post.getTitle()));
|
|
```
|
|
|
|
That's it. No complicated setup, no boilerplate. Just pure Ghost API goodness.
|
|
|
|
## 📚 Core API
|
|
|
|
### 🔑 Authentication & Setup
|
|
|
|
Initialize the Ghost client with your API credentials:
|
|
|
|
```typescript
|
|
const ghost = new Ghost({
|
|
baseUrl: 'https://your-ghost-site.com',
|
|
contentApiKey: 'your_content_api_key', // For reading public content
|
|
adminApiKey: 'your_admin_api_key' // For write operations
|
|
});
|
|
```
|
|
|
|
## 📝 Posts
|
|
|
|
### Get All Posts
|
|
|
|
```typescript
|
|
const posts = await ghost.getPosts();
|
|
|
|
posts.forEach(post => {
|
|
console.log(post.getTitle());
|
|
console.log(post.getExcerpt());
|
|
console.log(post.getFeatureImage());
|
|
});
|
|
```
|
|
|
|
### Filter Posts
|
|
|
|
```typescript
|
|
const techPosts = await ghost.getPosts({
|
|
tag: 'technology',
|
|
limit: 10
|
|
});
|
|
|
|
const featuredPosts = await ghost.getPosts({
|
|
featured: true,
|
|
limit: 5
|
|
});
|
|
|
|
const authorPosts = await ghost.getPosts({
|
|
author: 'john-doe'
|
|
});
|
|
```
|
|
|
|
### Get Single Post
|
|
|
|
```typescript
|
|
const post = await ghost.getPostById('post-id');
|
|
console.log(post.getTitle());
|
|
console.log(post.getHtml());
|
|
console.log(post.getAuthor());
|
|
```
|
|
|
|
### Create Post
|
|
|
|
```typescript
|
|
const newPost = await ghost.createPost({
|
|
title: 'My Awesome Post',
|
|
html: '<p>This is the content of my post.</p>',
|
|
feature_image: 'https://example.com/image.jpg',
|
|
tags: [{ id: 'tag-id' }],
|
|
excerpt: 'A brief summary of the post'
|
|
});
|
|
```
|
|
|
|
Or create from HTML specifically:
|
|
|
|
```typescript
|
|
const post = await ghost.createPostFromHtml({
|
|
title: 'My HTML Post',
|
|
html: '<p>Content here</p>'
|
|
});
|
|
```
|
|
|
|
### Update Post
|
|
|
|
```typescript
|
|
const post = await ghost.getPostById('post-id');
|
|
await post.update({
|
|
...post.toJson(),
|
|
title: 'Updated Title',
|
|
html: '<p>Updated content</p>'
|
|
});
|
|
```
|
|
|
|
### Delete Post
|
|
|
|
```typescript
|
|
const post = await ghost.getPostById('post-id');
|
|
await post.delete();
|
|
```
|
|
|
|
### Search Posts
|
|
|
|
Full-text search across post titles:
|
|
|
|
```typescript
|
|
const results = await ghost.searchPosts('typescript tutorial', { limit: 10 });
|
|
results.forEach(post => console.log(post.getTitle()));
|
|
```
|
|
|
|
### Related Posts
|
|
|
|
Get posts with similar tags:
|
|
|
|
```typescript
|
|
const post = await ghost.getPostById('post-id');
|
|
const related = await ghost.getRelatedPosts(post.getId(), 5);
|
|
related.forEach(p => console.log(`Related: ${p.getTitle()}`));
|
|
```
|
|
|
|
### Bulk Operations
|
|
|
|
```typescript
|
|
await ghost.bulkUpdatePosts(['id1', 'id2', 'id3'], {
|
|
featured: true
|
|
});
|
|
|
|
await ghost.bulkDeletePosts(['id4', 'id5', 'id6']);
|
|
```
|
|
|
|
## 📄 Pages
|
|
|
|
Pages work similarly to posts but are for static content:
|
|
|
|
```typescript
|
|
const pages = await ghost.getPages();
|
|
|
|
const aboutPage = await ghost.getPageBySlug('about');
|
|
console.log(aboutPage.getHtml());
|
|
|
|
const newPage = await ghost.createPage({
|
|
title: 'Contact',
|
|
html: '<p>Contact information...</p>'
|
|
});
|
|
|
|
await newPage.update({
|
|
html: '<p>Updated content</p>'
|
|
});
|
|
|
|
await newPage.delete();
|
|
```
|
|
|
|
Filter pages with minimatch patterns:
|
|
|
|
```typescript
|
|
const filteredPages = await ghost.getPages({
|
|
filter: 'about*',
|
|
limit: 10
|
|
});
|
|
```
|
|
|
|
## 🏷️ Tags
|
|
|
|
### Get All Tags
|
|
|
|
```typescript
|
|
// Get ALL tags (including those with zero posts)
|
|
const tags = await ghost.getTags();
|
|
tags.forEach(tag => console.log(`${tag.name} (${tag.slug})`));
|
|
```
|
|
|
|
**Note**: Uses Admin API to fetch ALL tags, including tags with zero posts. Previous versions using Content API would omit tags with no associated content.
|
|
|
|
### Filter by Visibility
|
|
|
|
Ghost supports two tag types:
|
|
- **Public tags**: Standard tags visible to readers
|
|
- **Internal tags**: Tags prefixed with `#` for internal organization (not visible publicly)
|
|
|
|
```typescript
|
|
// Get only public tags
|
|
const publicTags = await ghost.getPublicTags();
|
|
|
|
// Get only internal tags (e.g., #feature, #urgent)
|
|
const internalTags = await ghost.getInternalTags();
|
|
|
|
// Get all tags with explicit visibility filter
|
|
const publicTags = await ghost.getTags({ visibility: 'public' });
|
|
const internalTags = await ghost.getTags({ visibility: 'internal' });
|
|
const allTags = await ghost.getTags({ visibility: 'all' }); // default
|
|
```
|
|
|
|
### Filter Tags with Minimatch
|
|
|
|
```typescript
|
|
const techTags = await ghost.getTags({ filter: 'tech-*' });
|
|
const blogTags = await ghost.getTags({ filter: '*blog*' });
|
|
|
|
// Combine visibility and pattern filtering
|
|
const internalNews = await ghost.getTags({
|
|
filter: 'news-*',
|
|
visibility: 'internal'
|
|
});
|
|
```
|
|
|
|
### Get Single Tag
|
|
|
|
```typescript
|
|
const tag = await ghost.getTagBySlug('javascript');
|
|
console.log(tag.getName());
|
|
console.log(tag.getDescription());
|
|
console.log(tag.getVisibility()); // 'public' or 'internal'
|
|
|
|
// Check visibility
|
|
if (tag.isInternal()) {
|
|
console.log('This is an internal tag');
|
|
}
|
|
```
|
|
|
|
### Create, Update, Delete Tags
|
|
|
|
```typescript
|
|
// Create a public tag
|
|
const newTag = await ghost.createTag({
|
|
name: 'TypeScript',
|
|
slug: 'typescript',
|
|
description: 'All about TypeScript',
|
|
visibility: 'public'
|
|
});
|
|
|
|
// Create an internal tag (note the # prefix)
|
|
const internalTag = await ghost.createTag({
|
|
name: '#feature',
|
|
slug: 'hash-feature',
|
|
visibility: 'internal'
|
|
});
|
|
|
|
// Update tag
|
|
await newTag.update({
|
|
description: 'Everything TypeScript related'
|
|
});
|
|
|
|
// Delete tag (now works reliably!)
|
|
await newTag.delete();
|
|
```
|
|
|
|
## 👤 Authors
|
|
|
|
### Get Authors
|
|
|
|
```typescript
|
|
const authors = await ghost.getAuthors();
|
|
authors.forEach(author => {
|
|
console.log(`${author.getName()} (${author.getSlug()})`);
|
|
});
|
|
```
|
|
|
|
### Filter Authors
|
|
|
|
```typescript
|
|
const filteredAuthors = await ghost.getAuthors({
|
|
filter: 'j*',
|
|
limit: 10
|
|
});
|
|
```
|
|
|
|
### Get Single Author
|
|
|
|
```typescript
|
|
const author = await ghost.getAuthorBySlug('john-doe');
|
|
console.log(author.getBio());
|
|
console.log(author.getProfileImage());
|
|
```
|
|
|
|
### Update Author
|
|
|
|
```typescript
|
|
await author.update({
|
|
bio: 'Updated bio information',
|
|
website: 'https://johndoe.com'
|
|
});
|
|
```
|
|
|
|
## 👥 Members
|
|
|
|
Manage your Ghost site members (requires Ghost membership features):
|
|
|
|
### Get Members
|
|
|
|
```typescript
|
|
const members = await ghost.getMembers({ limit: 100 });
|
|
members.forEach(member => {
|
|
console.log(`${member.getName()} - ${member.getEmail()}`);
|
|
console.log(`Status: ${member.getStatus()}`);
|
|
});
|
|
```
|
|
|
|
### Filter Members
|
|
|
|
```typescript
|
|
const gmailMembers = await ghost.getMembers({
|
|
filter: '*@gmail.com'
|
|
});
|
|
```
|
|
|
|
### Get Single Member
|
|
|
|
```typescript
|
|
const member = await ghost.getMemberByEmail('user@example.com');
|
|
console.log(member.getStatus());
|
|
console.log(member.getLabels());
|
|
```
|
|
|
|
### Create Member
|
|
|
|
```typescript
|
|
const newMember = await ghost.createMember({
|
|
email: 'newuser@example.com',
|
|
name: 'New User',
|
|
note: 'VIP member'
|
|
});
|
|
```
|
|
|
|
### Update and Delete Members
|
|
|
|
```typescript
|
|
await member.update({
|
|
name: 'Updated Name',
|
|
note: 'Premium member'
|
|
});
|
|
|
|
await member.delete();
|
|
```
|
|
|
|
## 🪝 Webhooks
|
|
|
|
Manage webhooks for Ghost events:
|
|
|
|
```typescript
|
|
const webhook = await ghost.createWebhook({
|
|
event: 'post.published',
|
|
target_url: 'https://example.com/webhook',
|
|
name: 'Post Published Webhook'
|
|
});
|
|
|
|
await ghost.updateWebhook(webhook.id, {
|
|
target_url: 'https://example.com/new-webhook'
|
|
});
|
|
|
|
await ghost.deleteWebhook(webhook.id);
|
|
```
|
|
|
|
**Note:** The Ghost Admin API only supports creating, updating, and deleting webhooks. Browsing and reading individual webhooks are not supported by the underlying SDK.
|
|
|
|
## 🖼️ Image Upload
|
|
|
|
Upload images to your Ghost site:
|
|
|
|
```typescript
|
|
const imageUrl = await ghost.uploadImage('/path/to/image.jpg');
|
|
|
|
await ghost.createPost({
|
|
title: 'Post with Image',
|
|
html: '<p>Content here</p>',
|
|
feature_image: imageUrl
|
|
});
|
|
```
|
|
|
|
## 🔄 Multi-Instance Synchronization
|
|
|
|
The `SyncedInstance` class enables you to synchronize content across multiple Ghost instances - perfect for staging environments, multi-region deployments, or content distribution.
|
|
|
|
### Setup
|
|
|
|
```typescript
|
|
import { Ghost, SyncedInstance } from '@apiclient.xyz/ghost';
|
|
|
|
const sourceGhost = new Ghost({
|
|
baseUrl: 'https://source.ghost.com',
|
|
contentApiKey: 'source_content_key',
|
|
adminApiKey: 'source_admin_key'
|
|
});
|
|
|
|
const targetGhost1 = new Ghost({
|
|
baseUrl: 'https://target1.ghost.com',
|
|
contentApiKey: 'target1_content_key',
|
|
adminApiKey: 'target1_admin_key'
|
|
});
|
|
|
|
const targetGhost2 = new Ghost({
|
|
baseUrl: 'https://target2.ghost.com',
|
|
contentApiKey: 'target2_content_key',
|
|
adminApiKey: 'target2_admin_key'
|
|
});
|
|
|
|
const synced = new SyncedInstance(sourceGhost, [targetGhost1, targetGhost2]);
|
|
```
|
|
|
|
### Sync Content
|
|
|
|
```typescript
|
|
const tagReport = await synced.syncTags();
|
|
console.log(`Synced ${tagReport.totalItems} tags`);
|
|
console.log(`Duration: ${tagReport.duration}ms`);
|
|
|
|
const postReport = await synced.syncPosts();
|
|
console.log(`Success: ${postReport.targetReports[0].successCount}`);
|
|
console.log(`Failed: ${postReport.targetReports[0].failureCount}`);
|
|
|
|
const pageReport = await synced.syncPages();
|
|
```
|
|
|
|
### Sync Options
|
|
|
|
```typescript
|
|
const report = await synced.syncPosts({
|
|
filter: 'featured-*',
|
|
dryRun: true,
|
|
incremental: true
|
|
});
|
|
|
|
report.targetReports.forEach(targetReport => {
|
|
console.log(`Target: ${targetReport.targetUrl}`);
|
|
targetReport.results.forEach(result => {
|
|
console.log(` ${result.sourceSlug}: ${result.status}`);
|
|
});
|
|
});
|
|
```
|
|
|
|
### Sync Everything
|
|
|
|
```typescript
|
|
const reports = await synced.syncAll({
|
|
types: ['tags', 'posts', 'pages'],
|
|
syncOptions: {
|
|
dryRun: false
|
|
}
|
|
});
|
|
|
|
reports.forEach(report => {
|
|
console.log(`${report.contentType}: ${report.totalItems} items`);
|
|
});
|
|
```
|
|
|
|
### Sync Status & History
|
|
|
|
```typescript
|
|
const status = synced.getSyncStatus();
|
|
console.log(`Total mappings: ${status.totalMappings}`);
|
|
console.log(`Recent syncs: ${status.recentSyncs.length}`);
|
|
|
|
status.mappings.forEach(mapping => {
|
|
console.log(`Source: ${mapping.sourceSlug}`);
|
|
mapping.targetMappings.forEach(tm => {
|
|
console.log(` -> ${tm.targetUrl} (${tm.targetId})`);
|
|
});
|
|
});
|
|
|
|
synced.clearSyncHistory();
|
|
synced.clearMappings();
|
|
```
|
|
|
|
## 🎨 Complete Example
|
|
|
|
Here's a comprehensive example showing various operations:
|
|
|
|
```typescript
|
|
import { Ghost } from '@apiclient.xyz/ghost';
|
|
|
|
const ghost = new Ghost({
|
|
baseUrl: 'https://your-ghost-site.com',
|
|
contentApiKey: 'your_content_key',
|
|
adminApiKey: 'your_admin_key'
|
|
});
|
|
|
|
async function main() {
|
|
const imageUrl = await ghost.uploadImage('./banner.jpg');
|
|
|
|
const tag = await ghost.createTag({
|
|
name: 'Tutorial',
|
|
slug: 'tutorial',
|
|
description: 'Step-by-step guides'
|
|
});
|
|
|
|
const post = await ghost.createPost({
|
|
title: 'Getting Started with Ghost',
|
|
html: '<h1>Welcome</h1><p>This is an introduction...</p>',
|
|
feature_image: imageUrl,
|
|
tags: [{ id: tag.getId() }],
|
|
featured: true
|
|
});
|
|
|
|
console.log(`Created post: ${post.getTitle()}`);
|
|
|
|
const related = await ghost.getRelatedPosts(post.getId(), 5);
|
|
console.log(`Found ${related.length} related posts`);
|
|
|
|
const searchResults = await ghost.searchPosts('getting started', { limit: 10 });
|
|
console.log(`Search found ${searchResults.length} posts`);
|
|
}
|
|
|
|
main().catch(console.error);
|
|
```
|
|
|
|
## 🔒 Error Handling
|
|
|
|
All methods throw errors that you can catch and handle:
|
|
|
|
```typescript
|
|
try {
|
|
const post = await ghost.getPostById('invalid-id');
|
|
} catch (error) {
|
|
console.error('Failed to fetch post:', error);
|
|
}
|
|
|
|
try {
|
|
await post.update({ title: 'New Title' });
|
|
} catch (error) {
|
|
console.error('Failed to update post:', error);
|
|
}
|
|
```
|
|
|
|
## 📖 API Reference
|
|
|
|
### Ghost Class
|
|
|
|
| Method | Description | Returns |
|
|
|--------|-------------|---------|
|
|
| `getPosts(options?)` | Get all posts with optional filtering | `Promise<Post[]>` |
|
|
| `getPostById(id)` | Get a single post by ID | `Promise<Post>` |
|
|
| `createPost(data)` | Create a new post | `Promise<Post>` |
|
|
| `createPostFromHtml(data)` | Create post from HTML | `Promise<Post>` |
|
|
| `searchPosts(query, options?)` | Search posts by title | `Promise<Post[]>` |
|
|
| `getRelatedPosts(postId, limit)` | Get related posts | `Promise<Post[]>` |
|
|
| `bulkUpdatePosts(ids, updates)` | Update multiple posts | `Promise<Post[]>` |
|
|
| `bulkDeletePosts(ids)` | Delete multiple posts | `Promise<void>` |
|
|
| `getPages(options?)` | Get all pages | `Promise<Page[]>` |
|
|
| `getPageById(id)` | Get page by ID | `Promise<Page>` |
|
|
| `getPageBySlug(slug)` | Get page by slug | `Promise<Page>` |
|
|
| `createPage(data)` | Create a new page | `Promise<Page>` |
|
|
| `getTags(options?)` | Get all tags (including zero-count) | `Promise<ITag[]>` |
|
|
| `getPublicTags(options?)` | Get only public tags | `Promise<ITag[]>` |
|
|
| `getInternalTags(options?)` | Get only internal tags | `Promise<ITag[]>` |
|
|
| `getTagById(id)` | Get tag by ID | `Promise<Tag>` |
|
|
| `getTagBySlug(slug)` | Get tag by slug | `Promise<Tag>` |
|
|
| `createTag(data)` | Create a new tag | `Promise<Tag>` |
|
|
| `getAuthors(options?)` | Get all authors | `Promise<Author[]>` |
|
|
| `getAuthorById(id)` | Get author by ID | `Promise<Author>` |
|
|
| `getAuthorBySlug(slug)` | Get author by slug | `Promise<Author>` |
|
|
| `getMembers(options?)` | Get all members | `Promise<Member[]>` |
|
|
| `getMemberById(id)` | Get member by ID | `Promise<Member>` |
|
|
| `getMemberByEmail(email)` | Get member by email | `Promise<Member>` |
|
|
| `createMember(data)` | Create a new member | `Promise<Member>` |
|
|
| `createWebhook(data)` | Create a webhook | `Promise<any>` |
|
|
| `updateWebhook(id, data)` | Update a webhook | `Promise<any>` |
|
|
| `deleteWebhook(id)` | Delete a webhook | `Promise<void>` |
|
|
| `uploadImage(filePath)` | Upload an image | `Promise<string>` |
|
|
|
|
### Post Class
|
|
|
|
| Method | Description | Returns |
|
|
|--------|-------------|---------|
|
|
| `getId()` | Get post ID | `string` |
|
|
| `getTitle()` | Get post title | `string` |
|
|
| `getHtml()` | Get post HTML content | `string` |
|
|
| `getExcerpt()` | Get post excerpt | `string` |
|
|
| `getFeatureImage()` | Get feature image URL | `string \| undefined` |
|
|
| `getAuthor()` | Get primary author | `IAuthor` |
|
|
| `toJson()` | Get raw post data | `IPost` |
|
|
| `update(data)` | Update the post | `Promise<Post>` |
|
|
| `delete()` | Delete the post | `Promise<void>` |
|
|
|
|
### Page Class
|
|
|
|
| Method | Description | Returns |
|
|
|--------|-------------|---------|
|
|
| `getId()` | Get page ID | `string` |
|
|
| `getTitle()` | Get page title | `string` |
|
|
| `getHtml()` | Get page HTML content | `string` |
|
|
| `getSlug()` | Get page slug | `string` |
|
|
| `getFeatureImage()` | Get feature image URL | `string \| undefined` |
|
|
| `getAuthor()` | Get primary author | `IAuthor` |
|
|
| `toJson()` | Get raw page data | `IPage` |
|
|
| `update(data)` | Update the page | `Promise<Page>` |
|
|
| `delete()` | Delete the page | `Promise<void>` |
|
|
|
|
### Tag Class
|
|
|
|
| Method | Description | Returns |
|
|
|--------|-------------|---------|
|
|
| `getId()` | Get tag ID | `string` |
|
|
| `getName()` | Get tag name | `string` |
|
|
| `getSlug()` | Get tag slug | `string` |
|
|
| `getDescription()` | Get tag description | `string \| undefined` |
|
|
| `getVisibility()` | Get tag visibility | `string` |
|
|
| `isInternal()` | Check if tag is internal | `boolean` |
|
|
| `isPublic()` | Check if tag is public | `boolean` |
|
|
| `toJson()` | Get raw tag data | `ITag` |
|
|
| `update(data)` | Update the tag | `Promise<Tag>` |
|
|
| `delete()` | Delete the tag | `Promise<void>` |
|
|
|
|
### Author Class
|
|
|
|
| Method | Description | Returns |
|
|
|--------|-------------|---------|
|
|
| `getId()` | Get author ID | `string` |
|
|
| `getName()` | Get author name | `string` |
|
|
| `getSlug()` | Get author slug | `string` |
|
|
| `getProfileImage()` | Get profile image URL | `string \| undefined` |
|
|
| `getBio()` | Get author bio | `string \| undefined` |
|
|
| `toJson()` | Get raw author data | `IAuthor` |
|
|
| `update(data)` | Update the author | `Promise<Author>` |
|
|
|
|
### Member Class
|
|
|
|
| Method | Description | Returns |
|
|
|--------|-------------|---------|
|
|
| `getId()` | Get member ID | `string` |
|
|
| `getEmail()` | Get member email | `string` |
|
|
| `getName()` | Get member name | `string \| undefined` |
|
|
| `getStatus()` | Get member status | `string \| undefined` |
|
|
| `getLabels()` | Get member labels | `Array \| undefined` |
|
|
| `toJson()` | Get raw member data | `IMember` |
|
|
| `update(data)` | Update the member | `Promise<Member>` |
|
|
| `delete()` | Delete the member | `Promise<void>` |
|
|
|
|
### SyncedInstance Class
|
|
|
|
| Method | Description | Returns |
|
|
|--------|-------------|---------|
|
|
| `syncPosts(options?)` | Sync posts to targets | `Promise<ISyncReport>` |
|
|
| `syncPages(options?)` | Sync pages to targets | `Promise<ISyncReport>` |
|
|
| `syncTags(options?)` | Sync tags to targets | `Promise<ISyncReport>` |
|
|
| `syncAll(options?)` | Sync all content types | `Promise<ISyncReport[]>` |
|
|
| `getSyncStatus()` | Get sync status & mappings | `Object` |
|
|
| `clearSyncHistory()` | Clear sync history | `void` |
|
|
| `clearMappings()` | Clear ID mappings | `void` |
|
|
|
|
## 🧪 Testing
|
|
|
|
```bash
|
|
pnpm test
|
|
```
|
|
|
|
## 📝 TypeScript Support
|
|
|
|
This library is written in TypeScript and provides full type definitions out of the box. No `@types/*` package needed.
|
|
|
|
```typescript
|
|
import type { IPost, ITag, IAuthor, IMember } from '@apiclient.xyz/ghost';
|
|
```
|
|
|
|
## 🤝 Contributing
|
|
|
|
This is an open-source project. Issues and pull requests are welcome!
|
|
|
|
Repository: [https://code.foss.global/apiclient.xyz/ghost](https://code.foss.global/apiclient.xyz/ghost)
|
|
|
|
## License and Legal Information
|
|
|
|
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
|
|
### Trademarks
|
|
|
|
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
|
|
|
### Company Information
|
|
|
|
Task Venture Capital GmbH
|
|
Registered at District court Bremen HRB 35230 HB, Germany
|
|
|
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
|
|
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|