- API (api/src/auth.ts): scrypt password hashes; random session tokens stored only as SHA-256;
30-day sliding sessions; rate limits on sign-in (per IP and per email) and sign-up; changing the
password signs out other devices; deleting the account removes its data.
- Site: /signup, /signin (returns to the page the reader came from), /account; header link; plain
forms, no JavaScript needed. Session in an HTTP-only, SameSite=Lax cookie (Secure over HTTPS).
- CSRF: Astro's origin check, with the site's hostnames listed (SITE_HOSTS) so its own form posts
pass and other sites' are refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Selecting reading text shows a menu by the selection: معنی (word sidebar, single words),
تلاش (search Divan, phrases quoted), کاپی (text with poet, title and link), شیئر (link to the
page with the selection highlighted via ?hl=; native share sheet where available), قرآن
(tanzil.net), گوگل. Escape or clearing the selection closes it; no layout shift.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Panel folds the extras (more meanings, examples, long etymologies, long word lists). 175 MB in PostgreSQL.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- readings: one spelling, different short vowels (ملک: مَلَک، مَلِک، مِلک، مُلک), each with form,
transliteration, IPA, audio and meanings
- always: same consonants with other long vowels (consonant-skeleton regex)
- not found: inflection stems (آنکھوں -> آنکھ, جاتے -> جانا), prefix regex, trigram similarity
- Persian/Arabic words with no Urdu entry: Urdu translations via English first, then English, then
their own language; filler glosses (especially, usually…) dropped
- punctuation, dashes and spaces dropped from selected words and lookup keys; clean titles
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- en.wiktionary entries via kaikki.org (meanings, IPA, transliteration, audio, etymology, synonyms)
- ur./fa./ar.wiktionary dumps for meanings in each language (incl. more Urdu entry formats)
- English->Urdu pivot table from Urdu entries' glosses and ur.wiktionary's English entries
- dict-sync.ts: re-imports sources when upstream publishes new files, applies daily recent changes;
run from deploy/sync.sh
- lookups now read the database (2-7 ms) instead of calling Wikimedia live
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Urdu, Persian and Arabic Wiktionaries in that order, each labelled; English meanings, IPA,
transliteration and audio from en.wiktionary; Urdu equivalents pivoted through English when Urdu
Wiktionary has no entry. Cached in PostgreSQL for 30 days. Left panel on wide screens, bottom
sheet on phones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- @fontsource/noto-naskh-arabic and noto-nastaliq-urdu bundled with the site; no Google
Fonts request (Brave Shields blocked it, so the switch had nothing to switch to)
- ?font=nastaliq|naskh sets the reading font (shareable links)
Validated: both fonts render from local files in headless Chromium; no googleapis requests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- poets.pin_order; editorial list in db/featured.sql, applied after every import
- home page shows the pinned row first, like Ganjoor
- Faiz is not included: his work is under copyright until 2035, so not in divan-data
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- web/: server-rendered Astro over the Node API: home (poets by Hijri century), poet
(intro + sections), category (numbered contents), poem (couplets, prev/next, source),
search (paged); Naskh default with Nastaliq toggle, light/dark, Urdu digits, RTL, mobile
- api: section counts include nested categories
- README: how to run v2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>