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:
2025-10-10 12:57:31 +00:00
parent 719bfafb93
commit 11a9b23802
14 changed files with 875 additions and 125 deletions

View File

@@ -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>` |