Skip to content

Latest commit

 

History

History
268 lines (176 loc) · 8.71 KB

File metadata and controls

268 lines (176 loc) · 8.71 KB

Upgrading to MX Space v11

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.

Overview

Why upgrade?

v11 brings clearer API responsibilities and better performance:

  • Lighter Aggregate: GET /aggregate no longer returns categories and pageMeta, 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 icon and iconDark to enable light/dark theme favicon switching

Migration impact

  • No database migration: v11 does not change database schema; no migration scripts to run
  • API consumers only: Frontends and third-party clients using GET /aggregate or @mx-space/api-client need to adapt

Pre-upgrade checklist

1. Backup data (recommended)

Although v11 has no database migration, backing up MongoDB before upgrading is still recommended:

mongodump --uri="$MONGO_URI" --out=./backup-$(date +%Y%m%d)

2. Version requirements

Component Minimum version
Node.js 22+
MongoDB 5.0+
@mx-space/api-client v11-compatible
Shiroi / frontend Must adapt to new API

3. Check dependencies

  • Verify whether your frontend or third-party clients depend on categories or pageMeta in the aggregate response
  • If so, complete code updates before upgrading

Breaking Changes

API response structure changes

GET /aggregate

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 }
}

GET /aggregate/site (new)

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" }
}

SEO config changes

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.

@mx-space/api-client changes

Type definitions

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 changes

Method Change
getAggregateData(theme?) Return type AggregateRootWithTheme no longer includes categories, pageMeta
getSiteMetadata() New, calls GET /aggregate/site, returns AggregateSiteInfo

Migration guide

Scenario 1: Need category list

v10:

const data = await client.aggregate.getAggregateData()
const categories = data.categories

v11:

const [aggregateData, categoriesRes] = await Promise.all([
  client.aggregate.getAggregateData(),
  client.category.getAllCategories(),
])
const categories = categoriesRes.data

Scenario 2: Need page list (navigation, sitemap, etc.)

v10:

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, use client.page.getList(1, 50, { select: ['title', 'id', 'slug', 'order'] }) to reduce response size.

Scenario 3: Only need site metadata (favicon, SEO, site URL)

v10:

const data = await client.aggregate.getAggregateData()
const { user, seo, url } = data

v11 (recommended):

const data = await client.aggregate.getSiteMetadata()
const { user, seo, url } = data

getSiteMetadata() returns a lighter payload without commentOptions, latestNoteId, theme, ai, etc., suitable when you only need basic site info.

Scenario 4: Rely on Accept-Language for category/page translation

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() supports Accept-Language (if server has translation configured)
  • Pages: client.page.getList() or client.page.getBySlug() support Accept-Language

Check each endpoint’s docs for translation support, or implement i18n logic on the client.

Scenario 5: TypeScript type errors

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 ?? []

Troubleshooting

Frontend error: data.categories is undefined

Cause: v11’s GET /aggregate no longer returns categories.

Fix: Use client.category.getAllCategories() for categories. See Migration guide — Scenario 1.

Frontend error: data.pageMeta is undefined

Cause: v11’s GET /aggregate no longer returns pageMeta.

Fix: Use client.page.getList() for the page list. See Migration guide — Scenario 2.

Category/page names no longer translated by language

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.


FAQ

Q: Why were categories and pageMeta removed?

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.

Q: Do I need to modify the database after upgrading?

A: No. v11 has no database migration; only API behavior changes.

Q: Can I still use GET /aggregate?

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.

Q: What’s the difference between getSiteMetadata() and getAggregateData()?

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.

Q: Must icon and iconDark be configured?

A: No. Both are optional and default to empty string. Configure them to let the frontend switch favicon by theme.


Related resources