first commit

This commit is contained in:
“dongming”
2025-12-28 22:44:03 +08:00
commit acabcfa7ed
46 changed files with 13050 additions and 0 deletions

116
AGENT.md Normal file
View File

@@ -0,0 +1,116 @@
# Client SDK Usage Guide
This project uses an auto-generated SDK powered by `@hey-api/openapi-ts` to interact with the PayloadCMS multi-tenant backend.
## SDK Structure
- **Core Methods**: `src/clientsdk/sdk.gen.ts` (Contains classes like `Posts`, `Categories`, `Pages`, `Media`)
- **Type Definitions**: `src/clientsdk/types.gen.ts` (Contains interfaces like `Post`, `Category`, `Media`)
- **Query Serializer**: `src/clientsdk/querySerializer.ts` (Handles nested object serialization for PayloadCMS queries)
- **Client Factory**: `src/clientsdk/client/index.ts` (Use `createClient` to initialize a client instance)
## 1. Initialization
You must initialize the client with the correct `baseUrl`, `querySerializer`, and tenant headers.
```typescript
import { createClient } from '../clientsdk/client';
import { customQuerySerializer } from '../clientsdk/querySerializer';
import { TENANT_SLUG, TENANT_API_KEY, API_URL } from '../config';
const client = createClient({
baseUrl: API_URL,
querySerializer: customQuerySerializer, // CRITICAL: Required for nested where queries
headers: {
'X-Tenant-Slug': TENANT_SLUG,
'X-API-Key': TENANT_API_KEY,
},
});
```
## 2. Common Operations
### Fetching a List (with Sorting & Limits)
```typescript
import { Posts } from '../clientsdk/sdk.gen';
const response = await Posts.listPosts({
client,
query: {
limit: 10,
sort: '-createdAt', // Prefix with '-' for descending
},
});
// Access the data
const posts = response.data?.docs || [];
```
### Fetching a Single Document by Slug (Filtering)
PayloadCMS uses a specific `where` query syntax. The `customQuerySerializer` handles the translation to `where[slug][equals]=my-slug`.
```typescript
const response = await Posts.listPosts({
client,
query: {
where: {
slug: {
equals: 'my-article-slug',
},
},
limit: 1,
},
});
const post = response.data?.docs?.[0];
```
### Filtering by Category Slug
```typescript
const response = await Posts.listPosts({
client,
query: {
where: {
'categories.slug': {
equals: 'news',
},
},
},
});
```
## 3. Data Patterns
### Relationships
- **Categories**: In this project, categories are a **many-to-many** relationship. Always treat `post.categories` as an array.
- Correct: `post.categories?.[0]?.title`
- Incorrect: `post.category.title`
- **Media**: Images (like `heroImage`) are objects containing `url`, `alt`, and `sizes`.
- Example: `<img src={post.heroImage?.url} alt={post.heroImage?.alt} />`
### Rich Text (Lexical)
PayloadCMS provides Lexical rich text. We typically use `post.content_html` which is pre-rendered to HTML on the server.
- **React**: `<div dangerouslySetInnerHTML={{ __html: post.content_html }} />`
- **Vue**: `<div v-html="post.content_html" />`
- **Astro**: `<div set:html={post.content_html} />`
## 4. TypeScript Usage
Always use the generated types for better DX and safety.
```typescript
import type { Post, Category, Media } from '../clientsdk/types.gen';
function formatPost(post: Post) {
return {
title: post.title,
date: new Date(post.createdAt).toLocaleDateString()
};
}
```
## 5. Troubleshooting
- **CORS Issues**: Ensure `API_URL` in `config.ts` matches the backend port (default 3000).
- **Empty Results**: Check if the `X-Tenant-Slug` header matches the slug assigned to your content in the CMS admin panel.
- **Nested Query Error**: If you see "Deeply-nested arrays/objects arent supported", verify that you are passing the `customQuerySerializer` to the `createClient` options.