@geekity/cms 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/README.md +170 -4
  2. package/admin/pages/account/login.njk +3 -0
  3. package/admin/pages/documents/editor.njk +7 -0
  4. package/admin/pages/indieauth/consent.njk +51 -0
  5. package/admin/pages/indieauth/refused.njk +11 -0
  6. package/admin/pages/settings/general.njk +9 -0
  7. package/admin/pages/settings/reading.njk +93 -0
  8. package/admin/pages/users/apps.njk +74 -0
  9. package/admin/pages/users/edit.njk +12 -0
  10. package/admin/static/admin.css +27 -0
  11. package/dist/admin/accounts.d.ts +3 -0
  12. package/dist/admin/accounts.d.ts.map +1 -1
  13. package/dist/admin/accounts.js +5 -0
  14. package/dist/admin/accounts.js.map +1 -1
  15. package/dist/admin/documents.d.ts +2 -0
  16. package/dist/admin/documents.d.ts.map +1 -1
  17. package/dist/admin/documents.js +17 -1
  18. package/dist/admin/documents.js.map +1 -1
  19. package/dist/admin/headers.d.ts +5 -1
  20. package/dist/admin/headers.d.ts.map +1 -1
  21. package/dist/admin/headers.js +7 -3
  22. package/dist/admin/headers.js.map +1 -1
  23. package/dist/admin/menu.d.ts.map +1 -1
  24. package/dist/admin/menu.js +2 -1
  25. package/dist/admin/menu.js.map +1 -1
  26. package/dist/admin/routes.d.ts.map +1 -1
  27. package/dist/admin/routes.js +48 -5
  28. package/dist/admin/routes.js.map +1 -1
  29. package/dist/admin/settings-general.js +1 -1
  30. package/dist/admin/settings-general.js.map +1 -1
  31. package/dist/admin/settings-reading.d.ts.map +1 -1
  32. package/dist/admin/settings-reading.js +15 -1
  33. package/dist/admin/settings-reading.js.map +1 -1
  34. package/dist/admin/settings.d.ts +79 -2
  35. package/dist/admin/settings.d.ts.map +1 -1
  36. package/dist/admin/settings.js +168 -2
  37. package/dist/admin/settings.js.map +1 -1
  38. package/dist/admin/templates.d.ts +3 -0
  39. package/dist/admin/templates.d.ts.map +1 -1
  40. package/dist/admin/templates.js +3 -0
  41. package/dist/admin/templates.js.map +1 -1
  42. package/dist/admin/users.d.ts +8 -0
  43. package/dist/admin/users.d.ts.map +1 -1
  44. package/dist/admin/users.js +9 -0
  45. package/dist/admin/users.js.map +1 -1
  46. package/dist/config.d.ts +30 -0
  47. package/dist/config.d.ts.map +1 -1
  48. package/dist/config.js +1 -0
  49. package/dist/config.js.map +1 -1
  50. package/dist/env.d.ts +14 -0
  51. package/dist/env.d.ts.map +1 -1
  52. package/dist/federation/article.d.ts.map +1 -1
  53. package/dist/federation/article.js +18 -5
  54. package/dist/federation/article.js.map +1 -1
  55. package/dist/images/icons.d.ts +44 -25
  56. package/dist/images/icons.d.ts.map +1 -1
  57. package/dist/images/icons.js +205 -60
  58. package/dist/images/icons.js.map +1 -1
  59. package/dist/images/index.d.ts +2 -2
  60. package/dist/images/index.d.ts.map +1 -1
  61. package/dist/images/index.js +1 -1
  62. package/dist/images/index.js.map +1 -1
  63. package/dist/images/markup.d.ts +14 -0
  64. package/dist/images/markup.d.ts.map +1 -1
  65. package/dist/images/markup.js +16 -11
  66. package/dist/images/markup.js.map +1 -1
  67. package/dist/images/variants.d.ts.map +1 -1
  68. package/dist/images/variants.js +3 -4
  69. package/dist/images/variants.js.map +1 -1
  70. package/dist/index.d.ts +14 -4
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +28 -1
  73. package/dist/index.js.map +1 -1
  74. package/dist/indexnow.d.ts +34 -0
  75. package/dist/indexnow.d.ts.map +1 -0
  76. package/dist/indexnow.js +141 -0
  77. package/dist/indexnow.js.map +1 -0
  78. package/dist/indieauth/bearer.d.ts +39 -0
  79. package/dist/indieauth/bearer.d.ts.map +1 -0
  80. package/dist/indieauth/bearer.js +63 -0
  81. package/dist/indieauth/bearer.js.map +1 -0
  82. package/dist/indieauth/client.d.ts +61 -0
  83. package/dist/indieauth/client.d.ts.map +1 -0
  84. package/dist/indieauth/client.js +139 -0
  85. package/dist/indieauth/client.js.map +1 -0
  86. package/dist/indieauth/connected-apps.d.ts +23 -0
  87. package/dist/indieauth/connected-apps.d.ts.map +1 -0
  88. package/dist/indieauth/connected-apps.js +73 -0
  89. package/dist/indieauth/connected-apps.js.map +1 -0
  90. package/dist/indieauth/consent.d.ts +28 -0
  91. package/dist/indieauth/consent.d.ts.map +1 -0
  92. package/dist/indieauth/consent.js +185 -0
  93. package/dist/indieauth/consent.js.map +1 -0
  94. package/dist/indieauth/discovery.d.ts +87 -0
  95. package/dist/indieauth/discovery.d.ts.map +1 -0
  96. package/dist/indieauth/discovery.js +127 -0
  97. package/dist/indieauth/discovery.js.map +1 -0
  98. package/dist/indieauth/grants.d.ts +57 -0
  99. package/dist/indieauth/grants.d.ts.map +1 -0
  100. package/dist/indieauth/grants.js +35 -0
  101. package/dist/indieauth/grants.js.map +1 -0
  102. package/dist/indieauth/identity.d.ts +36 -0
  103. package/dist/indieauth/identity.d.ts.map +1 -0
  104. package/dist/indieauth/identity.js +78 -0
  105. package/dist/indieauth/identity.js.map +1 -0
  106. package/dist/indieauth/redeem.d.ts +47 -0
  107. package/dist/indieauth/redeem.d.ts.map +1 -0
  108. package/dist/indieauth/redeem.js +69 -0
  109. package/dist/indieauth/redeem.js.map +1 -0
  110. package/dist/indieauth/request.d.ts +47 -0
  111. package/dist/indieauth/request.d.ts.map +1 -0
  112. package/dist/indieauth/request.js +104 -0
  113. package/dist/indieauth/request.js.map +1 -0
  114. package/dist/indieauth/token.d.ts +19 -0
  115. package/dist/indieauth/token.d.ts.map +1 -0
  116. package/dist/indieauth/token.js +110 -0
  117. package/dist/indieauth/token.js.map +1 -0
  118. package/dist/indieauth/tokens.d.ts +131 -0
  119. package/dist/indieauth/tokens.d.ts.map +1 -0
  120. package/dist/indieauth/tokens.js +205 -0
  121. package/dist/indieauth/tokens.js.map +1 -0
  122. package/dist/web/archive.d.ts +1 -1
  123. package/dist/web/archive.d.ts.map +1 -1
  124. package/dist/web/archive.js +3 -2
  125. package/dist/web/archive.js.map +1 -1
  126. package/dist/web/context.d.ts +25 -0
  127. package/dist/web/context.d.ts.map +1 -1
  128. package/dist/web/context.js +18 -0
  129. package/dist/web/context.js.map +1 -1
  130. package/dist/web/feed-atom.d.ts.map +1 -1
  131. package/dist/web/feed-atom.js +3 -1
  132. package/dist/web/feed-atom.js.map +1 -1
  133. package/dist/web/feed-item.d.ts +11 -2
  134. package/dist/web/feed-item.d.ts.map +1 -1
  135. package/dist/web/feed-item.js +9 -3
  136. package/dist/web/feed-item.js.map +1 -1
  137. package/dist/web/feed-json.d.ts +4 -0
  138. package/dist/web/feed-json.d.ts.map +1 -1
  139. package/dist/web/feed-json.js +4 -1
  140. package/dist/web/feed-json.js.map +1 -1
  141. package/dist/web/feed-rss.d.ts.map +1 -1
  142. package/dist/web/feed-rss.js +16 -3
  143. package/dist/web/feed-rss.js.map +1 -1
  144. package/dist/web/feed-source.d.ts +28 -0
  145. package/dist/web/feed-source.d.ts.map +1 -1
  146. package/dist/web/feed-source.js +31 -0
  147. package/dist/web/feed-source.js.map +1 -1
  148. package/dist/web/feed-xml.d.ts +2 -0
  149. package/dist/web/feed-xml.d.ts.map +1 -1
  150. package/dist/web/feed-xml.js +2 -0
  151. package/dist/web/feed-xml.js.map +1 -1
  152. package/dist/web/feeds.d.ts.map +1 -1
  153. package/dist/web/feeds.js +8 -1
  154. package/dist/web/feeds.js.map +1 -1
  155. package/dist/web/index.d.ts +3 -1
  156. package/dist/web/index.d.ts.map +1 -1
  157. package/dist/web/index.js +2 -1
  158. package/dist/web/index.js.map +1 -1
  159. package/dist/web/indexnow.d.ts +9 -0
  160. package/dist/web/indexnow.d.ts.map +1 -0
  161. package/dist/web/indexnow.js +27 -0
  162. package/dist/web/indexnow.js.map +1 -0
  163. package/dist/web/llms.d.ts +58 -0
  164. package/dist/web/llms.d.ts.map +1 -0
  165. package/dist/web/llms.js +91 -0
  166. package/dist/web/llms.js.map +1 -0
  167. package/dist/web/locale.d.ts +41 -0
  168. package/dist/web/locale.d.ts.map +1 -0
  169. package/dist/web/locale.js +56 -0
  170. package/dist/web/locale.js.map +1 -0
  171. package/dist/web/manifest.d.ts +50 -0
  172. package/dist/web/manifest.d.ts.map +1 -0
  173. package/dist/web/manifest.js +56 -0
  174. package/dist/web/manifest.js.map +1 -0
  175. package/dist/web/negotiate.d.ts.map +1 -1
  176. package/dist/web/negotiate.js +6 -0
  177. package/dist/web/negotiate.js.map +1 -1
  178. package/dist/web/render.d.ts +6 -1
  179. package/dist/web/render.d.ts.map +1 -1
  180. package/dist/web/render.js +41 -10
  181. package/dist/web/render.js.map +1 -1
  182. package/dist/web/robots.d.ts +89 -0
  183. package/dist/web/robots.d.ts.map +1 -0
  184. package/dist/web/robots.js +259 -0
  185. package/dist/web/robots.js.map +1 -0
  186. package/dist/web/routes.d.ts.map +1 -1
  187. package/dist/web/routes.js +105 -6
  188. package/dist/web/routes.js.map +1 -1
  189. package/dist/web/share-image.d.ts +51 -0
  190. package/dist/web/share-image.d.ts.map +1 -0
  191. package/dist/web/share-image.js +43 -0
  192. package/dist/web/share-image.js.map +1 -0
  193. package/dist/web/sitemap.d.ts +0 -26
  194. package/dist/web/sitemap.d.ts.map +1 -1
  195. package/dist/web/sitemap.js +0 -44
  196. package/dist/web/sitemap.js.map +1 -1
  197. package/dist/web/templates.d.ts +16 -9
  198. package/dist/web/templates.d.ts.map +1 -1
  199. package/dist/web/templates.js +83 -55
  200. package/dist/web/templates.js.map +1 -1
  201. package/dist/web/themes.d.ts +33 -0
  202. package/dist/web/themes.d.ts.map +1 -1
  203. package/dist/web/themes.js +57 -0
  204. package/dist/web/themes.js.map +1 -1
  205. package/dist/webmention/discovery.d.ts +4 -2
  206. package/dist/webmention/discovery.d.ts.map +1 -1
  207. package/dist/webmention/discovery.js +14 -8
  208. package/dist/webmention/discovery.js.map +1 -1
  209. package/dist/webmention/fetch-public.d.ts +2 -0
  210. package/dist/webmention/fetch-public.d.ts.map +1 -1
  211. package/dist/webmention/fetch-public.js +1 -1
  212. package/dist/webmention/fetch-public.js.map +1 -1
  213. package/package.json +1 -1
  214. package/themes/default/README.md +119 -29
  215. package/themes/default/layouts/base.njk +95 -16
  216. package/themes/default/layouts/front-page.njk +6 -1
  217. package/themes/default/layouts/home.njk +10 -0
  218. package/themes/default/layouts/page.njk +4 -3
  219. package/themes/default/layouts/post.njk +5 -4
  220. package/themes/default/layouts/search.njk +4 -5
  221. package/themes/default/partials/archive.njk +3 -1
  222. package/themes/default/partials/bio.njk +9 -2
  223. package/themes/default/partials/breadcrumbs.njk +20 -0
  224. package/themes/default/partials/conversation.njk +4 -1
  225. package/themes/default/partials/jsonld.njk +19 -4
  226. package/themes/default/partials/kicker.njk +6 -4
  227. package/themes/default/partials/lang.njk +7 -0
  228. package/themes/default/partials/post-list.njk +5 -3
  229. package/themes/default/partials/reply-context.njk +4 -2
  230. package/themes/default/src/style.css +14 -0
  231. package/themes/default/static/style.css +53 -0
  232. package/themes/default/theme.json +2 -0
package/README.md CHANGED
@@ -370,6 +370,7 @@ the same directory reads all of it, and everything in it is meant to be public:
370
370
  | `data/mail.json` | The mail credential: a Brevo API key, an SMTP connection, or both. Mode `0600`. |
371
371
  | `data/notification-secret` | What signs the one-click links in a notification. Mode `0600`. Losing it kills every link already in an inbox and nothing else. |
372
372
  | `data/comment-optouts.json` | The addresses that have unsubscribed from reply notices. Mode `0600`. |
373
+ | `data/indieauth-tokens.json` | A SHA-256 hash of each IndieAuth access and refresh token, with its user, app, scopes and expiry (decision-24). Mode `0600`. |
373
374
  | `data/notification-digests.json` | When each user was last sent a digest. Mode `0600`. Losing it sends one digest early and nothing worse. |
374
375
  | `data/wordpress-activitypub.json` | When each WordPress compatibility path was last asked for. Losing it resets the answer the switch is watched by. |
375
376
 
@@ -535,6 +536,12 @@ arrives as its title, its excerpt and a link, so it sends `name` and a
535
536
  would show a `summary` as a content warning, so a note sends neither and puts a
536
537
  title its text does not open with at the top of its content.
537
538
 
539
+ Both carry their text twice: `content` as it always was, and `contentMap` keyed
540
+ by the post's language, with `summaryMap` beside an `Article`'s `summary`. The
541
+ language is the post's `lang` front matter when it names one, and the site's
542
+ `language` otherwise, so a client can filter and translate by it. Mastodon
543
+ reads a status's language from that key.
544
+
538
545
  An author can choose the type for one post in its front matter:
539
546
 
540
547
  ```yaml
@@ -1417,6 +1424,7 @@ says otherwise.
1417
1424
  | Other actors who liked, boosted, answered or quoted: handle, display name, avatar URL, profile URL | `data/geekity.db`, fetched from their actor document | A cache. Refetched weekly while the inbox log names them. |
1418
1425
  | Remote avatars, shrunk | `data/avatars/` | Deleted by the avatar sweep once nothing shown names them. |
1419
1426
  | Users: username, email, argon2id password hash, profile | `data/users.json`, mode `0600` | Until the user is deleted. |
1427
+ | The apps a user signed in to with IndieAuth: app, scopes, hashes of its tokens, when they expire | `data/indieauth-tokens.json`, mode `0600` | Until the user is deleted, or 60 days after the app last refreshed. |
1420
1428
  | An index of all of the above, and sessions, reset tokens and spent link tokens | `data/geekity.db` | A cache of the files. Sessions and tokens are pruned when they expire. |
1421
1429
  | Client addresses in the rate limits | Memory | Until the window passes or the site restarts. |
1422
1430
  | Client addresses in the access log | stdout, and whatever collects it | Only with `accessLogAddress` on. The collector keeps them. |
@@ -1686,7 +1694,7 @@ shadow the login form.
1686
1694
  | `/admin/appearance/themes` | Appearance > Themes: the themes on disk. `POST` activates the one named. |
1687
1695
  | `/admin/tools` | Tools > Content index: what the index holds, and the button that rebuilds it. |
1688
1696
  | `/admin/tools/rebuild-index` | `POST` only. Offers the rebuild, then reads every file again on the live site. |
1689
- | `/admin/settings` | Settings > General: title, tagline, author, base URL, time zone, language. |
1697
+ | `/admin/settings` | Settings > General: title, tagline, author, base URL, time zone, language, locale. |
1690
1698
  | `/admin/settings/reading` | What the homepage displays, posts per page, the notify server. |
1691
1699
  | `/admin/settings/permalinks` | The tag and category bases, and the archive redirects already recorded. |
1692
1700
  | `/admin/settings/discussion` | Comments and the closing window, webmentions, and the Akismet key. |
@@ -1838,8 +1846,9 @@ at once cannot each keep half of what the other kept.
1838
1846
 
1839
1847
  The file carries `title`, `tagline`, `url`, `author`, `postsPerPage`,
1840
1848
  `homepage`, `postsPage`,
1841
- `timezone`, `language`, `tagBase`,
1842
- `categoryBase`, `notifyServer`, `webmentionsSend`, `webmentionsReceive`,
1849
+ `timezone`, `language`, `locale` (when it is set), `tagBase`,
1850
+ `categoryBase`, `notifyServer`, `feedUpdatePeriod`, `feedUpdateFrequency`,
1851
+ `webmentionsSend`, `webmentionsReceive`,
1843
1852
  `mailProvider`, `mailFromName`, `mailFromAddress`, `mailReplyTo`,
1844
1853
  `contactEmail`, `securityContacts`, `securityPolicy`, `securityLanguages`,
1845
1854
  `relays`, `menus` and `taxonomyRedirects`,
@@ -2354,6 +2363,8 @@ Booting mounts the public site on the app. The routes are:
2354
2363
  | `/sitemap.xml` | Every public URL, for a search engine. |
2355
2364
  | `/sitemap-{n}.xml` | One file of a sitemap too big to be a single one. |
2356
2365
  | `/robots.txt` | What a crawler may have, and where the sitemap is. |
2366
+ | `/llms.txt` | The site's pages and recent posts for a language model, each linked to its Markdown. See [below](#llmstxt). |
2367
+ | `/{key}.txt` | The IndexNow key, while the site has IndexNow on. See [below](#indexnow). |
2357
2368
  | `/.well-known/security.txt` | Where to report a vulnerability; a 404 until a security contact is set. See [above](#securitytxt-and-change-password). |
2358
2369
  | `/.well-known/change-password` | A redirect to the signed-in user's change-password form, or to the login form. |
2359
2370
  | `/_geekity/comments` | `POST` only. Where the comment form under a post submits. |
@@ -2705,6 +2716,10 @@ without changing the document, so a development server would otherwise answer
2705
2716
  `304` with a page that had already moved on. The `.md` and `.json`
2706
2717
  representations are validated either way.
2707
2718
 
2719
+ Every representation but the HTML carries `X-Robots-Tag: noindex`, whether it
2720
+ was asked for by extension or by `Accept`. They say what the page says, and a
2721
+ search engine that indexed them would list one page two or three times.
2722
+
2708
2723
  Adding a representation — an ActivityStreams object, say — means adding it to
2709
2724
  `Representation` in `src/web/negotiate.ts` with its media type and, if it wants
2710
2725
  one, its extension. The selection, the `Link` alternates, the `ETag` and the
@@ -2748,6 +2763,16 @@ post on a site that publishes several.
2748
2763
  { "title": "My Site", "tagline": "Notes", "author": "Me", "feedSize": 20 }
2749
2764
  ```
2750
2765
 
2766
+ Every RSS feed, the comments feeds included, tells a reader how often to poll
2767
+ it with the Syndication module's `sy:updatePeriod` and `sy:updateFrequency`.
2768
+ Settings → Reading sets both, as `feedUpdatePeriod` (`hourly`, `daily`,
2769
+ `weekly`, `monthly` or `yearly`) and `feedUpdateFrequency` (a whole number, 1 or
2770
+ more) in `site.json`. The default is `hourly` and `1`, which is what WordPress
2771
+ declares, so the subscribers of a migrated site keep polling as they did. A
2772
+ reader may back off from a feed that stays quiet much longer than it says, so
2773
+ a site that posts weekly does better to say `weekly`. Atom and JSON Feed have no
2774
+ element for it.
2775
+
2751
2776
  ### What every format says about a post
2752
2777
 
2753
2778
  The three formats render one **feed item**, derived once per post, rather than
@@ -2802,6 +2827,13 @@ post that is not a reply, or whose `in-reply-to` is not such a URL, carries
2802
2827
  neither. RSS 2.0 has no equivalent element, so an RSS item for a reply is
2803
2828
  written the same as any other.
2804
2829
 
2830
+ **Languages.** Every feed declares the site's `language` once: RSS as the
2831
+ channel's `language`, Atom as the feed's `xml:lang` and JSON Feed as its
2832
+ `language`. A post whose `lang` front matter names another language says so on
2833
+ its own item: RSS as `dc:language`, Atom as `xml:lang` on the `entry` and JSON
2834
+ Feed as the item's `language`. A post in the site's language, or whose `lang`
2835
+ is not a language tag, adds nothing.
2836
+
2805
2837
  ### RSS 2.0
2806
2838
 
2807
2839
  The channel carries `title`, `link`, `description` (the tagline), `language`
@@ -3096,7 +3128,7 @@ holding its own slice and dated by the newest URL in it. The address a search
3096
3128
  engine holds does not change, which is the point of the index living there.
3097
3129
  While the whole sitemap fits in one file the children name nothing and 404.
3098
3130
 
3099
- `/robots.txt` is short:
3131
+ `/robots.txt` starts short:
3100
3132
 
3101
3133
  ```
3102
3134
  User-agent: *
@@ -3111,6 +3143,44 @@ fetched, they carry the same
3111
3143
  content as the pages that link to them, and a crawler that follows one gets
3112
3144
  JSON it will ignore.
3113
3145
 
3146
+ The Crawlers section of Settings → Reading adds to it, and writes what it sets
3147
+ to `site.json`:
3148
+
3149
+ | Setting | `site.json` key | What the file gains |
3150
+ | --------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3151
+ | AI crawlers | `aiCrawlers` | `allow` (the default) adds nothing. `block-training` adds a `Disallow: /` group for each training crawler: GPTBot, ClaudeBot, anthropic-ai, Google-Extended, Applebot-Extended, Bytespider, CCBot and meta-externalagent. `block-all` also blocks the retrieval crawlers: OAI-SearchBot, ChatGPT-User, PerplexityBot, Perplexity-User, Claude-SearchBot, Claude-User, meta-webindexer and meta-externalfetcher. |
3152
+ | Content signals | `contentSignalSearch`, `contentSignalAiInput`, `contentSignalAiTrain` | Each `yes`, `no` or empty. The ones set become one line, such as `Content-Signal: search=yes, ai-input=yes, ai-train=no`. |
3153
+ | More robots.txt rules | `robotsRules` | Groups of the site's own, one line per array entry: `User-agent`, then `Allow`, `Disallow`, `Crawl-delay`, `Content-Signal` or `Sitemap` lines. |
3154
+
3155
+ A crawler obeys only the one group that names it (RFC 9309), so the CMS puts
3156
+ `Disallow: /admin/` and the content signal into every group, its own and the
3157
+ site's, unless the group already disallows everything or carries a signal of
3158
+ its own. The form refuses a line that is not a robots.txt field, a rule with no
3159
+ `User-agent` above it, and an `Allow` under `/admin/`; a hand edit of
3160
+ `site.json` that does any of these loses that line. The site's own `Sitemap:`
3161
+ line is always there.
3162
+
3163
+ For example, `block-training`, `ai-train` set to `no` and a rule of
3164
+ `User-agent: SlowBot` / `Crawl-delay: 10` serve:
3165
+
3166
+ ```
3167
+ User-agent: *
3168
+ Disallow: /admin/
3169
+ Content-Signal: ai-train=no
3170
+
3171
+ User-agent: GPTBot
3172
+ Disallow: /
3173
+
3174
+ …one group per training crawler…
3175
+
3176
+ User-agent: SlowBot
3177
+ Disallow: /admin/
3178
+ Crawl-delay: 10
3179
+ Content-Signal: ai-train=no
3180
+
3181
+ Sitemap: https://example.com/sitemap.xml
3182
+ ```
3183
+
3114
3184
  Both are registered routes rather than anything resolved from the content
3115
3185
  index, so a document permalinked at `/sitemap.xml` cannot take the URL a
3116
3186
  search engine polls, and both carry an `ETag` and answer a conditional request
@@ -3120,6 +3190,102 @@ robots without one, because nothing dates it.
3120
3190
  Nothing links the sitemap from a page: `robots.txt` names it, which is where a
3121
3191
  crawler looks.
3122
3192
 
3193
+ ## llms.txt
3194
+
3195
+ `/llms.txt` describes the site for a language model, in the
3196
+ [llms.txt](https://llmstxt.org/) format. It holds the site's title as a heading
3197
+ and its tagline as a quote. Then it lists every public page by title and the
3198
+ posts the feeds carry, newest first. Each entry links to the document's
3199
+ Markdown, which is what a model reads best:
3200
+
3201
+ ```markdown
3202
+ # Field Notes
3203
+
3204
+ > Notes from the field.
3205
+
3206
+ ## Pages
3207
+
3208
+ - [About](https://example.com/about/index.md): Who writes this.
3209
+
3210
+ ## Recent posts
3211
+
3212
+ - [Third post](https://example.com/third/index.md)
3213
+ ```
3214
+
3215
+ A document's `description` follows its link. A static homepage is listed at
3216
+ `/index.md`, because `/` is where it is published. The file is served as
3217
+ `text/markdown` and carries an `ETag` and a `Last-Modified`, the newest date
3218
+ among its entries. It answers a conditional request with 304, as the sitemap
3219
+ does.
3220
+
3221
+ The home page advertises the file twice. The response carries
3222
+ `Link: </llms.txt>; rel="describedby"; type="text/markdown"`, for a tool that
3223
+ reads no HTML. The default theme's head carries
3224
+ `<link rel="describedby" type="text/markdown" href="/llms.txt">`. A theme
3225
+ gets the path as `llmsTxt` while the site serves the file.
3226
+
3227
+ To write the file yourself, put it at `content/llms.txt`. The CMS serves it
3228
+ exactly as written in place of the generated one, dated by the file. To serve
3229
+ no file at all, clear **Serve /llms.txt** under Settings → Reading. This
3230
+ writes `"llmsTxt": false` to `site.json`. `/llms.txt` then answers 404, even
3231
+ when `content/llms.txt` exists, and the home page stops advertising it.
3232
+
3233
+ ## IndexNow
3234
+
3235
+ [IndexNow](https://www.indexnow.org/) gets a changed URL recrawled by Bing,
3236
+ Yandex, Naver, Seznam and the other engines that share it within minutes,
3237
+ instead of on their next visit. It is off by default, because it sends the
3238
+ site's URLs to a third party. To turn it on, select **Submit changes to
3239
+ IndexNow** under Settings → Reading.
3240
+
3241
+ The first time you turn it on, the CMS generates a key of 32 hex digits and
3242
+ writes it to `site.json` as `indexNowKey`, beside `"indexNow": true`. The site
3243
+ then serves the key at `/{key}.txt` as plain text, which is how an engine
3244
+ checks that the submissions are yours. Turning IndexNow off takes the file away
3245
+ and keeps the key, so turning it back on reuses the key the engines already
3246
+ checked. To change the key, write a new one of 8 to 128 letters, digits or
3247
+ dashes to `indexNowKey`. A key that does not fit that pattern counts as none,
3248
+ and the site sends nothing.
3249
+
3250
+ When a post or a page is published, changed, moved or deleted, the CMS submits
3251
+ its URL. A move submits the old URL and the new one. Unpublishing, trashing and
3252
+ deleting submit the URL that went away. The changes of the next ten seconds go
3253
+ out together as one `POST` to `https://api.indexnow.org/indexnow`:
3254
+
3255
+ ```json
3256
+ {
3257
+ "host": "example.com",
3258
+ "key": "0123456789abcdef0123456789abcdef",
3259
+ "keyLocation": "https://example.com/0123456789abcdef0123456789abcdef.txt",
3260
+ "urlList": ["https://example.com/hello/"]
3261
+ }
3262
+ ```
3263
+
3264
+ A network failure, a 429 or a 5xx answer is tried again after ten seconds, then
3265
+ after forty. Any other refusal, such as a 403 for a key the engine could not
3266
+ fetch, is not. A batch that still fails is logged as a warning, and the post
3267
+ stays published.
3268
+
3269
+ Nothing is sent for a draft or a scheduled post, for the boot scan, or while
3270
+ the base URL's host is local: `localhost`, a `.local` name, or a private IP
3271
+ address.
3272
+
3273
+ A site can change how the CMS sends with `indexNow` in its config. Every field
3274
+ is optional:
3275
+
3276
+ ```ts
3277
+ export default defineConfig({
3278
+ indexNow: {
3279
+ fetch, // what submits the URLs; a test names one
3280
+ endpoint: 'https://www.bing.com/indexnow',
3281
+ batchMs: 10_000,
3282
+ attempts: 3,
3283
+ backoffMs: (attempt) => attempt * attempt * 10_000,
3284
+ logger: console,
3285
+ },
3286
+ });
3287
+ ```
3288
+
3123
3289
  ## Theme overrides
3124
3290
 
3125
3291
  A site's themes live one directory per theme under `themesDir` (`themes/` by
@@ -12,6 +12,9 @@
12
12
 
13
13
  <form method="post" action="{{ loginUrl }}">
14
14
  <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
15
+ {% if returnTo %}
16
+ <input type="hidden" name="return_to" value="{{ returnTo }}" />
17
+ {% endif %}
15
18
 
16
19
  {{ field.text('username', 'username', 'Username', username,
17
20
  autocomplete='username', required=true, autofocus=true) }}
@@ -103,6 +103,13 @@
103
103
  <label for="editor-description">Description</label>
104
104
  <input id="editor-description" name="description" type="text" value="{{ form.description }}" />
105
105
 
106
+ {#- The `lang` front matter (TASK-154): a post or page written in another
107
+ language than the site's says so, for screen readers, translation
108
+ and fediverse language filters. -#}
109
+ <label for="editor-lang">Language</label>
110
+ <input id="editor-lang" name="lang" type="text" value="{{ form.lang }}" autocomplete="off" spellcheck="false" aria-describedby="editor-lang-hint" />
111
+ <p class="admin-hint" id="editor-lang-hint">A language tag, such as fr or pt-BR. Leave it empty for the site’s language, {{ siteLanguage }}.</p>
112
+
106
113
  {# Who the front matter says wrote this (TASK-67). A select of the site's
107
114
  users rather than a free box, because after decision-14 the value is a
108
115
  person rather than a string: it decides whose archive the post is on
@@ -0,0 +1,51 @@
1
+ {# The IndieAuth consent screen (TASK-158): an app wants to know who the
2
+ signed-in person is. A bare page like the login form, because the person
3
+ arrived from another site and has one thing to decide here. #}
4
+ {% extends "layouts/base.njk" %}
5
+ {% import "components/fields.njk" as field %}
6
+
7
+ {% block title %}Sign in to {{ client.name }}{% endblock %}
8
+
9
+ {% block content %}
10
+ {# A data: URI the server fetched, never the client's URL (TASK-190). #}
11
+ {% if client.logo %}
12
+ <img class="admin-consent-logo" src="{{ client.logo }}" alt="" width="64" height="64" />
13
+ {% endif %}
14
+ <h1>Sign in to {{ client.name }}?</h1>
15
+
16
+ <dl class="admin-consent">
17
+ <dt>App</dt>
18
+ <dd>{{ client.name }}{% if client.named %} <span class="admin-hint">({{ client.id }})</span>{% endif %}</dd>
19
+ <dt>Sends you back to</dt>
20
+ <dd>{{ redirectHost }}</dd>
21
+ <dt>Signs you in as</dt>
22
+ <dd>{{ identity }}</dd>
23
+ {% if resource %}
24
+ <dt>For use at</dt>
25
+ <dd>{{ resource }}</dd>
26
+ {% endif %}
27
+ </dl>
28
+
29
+ {% if loopback %}
30
+ <p class="admin-hint">This app runs on your own computer or network. Approve only if you started this sign-in yourself.</p>
31
+ {% endif %}
32
+
33
+ <form method="post" action="{{ consentUrl }}">
34
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
35
+ <input type="hidden" name="request" value="{{ pending }}" />
36
+
37
+ {% if scopes | length %}
38
+ <fieldset>
39
+ <legend>It also asks for</legend>
40
+ {% for scope in scopes %}
41
+ {{ field.checkbox('scope-' ~ scope.name, 'scope', scope.label, checked=true, value=scope.name) }}
42
+ {% endfor %}
43
+ </fieldset>
44
+ {% else %}
45
+ <p>It asks only who you are.</p>
46
+ {% endif %}
47
+
48
+ <button type="submit" name="decision" value="approve">Approve</button>
49
+ <button type="submit" name="decision" value="deny">Deny</button>
50
+ </form>
51
+ {% endblock %}
@@ -0,0 +1,11 @@
1
+ {# A sign-in request that cannot go ahead (TASK-158). Shown rather than
2
+ redirected, because the fault is in the address it would redirect to. #}
3
+ {% extends "layouts/base.njk" %}
4
+
5
+ {% block title %}Sign-in refused{% endblock %}
6
+
7
+ {% block content %}
8
+ <h1>This sign-in cannot go ahead</h1>
9
+ <p>{{ message }}</p>
10
+ <p>Go back to the app and try again. If it keeps happening, the app may be set up wrongly.</p>
11
+ {% endblock %}
@@ -7,6 +7,7 @@
7
7
  {{ field.problem('settings-base-url', problems.baseUrl) }}
8
8
  {{ field.problem('settings-timezone', problems.timezone) }}
9
9
  {{ field.problem('settings-language', problems.language) }}
10
+ {{ field.problem('settings-locale', problems.locale) }}
10
11
  {% endblock %}
11
12
 
12
13
  {% block settingsFields %}
@@ -19,6 +20,10 @@
19
20
  {{ field.text('settings-author', fields.author, 'Author', form.author,
20
21
  hint='The name on the feeds.') }}
21
22
 
23
+ {% set soloAuthorHint %}The homepage speaks for the author: it shows their bio and links, and claims their author archive and profiles with <code>rel="me"</code>. Leave it off for a site with more than one author.{% endset %}
24
+ {{ field.checkbox('settings-solo-author', fields.soloAuthor, 'Solo author blog',
25
+ checked=form.soloAuthor, hint=soloAuthorHint) }}
26
+
22
27
  {% set baseUrlHint %}In effect: <code>{{ baseUrlInEffect }}</code>. {{ baseUrlNote }}{% endset %}
23
28
  {{ field.text('settings-base-url', fields.baseUrl, 'Base URL', form.baseUrl,
24
29
  error=problems.baseUrl, hint=baseUrlHint, inputmode='url',
@@ -31,6 +36,10 @@
31
36
  {% set languageHint %}A BCP 47 tag, such as <code>en</code> or <code>en-GB</code>. It is the page's <code>lang</code> and the feeds' language.{% endset %}
32
37
  {{ field.text('settings-language', fields.language, 'Language', form.language,
33
38
  error=problems.language, hint=languageHint, required=true) }}
39
+
40
+ {% set localeHint %}How the public site writes dates and counts, such as <code>en-US</code> for <code>September 2, 2026</code>. Leave it empty to follow the language.{% endset %}
41
+ {{ field.text('settings-locale', fields.locale, 'Locale', form.locale,
42
+ error=problems.locale, hint=localeHint) }}
34
43
  {% endblock %}
35
44
 
36
45
  {% block settingsPanels %}{% endblock %}
@@ -9,6 +9,13 @@
9
9
  {{ field.problem('settings-posts-page', problems.postsPage) }}
10
10
  {{ field.problem('settings-posts-per-page', problems.postsPerPage) }}
11
11
  {{ field.problem('settings-notify-server', problems.notifyServer) }}
12
+ {{ field.problem('settings-feed-update-period', problems.feedUpdatePeriod) }}
13
+ {{ field.problem('settings-feed-update-frequency', problems.feedUpdateFrequency) }}
14
+ {{ field.problem('settings-ai-crawlers', problems.aiCrawlers) }}
15
+ {{ field.problem('settings-content-signal-search', problems.contentSignalSearch) }}
16
+ {{ field.problem('settings-content-signal-ai-input', problems.contentSignalAiInput) }}
17
+ {{ field.problem('settings-content-signal-ai-train', problems.contentSignalAiTrain) }}
18
+ {{ field.problem('settings-robots-rules', problems.robotsRules) }}
12
19
  {% endblock %}
13
20
 
14
21
  {% block settingsFields %}
@@ -68,4 +75,90 @@
68
75
  {% endset %}
69
76
  {{ field.text('settings-notify-server', fields.notifyServer, 'Notify server', form.notifyServer,
70
77
  error=problems.notifyServer, hint=notifyHint, inputmode='url') }}
78
+
79
+ {# TASK-152. The Syndication module's polling hint, which only RSS has an
80
+ element for. #}
81
+ {% set periodHint %}
82
+ How often RSS readers should check the feeds. Readers that see no new post
83
+ for much longer than this may check less often, so pick a pace the site keeps.
84
+ {% endset %}
85
+ {% call field.select('settings-feed-update-period', fields.feedUpdatePeriod, 'Feed update period',
86
+ error=problems.feedUpdatePeriod, hint=periodHint) %}
87
+ {% for option in [
88
+ ['hourly', 'Hourly'],
89
+ ['daily', 'Daily'],
90
+ ['weekly', 'Weekly'],
91
+ ['monthly', 'Monthly'],
92
+ ['yearly', 'Yearly']] %}
93
+ <option value="{{ option[0] }}"{% if option[0] == form.feedUpdatePeriod %} selected{% endif %}>{{ option[1] }}</option>
94
+ {% endfor %}
95
+ {% endcall %}
96
+
97
+ {{ field.text('settings-feed-update-frequency', fields.feedUpdateFrequency, 'Checks per period',
98
+ form.feedUpdateFrequency, error=problems.feedUpdateFrequency, inputmode='numeric', required=true,
99
+ hint='How many times in each period. Daily and 2 means twice a day.') }}
100
+
101
+ {# TASK-148. What /robots.txt tells crawlers beyond keeping them out of the
102
+ admin, which it does whatever is set here. #}
103
+ <h2>Crawlers</h2>
104
+
105
+ {% set aiHint %}
106
+ Training crawlers gather pages to train AI models. Retrieval crawlers fetch a
107
+ page when somebody asks an assistant about it, so blocking them also stops the
108
+ site being cited. Each choice writes its own groups into
109
+ <a href="/robots.txt"><code>/robots.txt</code></a>.
110
+ {% endset %}
111
+ {% call field.select('settings-ai-crawlers', fields.aiCrawlers, 'AI crawlers',
112
+ error=problems.aiCrawlers, hint=aiHint) %}
113
+ {% for option in [
114
+ ['allow', 'Allow all'],
115
+ ['block-training', 'Block training crawlers'],
116
+ ['block-all', 'Block all AI crawlers']] %}
117
+ <option value="{{ option[0] }}"{% if option[0] == form.aiCrawlers %} selected{% endif %}>{{ option[1] }}</option>
118
+ {% endfor %}
119
+ {% endcall %}
120
+
121
+ {% for signal in [
122
+ ['contentSignalSearch', 'settings-content-signal-search', 'Content signal: search',
123
+ 'Whether pages may be indexed and shown as search results.'],
124
+ ['contentSignalAiInput', 'settings-content-signal-ai-input', 'Content signal: AI input',
125
+ 'Whether pages may be fed to an AI model to answer a question.'],
126
+ ['contentSignalAiTrain', 'settings-content-signal-ai-train', 'Content signal: AI training',
127
+ 'Whether pages may be used to train or fine-tune an AI model.']] %}
128
+ {% call field.select(signal[1], fields[signal[0]], signal[2],
129
+ error=problems[signal[0]], hint=signal[3]) %}
130
+ {% for option in [['', 'Not said'], ['yes', 'Yes'], ['no', 'No']] %}
131
+ <option value="{{ option[0] }}"{% if option[0] == form[signal[0]] %} selected{% endif %}>{{ option[1] }}</option>
132
+ {% endfor %}
133
+ {% endcall %}
134
+ {% endfor %}
135
+
136
+ {% set rulesHint %}
137
+ More <code>robots.txt</code> groups, written as they would be in the file: one or
138
+ more <code>User-agent</code> lines, then <code>Allow</code>, <code>Disallow</code>,
139
+ <code>Crawl-delay</code> or <code>Content-Signal</code> lines. Every group still
140
+ keeps crawlers out of <code>/admin/</code>, and the sitemap is always named.
141
+ {% endset %}
142
+ {{ field.textarea('settings-robots-rules', fields.robotsRules, 'More robots.txt rules',
143
+ form.robotsRules, error=problems.robotsRules, hint=rulesHint,
144
+ rows='5', spellcheck='false') }}
145
+
146
+ {# TASK-149. The index for language models, beside the file for crawlers. #}
147
+ {% set llmsHint %}
148
+ <a href="/llms.txt"><code>/llms.txt</code></a> lists the site's pages and recent
149
+ posts, each linked to its Markdown, for AI tools to read. The home page points
150
+ to it. To write it yourself, put your own file at <code>content/llms.txt</code>.
151
+ {% endset %}
152
+ {{ field.checkbox('settings-llms-txt', fields.llmsTxt, 'Serve /llms.txt',
153
+ checked=form.llmsTxt, hint=llmsHint) }}
154
+
155
+ {# TASK-151. Telling the search engines, beside the files they read. #}
156
+ {% set indexNowHint %}
157
+ Tells Bing, Yandex, Naver, Seznam and the other IndexNow search engines about
158
+ every post or page you publish, change or delete, so they recrawl it within
159
+ minutes. Turning it on creates a key the site serves at
160
+ <code>/{key}.txt</code>. Nothing is sent while the site's URL is local.
161
+ {% endset %}
162
+ {{ field.checkbox('settings-index-now', fields.indexNow, 'Submit changes to IndexNow',
163
+ checked=form.indexNow, hint=indexNowHint) }}
71
164
  {% endblock %}
@@ -0,0 +1,74 @@
1
+ {# /admin/users/apps: the apps that can act as whoever is signed in (TASK-162).
2
+
3
+ Only your own connections, each with a Revoke button that names the app,
4
+ so a screen reader moving between buttons hears which one it is on. #}
5
+ {% extends "layouts/shell.njk" %}
6
+
7
+ {% block title %}Connected apps{% endblock %}
8
+
9
+ {% block content %}
10
+ <h1>Connected apps</h1>
11
+
12
+ {% if connections | length %}
13
+ <p class="admin-hint">
14
+ These apps signed in as you and can act as you, within the permissions
15
+ listed. An app that keeps using its connection stays connected; one left
16
+ unused is disconnected on the date shown. Revoking disconnects it now:
17
+ its next request is refused, and it has to ask you again.
18
+ </p>
19
+
20
+ <table class="admin-list">
21
+ <caption class="admin-visually-hidden">Connected apps</caption>
22
+ <thead>
23
+ <tr>
24
+ <th scope="col">App</th>
25
+ <th scope="col">Can</th>
26
+ <th scope="col">Connected</th>
27
+ <th scope="col">Last used</th>
28
+ <th scope="col">Expires</th>
29
+ <th scope="col">Actions</th>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ {% for connection in connections %}
34
+ <tr>
35
+ <td><a href="{{ connection.url }}">{{ connection.name }}</a></td>
36
+ <td>
37
+ <ul>
38
+ {% for scope in connection.scopes %}
39
+ <li>{{ scope }}</li>
40
+ {% else %}
41
+ <li>Confirm who you are</li>
42
+ {% endfor %}
43
+ </ul>
44
+ </td>
45
+ <td><time datetime="{{ connection.issued.iso }}">{{ connection.issued.text }}</time></td>
46
+ <td>
47
+ {% if connection.lastUsed %}
48
+ <time datetime="{{ connection.lastUsed.iso }}">{{ connection.lastUsed.text }}</time>
49
+ {% else %}
50
+ <span class="admin-status">Not yet</span>
51
+ {% endif %}
52
+ </td>
53
+ <td><time datetime="{{ connection.expires.iso }}">{{ connection.expires.text }}</time></td>
54
+ <td class="admin-actions">
55
+ <form method="post" action="{{ revokeUrl }}">
56
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
57
+ <input type="hidden" name="{{ connectionField }}" value="{{ connection.id }}" />
58
+ <button type="submit">Revoke {{ connection.name }}</button>
59
+ </form>
60
+ </td>
61
+ </tr>
62
+ {% endfor %}
63
+ </tbody>
64
+ </table>
65
+ {% else %}
66
+ <p>No apps are connected to your account.</p>
67
+ <p class="admin-hint">
68
+ An app connects here when you sign in to it with your site's address and
69
+ approve what it asks for: a Micropub app such as Quill that posts to
70
+ your site, or an MCP client such as an AI assistant. Each one you approve
71
+ is listed here, with a button to disconnect it.
72
+ </p>
73
+ {% endif %}
74
+ {% endblock %}
@@ -211,6 +211,18 @@
211
211
  whoever is signed in and means nothing on somebody else's screen.
212
212
  Resetting a colleague's password from under them is deliberately not
213
213
  offered — a fresh account is what that is for. #}
214
+ {# Only on your own page, as the screen it links to only ever lists your
215
+ own connections (TASK-162). #}
216
+ {% if account.you %}
217
+ <section class="admin-settings">
218
+ <h2>Connected apps</h2>
219
+ <p class="admin-hint">
220
+ Apps you signed in to with your site's address can act as you.
221
+ <a href="{{ connectedAppsUrl }}">Review or revoke them</a>.
222
+ </p>
223
+ </section>
224
+ {% endif %}
225
+
214
226
  {% if account.you %}
215
227
  <form class="admin-settings" id="change-password" method="post" action="{{ changePasswordUrl }}">
216
228
  <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
@@ -1347,3 +1347,30 @@ button[type='submit']:hover,
1347
1347
  background: var(--admin-surface);
1348
1348
  border: 1px solid var(--admin-border);
1349
1349
  }
1350
+
1351
+ /* The IndieAuth consent screen (TASK-158): who is asking, where the answer
1352
+ goes and who it names, as label and value pairs a person reads down. */
1353
+
1354
+ .admin-consent {
1355
+ display: grid;
1356
+ margin: 0 0 1.5rem;
1357
+ gap: 0.4rem 1.5rem;
1358
+ grid-template-columns: max-content 1fr;
1359
+ }
1360
+
1361
+ .admin-consent dt {
1362
+ color: var(--admin-muted);
1363
+ }
1364
+
1365
+ .admin-consent dd {
1366
+ margin: 0;
1367
+ overflow-wrap: anywhere;
1368
+ }
1369
+
1370
+ .admin-consent-logo {
1371
+ display: block;
1372
+ width: 4rem;
1373
+ height: 4rem;
1374
+ margin: 0 0 1rem;
1375
+ object-fit: contain;
1376
+ }
@@ -382,6 +382,9 @@ export declare class UnknownUserError extends Error {
382
382
  /**
383
383
  * Take a user out of the file. Returns `false` when there was nothing to take.
384
384
  *
385
+ * Their IndieAuth tokens go with them (TASK-160): a token is a file in
386
+ * `data/` too, so it is revoked here, where every caller deletes a user.
387
+ *
385
388
  * Their sessions are not ended here: sessions are in the database, and the
386
389
  * screen that deletes a user ends them itself. A session that outlives this —
387
390
  * one in a database restored from a backup, say — names a user the file no
@@ -1 +1 @@
1
- {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../src/admin/accounts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../src/admin/accounts.ts"],"names":[],"mappings":"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"}