Skip to content

Derive slugs from title when provided#46

Open
tomershlasky wants to merge 1 commit into
AdirAmsalem:mainfrom
tomershlasky:feat/title-derived-slugs
Open

Derive slugs from title when provided#46
tomershlasky wants to merge 1 commit into
AdirAmsalem:mainfrom
tomershlasky:feat/title-derived-slugs

Conversation

@tomershlasky

Copy link
Copy Markdown

Summary

Auto-generated subdomains currently look like warm-dawn-a1b2.easl.dev — purely random, even though POST /publish already accepts a title field. This PR uses that title (when present) to produce a self-describing slug like q1-budget-report-a1b2, with the existing adjective-noun-hex format kept as the fallback.

  • New slugifyTitle helper in packages/worker/src/lib/slug.ts (NFKD normalize → strip combining marks → lowercase → non-alphanumeric runs → - → trim → cap at 40 chars). Returns null when the result is empty or would collide with the reserved preview- namespace.
  • generateSlug(title?) accepts an optional title; falls back to the current adjective-noun-hex when no usable base is derived.
  • generateUniqueSlug in publish.ts threads body.title through; the per-attempt random hex suffix continues to resolve same-title collisions inside the existing retry loop. Custom-slug path (body.slug validated via isValidCustomSlug) is untouched.

The 40-char cap + -XXXX keeps generated slugs ≤ 45 chars, well under the 48-char ceiling enforced by SLUG_REGEX. A new invariant test asserts every generated slug passes isValidCustomSlug across 15 representative inputs.

Examples (verified locally against wrangler dev)

Title Slug
Q1 Budget Report q1-budget-report-cd51
(none) dawn-edge-03fa (fallback)
Café Menu cafe-menu-4545 (NFKD strip)
!!! / falls back to adjective-noun
Preview release falls back (reserved preview- guard)
200-char title truncated to 45 chars, still valid
same title twice distinct hex suffixes
slug: "my-custom-name" my-custom-name (custom path unchanged)

Note on title visibility

Titles will now appear in URLs. This is consistent with the "pages worth sharing" framing, but worth flagging — anyone publishing with sensitive titles can omit title to keep the current opaque slug, or pass an explicit slug.

Test plan

  • pnpm test — 149/149 pass (3 new test groups in slug.test.ts: title derivation, preview-guard, broad invariant across 15 titles)
  • pnpm typecheck — clean across worker, cli, mcp
  • pnpm test:e2e — 12/12 pass in the Cloudflare Workers runtime (custom-slug + untitled paths still work end-to-end)
  • pnpm build — clean dry-run deploy
  • Manual end-to-end against wrangler dev for all the cases in the table above

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