Reserve slugs beginning with _ or .

Enforced at three layers: the site editor validates slug inputs before
committing (rename and new-page rows), the API rejects such paths in
_check_reserved (page save/delete, structure moves, editor socket), and
the content catch-all 404s them without a tree lookup.
This commit is contained in:
2026-08-16 16:25:26 +00:00
parent 508795437f
commit 37af433704
4 changed files with 34 additions and 9 deletions
+15
View File
@@ -200,6 +200,10 @@ async function commitPending() {
if (!slug) {
return
}
if (invalidSlug(slug)) {
saveError.value = '⚠️ slugs cannot begin with _ or .'
return // keep the pending row so the slug can be fixed
}
const loc = locatePending(tree.value, '')
const parentPath = loc?.parentPath ?? ''
const newPath = parentPath ? `${parentPath}/${slug}` : slug
@@ -394,9 +398,20 @@ function onTitleInput(node, ev) {
})
}
// Slugs may not begin with _ or . (reserved for the /_/ machinery and
// dot-paths); enforced on every commit, and again server-side.
function invalidSlug(slug) {
return slug.startsWith('_') || slug.startsWith('.')
}
async function commitSlug(node, ev) {
const slug = ev.target.value.trim().replace(/\/+/g, '')
if (slug === node.slug) return
if (invalidSlug(slug)) {
saveError.value = '⚠️ slugs cannot begin with _ or .'
ev.target.value = node.slug
return
}
const parent = node.path.split('/').slice(0, -1).join('/')
// Empty slug at top level = the front page (path "").
const moveTo = parent ? (slug ? `${parent}/${slug}` : parent) : slug