Skip to content

feat: collection permalinks, step 1 — the contract and one entry path function - #72

Merged
Madraka merged 1 commit into
mainfrom
feat/collection-permalinks
Oct 22, 2026
Merged

Madraka merged 1 commit into
mainfrom
feat/collection-permalinks

Conversation

@Madraka

@Madraka Madraka commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

RFC-0038 / ADR-0040, step 1 of 3. There is no behaviour change: with no collections set, every entry URL is exactly what it was. Refs #50.

Contract

  • Site.collections.<key>.permalink: a template with a closed token set; v1 is fixed lower-case segments plus /{slug} (schema pattern).
  • Fixtures: valid/site/collection-permalinks.json; invalid/site/permalink-{trailing-slash,unknown-token,without-slug}.json. TS and Rust regenerated.

One function each way (@cloudhal/core-ts, browser-safe ./permalinks subpath)

  • entryPath(site, entry) and entryAt(site, path) (longest configured prefix first; a moved collection no longer answers at its old prefix), plus collectionPermalink and permalinkPrefix.

Every caller moved

About 35 inline /${collection}/${slug} copies and the renderer's one-argument entryPath(entry):

  • renderer: routes and resolvePath (now through entryAt), SEO, feeds, previews, surfaces, navigation, comments;
  • starter: routes and theme components;
  • core-ts: automations, search rows, site search, and the store's automatic redirect;
  • API: assets, menus, search, comments;
  • MCP: analytics reports, comments, search, schedules (release-titles.ts split out for the size ratchet);
  • CLI: analytics;
  • Studio: EntryPath / useSitePermalinks and the slug field prefix.

Themes without a Site in hand get the templates through MediaContext.permalinks.

A few callers that had only a site id now read the site once (in parallel where possible): releaseView, commentEntries, CLI publishedNodes, and planSearch (it reads the site node once).

Checks (run per package, sequentially)

Package Tests
core-ts 630/630 (incl. new permalinks.test.ts)
astro-renderer 255/255
api 371/371
mcp-server 140/140
Studio 1138/1138
core-contracts 444/444
cli (e2e, analytics) 15/15

Also passing: Rust tests, clippy, typecheck everywhere, design lint, and the size ratchet (the baseline only went down).

Next steps

  • Step 2: prefix redirects on template change, overlap checks, and reindexing search hrefs when a template changes.
  • Step 3: the Studio "Collections" settings and the MCP set_collection_permalink tool (with approval).

🤖 Generated with Claude Code

… function

RFC-0038 / ADR-0040, step 1 (no behaviour change):

- Contract: `Site.collections.<key>.permalink`, a template with a closed
  token set; v1 accepts fixed segments plus `/{slug}`. Fixtures: one valid,
  three invalid (trailing slash, unknown token, no slug). TS and Rust
  regenerated.
- core-ts `permalinks.ts`: `entryPath(site, entry)`, `entryAt(site, path)`,
  `collectionPermalink`, `permalinkPrefix`; browser-safe subpath
  `@cloudhal/core-ts/permalinks`.
- Every entry URL (about 35 inline `/${collection}/${slug}` copies and the
  renderer's one-argument `entryPath`) now comes from them: renderer
  routes, SEO, feeds, previews, surfaces, navigation, comments; starter;
  core-ts automations, search, the store's automatic redirect; API assets,
  menus, search, comments; MCP analytics, comments, search, schedules; CLI
  analytics; Studio screens through `EntryPath` / `useSitePermalinks`.
- The renderer's `resolvePath` reads entries through `entryAt`.
- Themes without a Site get the templates through `MediaContext.permalinks`.

With no `collections` set every path is unchanged.

Refs #50

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
@Madraka
Madraka merged commit cd9b7ff into main Oct 22, 2026
5 checks passed
@Madraka
Madraka deleted the feat/collection-permalinks branch October 22, 2026 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant