Plugins
Add more capabilities to the same Next.js config through withAffordances's plugins, and write your own.
A plugin adds a capability to an Affordances app, such as serving every page as Markdown, without another config wrapper to order by hand. Plugins in Concepts explains what they are, and the Plugins section lists each one. Pass plugins to withAffordances:
import { withAffordances } from '@affordances/next/config'
import { md } from '@affordances/md/next'
export default withAffordances(nextConfig, { name: 'Store', plugins: [md()] })Then add each plugin's route handler. For md():
vlx @affordances/md initnpx @affordances/md initpnpm dlx @affordances/md inityarn dlx @affordances/md initbunx @affordances/md initdeno run -A npm:@affordances/md init
This site runs with md(): add .md to any page's URL. See Markdown.
How they combine
- Plugins run in order, after the graph's own rewrites and headers.
- Each plugin owns a route handler under
/api/affordances/<name>. - Each one matches its own requests, such as
Accept: text/markdownformd(), so plugins and the graph never answer for each other.
Write a plugin
A plugin is a config wrapper: it takes the Next config and returns it, the same shape as createMDX(). Call the config's own rewrites and headers so you keep what came before:
import type { AffordancesPlugin } from '@affordances/next/config'
// serves /.well-known/agents.json from a route handler at /api/affordances/agents
export const agents = (): AffordancesPlugin => (config) => ({
...config,
rewrites: async () => {
const before = await config.rewrites?.()
const rule = { source: '/.well-known/agents.json', destination: '/api/affordances/agents' }
return Array.isArray(before)
? [rule, ...before]
: { ...before, beforeFiles: [rule, ...(before?.beforeFiles ?? [])] }
},
})export default withAffordances(nextConfig, { plugins: [md(), agents()] })Keep its route under /api/affordances/<name>, and match only the requests it's for: withAffordances already claims the Affordances media type and ?affordances=1.