feat(apiclient): Add native Admin & Content API clients, JWT generator, and tag visibility features; remove external @tryghost deps and update docs
This commit is contained in:
58
readme.md
58
readme.md
@@ -9,8 +9,10 @@ A modern, fully-typed API client for Ghost CMS that wraps both the Content and A
|
||||
- **🎯 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
|
||||
|
||||
@@ -199,18 +201,46 @@ const filteredPages = await ghost.getPages({
|
||||
|
||||
## 🏷️ Tags
|
||||
|
||||
### Get 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
|
||||
@@ -219,21 +249,38 @@ const blogTags = await ghost.getTags({ filter: '*blog*' });
|
||||
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'
|
||||
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();
|
||||
```
|
||||
|
||||
@@ -531,7 +578,9 @@ try {
|
||||
| `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 | `Promise<ITag[]>` |
|
||||
| `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>` |
|
||||
@@ -583,6 +632,9 @@ try {
|
||||
| `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>` |
|
||||
|
Reference in New Issue
Block a user