MX Space v11 refactors the Aggregate API by splitting categories and pages out of the aggregate endpoint and adding a lightweight site metadata endpoint. This guide will help you complete the upgrade.
v11 brings clearer API responsibilities and better performance:
- Lighter Aggregate:
GET /aggregateno longer returnscategoriesandpageMeta, reducing response size and improving cache efficiency - New
/aggregate/site: Use this lightweight endpoint when you only need basic site info (user, SEO, URL), reducing unnecessary request payload - SEO config enhancements: Support for
iconandiconDarkto enable light/dark theme favicon switching
- No database migration: v11 does not change database schema; no migration scripts to run
- API consumers only: Frontends and third-party clients using
GET /aggregateor@mx-space/api-clientneed to adapt
Although v11 has no database migration, backing up MongoDB before upgrading is still recommended:
mongodump --uri="$MONGO_URI" --out=./backup-$(date +%Y%m%d)| Component | Minimum version |
|---|---|
| Node.js | 22+ |
| MongoDB | 5.0+ |
| @mx-space/api-client | v11-compatible |
| Shiroi / frontend | Must adapt to new API |
- Verify whether your frontend or third-party clients depend on
categoriesorpageMetain the aggregate response - If so, complete code updates before upgrading
| Change | v10 (old) | v11 (new) |
|---|---|---|
categories |
CategoryModel[] category list |
Removed |
pageMeta |
Pick<PageModel, 'title' | 'id' | 'slug' | 'order'>[] page metadata |
Removed |
Accept-Language translation |
Category names and page titles auto-translated by request language | Removed |
| Other fields | user, seo, url, commentOptions, latestNoteId, theme, ai |
Unchanged |
Example v11 GET /aggregate response:
{
"user": { "id": "...", "name": "...", "socialIds": {...}, ... },
"seo": { "title": "...", "description": "...", "icon": "", "iconDark": "", "keywords": [] },
"url": { "wsUrl": "...", "serverUrl": "...", "webUrl": "..." },
"commentOptions": { "disableComment": false, "allowGuestComment": true },
"latestNoteId": { "id": "...", "nid": 123 },
"theme": { ... },
"ai": { "enableSummary": false }
}v11 adds a lightweight site metadata endpoint for scenarios that only need basic site info (e.g. PWA manifest, SSR metadata):
| Field | Type | Description |
|---|---|---|
user |
Pick<UserModel, 'id' | 'name' | 'socialIds'> |
Basic user info |
seo |
SeoOptionModel |
SEO config (includes icon, iconDark) |
url |
Pick<Url, 'webUrl'> |
Site URL |
Example response:
{
"user": { "id": "...", "name": "Innei", "socialIds": { "github": "...", "x": "..." } },
"seo": { "title": "...", "description": "...", "icon": "/favicon-light.svg", "iconDark": "/favicon-dark.svg", "keywords": [] },
"url": { "webUrl": "https://example.com" }
}| Field | v10 (old) | v11 (new) |
|---|---|---|
icon |
N/A | New, optional, light theme favicon URL |
iconDark |
N/A | New, optional, dark theme favicon URL |
Defaults to empty string. Configurable in the admin panel under SEO settings.
| Interface | Change |
|---|---|
AggregateRoot |
categories and pageMeta removed |
AggregateRootWithTheme |
Extends AggregateRoot; same fields removed |
AggregateSiteInfo |
New, maps to GET /aggregate/site response |
SeoOptionModel |
New optional field iconDark?: string |
| Method | Change |
|---|---|
getAggregateData(theme?) |
Return type AggregateRootWithTheme no longer includes categories, pageMeta |
getSiteMetadata() |
New, calls GET /aggregate/site, returns AggregateSiteInfo |
v10:
const data = await client.aggregate.getAggregateData()
const categories = data.categoriesv11:
const [aggregateData, categoriesRes] = await Promise.all([
client.aggregate.getAggregateData(),
client.category.getAllCategories(),
])
const categories = categoriesRes.datav10:
const data = await client.aggregate.getAggregateData()
const pageMeta = data.pageMeta ?? []v11:
const [aggregateData, pagesRes] = await Promise.all([
client.aggregate.getAggregateData(),
client.page.getList(1, 50, { sortBy: 'order', sortOrder: 1 }),
])
const pageMeta = pagesRes.data ?? []If you only need
title,id,slug,order, useclient.page.getList(1, 50, { select: ['title', 'id', 'slug', 'order'] })to reduce response size.
v10:
const data = await client.aggregate.getAggregateData()
const { user, seo, url } = datav11 (recommended):
const data = await client.aggregate.getSiteMetadata()
const { user, seo, url } = datagetSiteMetadata() returns a lighter payload without commentOptions, latestNoteId, theme, ai, etc., suitable when you only need basic site info.
v10 behavior: Sending Accept-Language: zh-CN with GET /aggregate returned translated categories[].name and pageMeta[].title.
v11 behavior: The aggregate endpoint no longer provides translation. Fetch and handle i18n via the respective APIs:
- Categories:
client.category.getAllCategories()supportsAccept-Language(if server has translation configured) - Pages:
client.page.getList()orclient.page.getBySlug()supportAccept-Language
Check each endpoint’s docs for translation support, or implement i18n logic on the client.
If your code explicitly references categories or pageMeta on AggregateRoot:
// v10
const categories: CategoryModel[] = data.categories
const pageMeta: PageMeta[] = data.pageMeta ?? []v11 fix:
// Remove references to removed fields; fetch from respective APIs instead
const categoriesRes = await client.category.getAllCategories()
const categories: CategoryModel[] = categoriesRes.data
const pagesRes = await client.page.getList(1, 50)
const pageMeta = pagesRes.data ?? []Cause: v11’s GET /aggregate no longer returns categories.
Fix: Use client.category.getAllCategories() for categories. See Migration guide — Scenario 1.
Cause: v11’s GET /aggregate no longer returns pageMeta.
Fix: Use client.page.getList() for the page list. See Migration guide — Scenario 2.
Cause: v11 removed Accept-Language translation support from the aggregate endpoint.
Fix: Send Accept-Language when calling category or page APIs, or implement i18n logic on the client.
A: The aggregate endpoint was doing too much, leading to large responses and coarse cache granularity. After splitting, use /aggregate/site when you only need site metadata, and request categories or pages on demand. This improves first-load performance and cache strategy.
A: No. v11 has no database migration; only API behavior changes.
A: Yes. GET /aggregate still exists; only categories and pageMeta were removed. Other fields are unchanged. If you need full data, request category and page endpoints separately.
A: getSiteMetadata() returns only user, seo, and url (with user and url trimmed). getAggregateData() also includes commentOptions, latestNoteId, theme, ai, etc. Choose based on your needs.
A: No. Both are optional and default to empty string. Configure them to let the frontend switch favicon by theme.