@geekity/cms 0.3.0 → 0.5.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.
- package/README.md +2217 -214
- package/admin/components/fields.njk +165 -0
- package/admin/layouts/base.njk +1 -1
- package/admin/layouts/settings-page.njk +26 -0
- package/admin/layouts/shell.njk +17 -3
- package/admin/pages/account/forgot.njk +47 -0
- package/admin/pages/account/login.njk +26 -0
- package/admin/pages/account/reset.njk +38 -0
- package/admin/pages/account/setup.njk +28 -0
- package/admin/pages/appearance/themes.njk +69 -0
- package/admin/pages/comments/all.njk +133 -0
- package/admin/{layouts/dashboard.njk → pages/dashboard/home.njk} +8 -15
- package/admin/{layouts/document-conflict.njk → pages/documents/conflict.njk} +1 -0
- package/admin/{layouts/document-editor.njk → pages/documents/editor.njk} +75 -59
- package/admin/{layouts/document-list.njk → pages/documents/list.njk} +19 -2
- package/admin/pages/documents/taxonomy.njk +95 -0
- package/admin/pages/federation/followers.njk +238 -0
- package/admin/pages/federation/settings.njk +77 -0
- package/admin/pages/media/library.njk +160 -0
- package/admin/pages/messages/all.njk +110 -0
- package/admin/pages/navigation/menus.njk +129 -0
- package/admin/{layouts → pages}/placeholder.njk +5 -1
- package/admin/pages/settings/discussion.njk +99 -0
- package/admin/pages/settings/email.njk +203 -0
- package/admin/pages/settings/general.njk +29 -0
- package/admin/pages/settings/permalinks.njk +50 -0
- package/admin/pages/settings/reading.njk +64 -0
- package/admin/pages/tools/content-index.njk +89 -0
- package/admin/pages/users/edit.njk +239 -0
- package/admin/pages/users/list.njk +51 -0
- package/admin/pages/users/new.njk +41 -0
- package/admin/static/admin.css +558 -3
- package/admin/static/copy.js +52 -0
- package/admin/static/editor.js +16 -16
- package/admin/static/slug.js +61 -0
- package/dist/access-log.d.ts +44 -0
- package/dist/access-log.d.ts.map +1 -0
- package/dist/access-log.js +71 -0
- package/dist/access-log.js.map +1 -0
- package/dist/admin/accounts.d.ts +413 -0
- package/dist/admin/accounts.d.ts.map +1 -0
- package/dist/admin/accounts.js +680 -0
- package/dist/admin/accounts.js.map +1 -0
- package/dist/admin/appearance.d.ts +80 -0
- package/dist/admin/appearance.d.ts.map +1 -0
- package/dist/admin/appearance.js +136 -0
- package/dist/admin/appearance.js.map +1 -0
- package/dist/admin/comments.d.ts +90 -0
- package/dist/admin/comments.d.ts.map +1 -0
- package/dist/admin/comments.js +244 -0
- package/dist/admin/comments.js.map +1 -0
- package/dist/admin/credentials.d.ts +26 -2
- package/dist/admin/credentials.d.ts.map +1 -1
- package/dist/admin/credentials.js +35 -2
- package/dist/admin/credentials.js.map +1 -1
- package/dist/admin/documents.d.ts +117 -10
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +328 -41
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/federation.d.ts +161 -50
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +235 -93
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/formatting.d.ts +20 -0
- package/dist/admin/formatting.d.ts.map +1 -0
- package/dist/admin/formatting.js +72 -0
- package/dist/admin/formatting.js.map +1 -0
- package/dist/admin/headers.d.ts +65 -0
- package/dist/admin/headers.d.ts.map +1 -0
- package/dist/admin/headers.js +104 -0
- package/dist/admin/headers.js.map +1 -0
- package/dist/admin/index.d.ts +38 -12
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +25 -7
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/media.d.ts +168 -0
- package/dist/admin/media.d.ts.map +1 -0
- package/dist/admin/media.js +295 -0
- package/dist/admin/media.js.map +1 -0
- package/dist/admin/menu.d.ts +79 -0
- package/dist/admin/menu.d.ts.map +1 -0
- package/dist/admin/menu.js +143 -0
- package/dist/admin/menu.js.map +1 -0
- package/dist/admin/messages.d.ts +80 -0
- package/dist/admin/messages.d.ts.map +1 -0
- package/dist/admin/messages.js +152 -0
- package/dist/admin/messages.js.map +1 -0
- package/dist/admin/navigation.d.ts +155 -0
- package/dist/admin/navigation.d.ts.map +1 -0
- package/dist/admin/navigation.js +292 -0
- package/dist/admin/navigation.js.map +1 -0
- package/dist/admin/preview.d.ts.map +1 -1
- package/dist/admin/preview.js +31 -7
- package/dist/admin/preview.js.map +1 -1
- package/dist/admin/recovery.d.ts +92 -0
- package/dist/admin/recovery.d.ts.map +1 -0
- package/dist/admin/recovery.js +229 -0
- package/dist/admin/recovery.js.map +1 -0
- package/dist/admin/routes.d.ts +0 -20
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +164 -105
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/session.d.ts +17 -3
- package/dist/admin/session.d.ts.map +1 -1
- package/dist/admin/session.js +19 -5
- package/dist/admin/session.js.map +1 -1
- package/dist/admin/settings-discussion.d.ts +37 -0
- package/dist/admin/settings-discussion.d.ts.map +1 -0
- package/dist/admin/settings-discussion.js +117 -0
- package/dist/admin/settings-discussion.js.map +1 -0
- package/dist/admin/settings-email.d.ts +54 -0
- package/dist/admin/settings-email.d.ts.map +1 -0
- package/dist/admin/settings-email.js +189 -0
- package/dist/admin/settings-email.js.map +1 -0
- package/dist/admin/settings-federation.d.ts +48 -0
- package/dist/admin/settings-federation.d.ts.map +1 -0
- package/dist/admin/settings-federation.js +123 -0
- package/dist/admin/settings-federation.js.map +1 -0
- package/dist/admin/settings-general.d.ts +12 -0
- package/dist/admin/settings-general.d.ts.map +1 -0
- package/dist/admin/settings-general.js +48 -0
- package/dist/admin/settings-general.js.map +1 -0
- package/dist/admin/settings-page.d.ts +119 -0
- package/dist/admin/settings-page.d.ts.map +1 -0
- package/dist/admin/settings-page.js +132 -0
- package/dist/admin/settings-page.js.map +1 -0
- package/dist/admin/settings-pages.d.ts +30 -0
- package/dist/admin/settings-pages.d.ts.map +1 -0
- package/dist/admin/settings-pages.js +43 -0
- package/dist/admin/settings-pages.js.map +1 -0
- package/dist/admin/settings-permalinks.d.ts +16 -0
- package/dist/admin/settings-permalinks.d.ts.map +1 -0
- package/dist/admin/settings-permalinks.js +32 -0
- package/dist/admin/settings-permalinks.js.map +1 -0
- package/dist/admin/settings-reading.d.ts +34 -0
- package/dist/admin/settings-reading.d.ts.map +1 -0
- package/dist/admin/settings-reading.js +49 -0
- package/dist/admin/settings-reading.js.map +1 -0
- package/dist/admin/settings.d.ts +339 -96
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +600 -308
- package/dist/admin/settings.js.map +1 -1
- package/dist/admin/store.d.ts +606 -152
- package/dist/admin/store.d.ts.map +1 -1
- package/dist/admin/store.js +863 -268
- package/dist/admin/store.js.map +1 -1
- package/dist/admin/taxonomy.d.ts +114 -0
- package/dist/admin/taxonomy.d.ts.map +1 -0
- package/dist/admin/taxonomy.js +289 -0
- package/dist/admin/taxonomy.js.map +1 -0
- package/dist/admin/templates.d.ts +46 -14
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +46 -14
- package/dist/admin/templates.js.map +1 -1
- package/dist/admin/throttle.d.ts +84 -0
- package/dist/admin/throttle.d.ts.map +1 -0
- package/dist/admin/throttle.js +143 -0
- package/dist/admin/throttle.js.map +1 -0
- package/dist/admin/tools.d.ts +111 -0
- package/dist/admin/tools.d.ts.map +1 -0
- package/dist/admin/tools.js +182 -0
- package/dist/admin/tools.js.map +1 -0
- package/dist/admin/uploads.d.ts +28 -2
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +43 -4
- package/dist/admin/uploads.js.map +1 -1
- package/dist/admin/users.d.ts +100 -13
- package/dist/admin/users.d.ts.map +1 -1
- package/dist/admin/users.js +412 -39
- package/dist/admin/users.js.map +1 -1
- package/dist/cache.d.ts +141 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +207 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts +14 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +429 -21
- package/dist/cli.js.map +1 -1
- package/dist/comments/akismet.d.ts +130 -0
- package/dist/comments/akismet.d.ts.map +1 -0
- package/dist/comments/akismet.js +274 -0
- package/dist/comments/akismet.js.map +1 -0
- package/dist/comments/conversation.d.ts +29 -0
- package/dist/comments/conversation.d.ts.map +1 -0
- package/dist/comments/conversation.js +60 -0
- package/dist/comments/conversation.js.map +1 -0
- package/dist/comments/form.d.ts +123 -0
- package/dist/comments/form.d.ts.map +1 -0
- package/dist/comments/form.js +79 -0
- package/dist/comments/form.js.map +1 -0
- package/dist/comments/index.d.ts +16 -0
- package/dist/comments/index.d.ts.map +1 -0
- package/dist/comments/index.js +10 -0
- package/dist/comments/index.js.map +1 -0
- package/dist/comments/markdown.d.ts +8 -0
- package/dist/comments/markdown.d.ts.map +1 -0
- package/dist/comments/markdown.js +85 -0
- package/dist/comments/markdown.js.map +1 -0
- package/dist/comments/moderate.d.ts +71 -0
- package/dist/comments/moderate.d.ts.map +1 -0
- package/dist/comments/moderate.js +88 -0
- package/dist/comments/moderate.js.map +1 -0
- package/dist/comments/policy.d.ts +57 -0
- package/dist/comments/policy.d.ts.map +1 -0
- package/dist/comments/policy.js +80 -0
- package/dist/comments/policy.js.map +1 -0
- package/dist/comments/records.d.ts +266 -0
- package/dist/comments/records.d.ts.map +1 -0
- package/dist/comments/records.js +487 -0
- package/dist/comments/records.js.map +1 -0
- package/dist/comments/routes.d.ts +60 -0
- package/dist/comments/routes.d.ts.map +1 -0
- package/dist/comments/routes.js +212 -0
- package/dist/comments/routes.js.map +1 -0
- package/dist/comments/submission.d.ts +297 -0
- package/dist/comments/submission.d.ts.map +1 -0
- package/dist/comments/submission.js +280 -0
- package/dist/comments/submission.js.map +1 -0
- package/dist/comments/viewer.d.ts +21 -0
- package/dist/comments/viewer.d.ts.map +1 -0
- package/dist/comments/viewer.js +45 -0
- package/dist/comments/viewer.js.map +1 -0
- package/dist/config.d.ts +225 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +121 -6
- package/dist/config.js.map +1 -1
- package/dist/contact/delivery.d.ts +60 -0
- package/dist/contact/delivery.d.ts.map +1 -0
- package/dist/contact/delivery.js +87 -0
- package/dist/contact/delivery.js.map +1 -0
- package/dist/contact/form.d.ts +130 -0
- package/dist/contact/form.d.ts.map +1 -0
- package/dist/contact/form.js +163 -0
- package/dist/contact/form.js.map +1 -0
- package/dist/contact/index.d.ts +17 -0
- package/dist/contact/index.d.ts.map +1 -0
- package/dist/contact/index.js +13 -0
- package/dist/contact/index.js.map +1 -0
- package/dist/contact/records.d.ts +124 -0
- package/dist/contact/records.d.ts.map +1 -0
- package/dist/contact/records.js +218 -0
- package/dist/contact/records.js.map +1 -0
- package/dist/contact/routes.d.ts +17 -0
- package/dist/contact/routes.d.ts.map +1 -0
- package/dist/contact/routes.js +127 -0
- package/dist/contact/routes.js.map +1 -0
- package/dist/contact/submission.d.ts +103 -0
- package/dist/contact/submission.d.ts.map +1 -0
- package/dist/contact/submission.js +166 -0
- package/dist/contact/submission.js.map +1 -0
- package/dist/content/document.d.ts +7 -2
- package/dist/content/document.d.ts.map +1 -1
- package/dist/content/document.js +1 -0
- package/dist/content/document.js.map +1 -1
- package/dist/content/index.d.ts +7 -2
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +4 -1
- package/dist/content/index.js.map +1 -1
- package/dist/content/markdown.d.ts.map +1 -1
- package/dist/content/markdown.js +24 -2
- package/dist/content/markdown.js.map +1 -1
- package/dist/content/parser.d.ts.map +1 -1
- package/dist/content/parser.js +11 -4
- package/dist/content/parser.js.map +1 -1
- package/dist/content/save.d.ts +5 -0
- package/dist/content/save.d.ts.map +1 -1
- package/dist/content/save.js +44 -1
- package/dist/content/save.js.map +1 -1
- package/dist/content/schedule.d.ts +125 -0
- package/dist/content/schedule.d.ts.map +1 -0
- package/dist/content/schedule.js +207 -0
- package/dist/content/schedule.js.map +1 -0
- package/dist/content/search.d.ts +64 -0
- package/dist/content/search.d.ts.map +1 -0
- package/dist/content/search.js +136 -0
- package/dist/content/search.js.map +1 -0
- package/dist/content/store.d.ts +220 -7
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +392 -67
- package/dist/content/store.js.map +1 -1
- package/dist/content/sync.d.ts +7 -1
- package/dist/content/sync.d.ts.map +1 -1
- package/dist/content/sync.js +18 -10
- package/dist/content/sync.js.map +1 -1
- package/dist/content/time.d.ts +56 -0
- package/dist/content/time.d.ts.map +1 -0
- package/dist/content/time.js +141 -0
- package/dist/content/time.js.map +1 -0
- package/dist/content/writer.d.ts.map +1 -1
- package/dist/content/writer.js +3 -0
- package/dist/content/writer.js.map +1 -1
- package/dist/env.d.ts +70 -5
- package/dist/env.d.ts.map +1 -1
- package/dist/federation/actor.d.ts +95 -41
- package/dist/federation/actor.d.ts.map +1 -1
- package/dist/federation/actor.js +180 -53
- package/dist/federation/actor.js.map +1 -1
- package/dist/federation/article.d.ts +44 -17
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +98 -46
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/delivery.d.ts +63 -15
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +154 -80
- package/dist/federation/delivery.js.map +1 -1
- package/dist/federation/federation.d.ts +22 -17
- package/dist/federation/federation.d.ts.map +1 -1
- package/dist/federation/federation.js +98 -77
- package/dist/federation/federation.js.map +1 -1
- package/dist/federation/followers.d.ts +3 -2
- package/dist/federation/followers.d.ts.map +1 -1
- package/dist/federation/followers.js +6 -5
- package/dist/federation/followers.js.map +1 -1
- package/dist/federation/import-wordpress.d.ts +128 -0
- package/dist/federation/import-wordpress.d.ts.map +1 -0
- package/dist/federation/import-wordpress.js +426 -0
- package/dist/federation/import-wordpress.js.map +1 -0
- package/dist/federation/inbox.d.ts +36 -13
- package/dist/federation/inbox.d.ts.map +1 -1
- package/dist/federation/inbox.js +120 -49
- package/dist/federation/inbox.js.map +1 -1
- package/dist/federation/index.d.ts +22 -10
- package/dist/federation/index.d.ts.map +1 -1
- package/dist/federation/index.js +13 -8
- package/dist/federation/index.js.map +1 -1
- package/dist/federation/keys.d.ts +98 -20
- package/dist/federation/keys.d.ts.map +1 -1
- package/dist/federation/keys.js +269 -39
- package/dist/federation/keys.js.map +1 -1
- package/dist/federation/mount.d.ts +46 -10
- package/dist/federation/mount.d.ts.map +1 -1
- package/dist/federation/mount.js +300 -28
- package/dist/federation/mount.js.map +1 -1
- package/dist/federation/paths.d.ts +23 -35
- package/dist/federation/paths.d.ts.map +1 -1
- package/dist/federation/paths.js +26 -39
- package/dist/federation/paths.js.map +1 -1
- package/dist/federation/records.d.ts +223 -0
- package/dist/federation/records.d.ts.map +1 -0
- package/dist/federation/records.js +506 -0
- package/dist/federation/records.js.map +1 -0
- package/dist/federation/relays.d.ts +114 -0
- package/dist/federation/relays.d.ts.map +1 -0
- package/dist/federation/relays.js +290 -0
- package/dist/federation/relays.js.map +1 -0
- package/dist/federation/replies.d.ts +80 -0
- package/dist/federation/replies.d.ts.map +1 -0
- package/dist/federation/replies.js +166 -0
- package/dist/federation/replies.js.map +1 -0
- package/dist/federation/wordpress.d.ts +131 -0
- package/dist/federation/wordpress.d.ts.map +1 -0
- package/dist/federation/wordpress.js +341 -0
- package/dist/federation/wordpress.js.map +1 -0
- package/dist/files/atomic.d.ts +103 -0
- package/dist/files/atomic.d.ts.map +1 -0
- package/dist/files/atomic.js +150 -0
- package/dist/files/atomic.js.map +1 -0
- package/dist/files/index.d.ts +3 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +2 -0
- package/dist/files/index.js.map +1 -0
- package/dist/forms/protection.d.ts +85 -0
- package/dist/forms/protection.d.ts.map +1 -0
- package/dist/forms/protection.js +116 -0
- package/dist/forms/protection.js.map +1 -0
- package/dist/images/icons.d.ts +59 -0
- package/dist/images/icons.d.ts.map +1 -0
- package/dist/images/icons.js +131 -0
- package/dist/images/icons.js.map +1 -0
- package/dist/images/index.d.ts +7 -0
- package/dist/images/index.d.ts.map +1 -0
- package/dist/images/index.js +4 -0
- package/dist/images/index.js.map +1 -0
- package/dist/images/markup.d.ts +47 -0
- package/dist/images/markup.d.ts.map +1 -0
- package/dist/images/markup.js +175 -0
- package/dist/images/markup.js.map +1 -0
- package/dist/images/paths.d.ts +34 -0
- package/dist/images/paths.d.ts.map +1 -0
- package/dist/images/paths.js +41 -0
- package/dist/images/paths.js.map +1 -0
- package/dist/images/variants.d.ts +104 -0
- package/dist/images/variants.d.ts.map +1 -0
- package/dist/images/variants.js +320 -0
- package/dist/images/variants.js.map +1 -0
- package/dist/index.d.ts +123 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +344 -25
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +18 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +34 -3
- package/dist/init.js.map +1 -1
- package/dist/mail/brevo.d.ts +35 -0
- package/dist/mail/brevo.d.ts.map +1 -0
- package/dist/mail/brevo.js +85 -0
- package/dist/mail/brevo.js.map +1 -0
- package/dist/mail/credentials.d.ts +62 -0
- package/dist/mail/credentials.d.ts.map +1 -0
- package/dist/mail/credentials.js +86 -0
- package/dist/mail/credentials.js.map +1 -0
- package/dist/mail/index.d.ts +15 -0
- package/dist/mail/index.d.ts.map +1 -0
- package/dist/mail/index.js +8 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/mail/memory.d.ts +35 -0
- package/dist/mail/memory.d.ts.map +1 -0
- package/dist/mail/memory.js +29 -0
- package/dist/mail/memory.js.map +1 -0
- package/dist/mail/provider.d.ts +80 -0
- package/dist/mail/provider.d.ts.map +1 -0
- package/dist/mail/provider.js +23 -0
- package/dist/mail/provider.js.map +1 -0
- package/dist/mail/service.d.ts +156 -0
- package/dist/mail/service.d.ts.map +1 -0
- package/dist/mail/service.js +265 -0
- package/dist/mail/service.js.map +1 -0
- package/dist/mail/smtp.d.ts +39 -0
- package/dist/mail/smtp.d.ts.map +1 -0
- package/dist/mail/smtp.js +58 -0
- package/dist/mail/smtp.js.map +1 -0
- package/dist/mail/templates.d.ts +91 -0
- package/dist/mail/templates.d.ts.map +1 -0
- package/dist/mail/templates.js +69 -0
- package/dist/mail/templates.js.map +1 -0
- package/dist/notifications/comments.d.ts +66 -0
- package/dist/notifications/comments.d.ts.map +1 -0
- package/dist/notifications/comments.js +151 -0
- package/dist/notifications/comments.js.map +1 -0
- package/dist/notifications/digest.d.ts +135 -0
- package/dist/notifications/digest.d.ts.map +1 -0
- package/dist/notifications/digest.js +287 -0
- package/dist/notifications/digest.js.map +1 -0
- package/dist/notifications/index.d.ts +13 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +8 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/links.d.ts +60 -0
- package/dist/notifications/links.d.ts.map +1 -0
- package/dist/notifications/links.js +63 -0
- package/dist/notifications/links.js.map +1 -0
- package/dist/notifications/optouts.d.ts +48 -0
- package/dist/notifications/optouts.d.ts.map +1 -0
- package/dist/notifications/optouts.js +93 -0
- package/dist/notifications/optouts.js.map +1 -0
- package/dist/notifications/preferences.d.ts +158 -0
- package/dist/notifications/preferences.d.ts.map +1 -0
- package/dist/notifications/preferences.js +195 -0
- package/dist/notifications/preferences.js.map +1 -0
- package/dist/notifications/routes.d.ts +28 -0
- package/dist/notifications/routes.d.ts.map +1 -0
- package/dist/notifications/routes.js +184 -0
- package/dist/notifications/routes.js.map +1 -0
- package/dist/notifications/tokens.d.ts +60 -0
- package/dist/notifications/tokens.d.ts.map +1 -0
- package/dist/notifications/tokens.js +125 -0
- package/dist/notifications/tokens.js.map +1 -0
- package/dist/notify.d.ts +84 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +149 -0
- package/dist/notify.js.map +1 -0
- package/dist/web/archive.d.ts +49 -0
- package/dist/web/archive.d.ts.map +1 -0
- package/dist/web/archive.js +59 -0
- package/dist/web/archive.js.map +1 -0
- package/dist/web/assets.d.ts +6 -5
- package/dist/web/assets.d.ts.map +1 -1
- package/dist/web/assets.js +5 -7
- package/dist/web/assets.js.map +1 -1
- package/dist/web/authors.d.ts +143 -0
- package/dist/web/authors.d.ts.map +1 -0
- package/dist/web/authors.js +178 -0
- package/dist/web/authors.js.map +1 -0
- package/dist/web/comments.d.ts +60 -0
- package/dist/web/comments.d.ts.map +1 -0
- package/dist/web/comments.js +207 -0
- package/dist/web/comments.js.map +1 -0
- package/dist/web/context.d.ts +162 -28
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +123 -26
- package/dist/web/context.js.map +1 -1
- package/dist/web/conversation.d.ts +209 -0
- package/dist/web/conversation.d.ts.map +1 -0
- package/dist/web/conversation.js +557 -0
- package/dist/web/conversation.js.map +1 -0
- package/dist/web/documents.d.ts +36 -6
- package/dist/web/documents.d.ts.map +1 -1
- package/dist/web/documents.js +52 -10
- package/dist/web/documents.js.map +1 -1
- package/dist/web/feed-atom.d.ts +22 -0
- package/dist/web/feed-atom.d.ts.map +1 -0
- package/dist/web/feed-atom.js +83 -0
- package/dist/web/feed-atom.js.map +1 -0
- package/dist/web/feed-item.d.ts +145 -0
- package/dist/web/feed-item.d.ts.map +1 -0
- package/dist/web/feed-item.js +120 -0
- package/dist/web/feed-item.js.map +1 -0
- package/dist/web/feed-json.d.ts +79 -0
- package/dist/web/feed-json.d.ts.map +1 -0
- package/dist/web/feed-json.js +53 -0
- package/dist/web/feed-json.js.map +1 -0
- package/dist/web/feed-rss.d.ts +26 -0
- package/dist/web/feed-rss.d.ts.map +1 -0
- package/dist/web/feed-rss.js +203 -0
- package/dist/web/feed-rss.js.map +1 -0
- package/dist/web/feed-source.d.ts +244 -0
- package/dist/web/feed-source.d.ts.map +1 -0
- package/dist/web/feed-source.js +201 -0
- package/dist/web/feed-source.js.map +1 -0
- package/dist/web/feed-xml.d.ts +63 -0
- package/dist/web/feed-xml.d.ts.map +1 -0
- package/dist/web/feed-xml.js +116 -0
- package/dist/web/feed-xml.js.map +1 -0
- package/dist/web/feeds.d.ts +31 -96
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js +94 -198
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/health.d.ts +31 -0
- package/dist/web/health.d.ts.map +1 -0
- package/dist/web/health.js +44 -0
- package/dist/web/health.js.map +1 -0
- package/dist/web/index.d.ts +30 -10
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +18 -7
- package/dist/web/index.js.map +1 -1
- package/dist/web/navigation.d.ts +195 -0
- package/dist/web/navigation.d.ts.map +1 -0
- package/dist/web/navigation.js +300 -0
- package/dist/web/navigation.js.map +1 -0
- package/dist/web/negotiate.d.ts +31 -0
- package/dist/web/negotiate.d.ts.map +1 -1
- package/dist/web/negotiate.js +31 -11
- package/dist/web/negotiate.js.map +1 -1
- package/dist/web/recent.d.ts +43 -0
- package/dist/web/recent.d.ts.map +1 -0
- package/dist/web/recent.js +37 -0
- package/dist/web/recent.js.map +1 -0
- package/dist/web/render.d.ts +203 -9
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +341 -17
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts +25 -8
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +854 -93
- package/dist/web/routes.js.map +1 -1
- package/dist/web/sanitize.d.ts +19 -0
- package/dist/web/sanitize.d.ts.map +1 -0
- package/dist/web/sanitize.js +272 -0
- package/dist/web/sanitize.js.map +1 -0
- package/dist/web/search.d.ts +79 -0
- package/dist/web/search.d.ts.map +1 -0
- package/dist/web/search.js +94 -0
- package/dist/web/search.js.map +1 -0
- package/dist/web/sitemap.d.ts +120 -0
- package/dist/web/sitemap.d.ts.map +1 -0
- package/dist/web/sitemap.js +199 -0
- package/dist/web/sitemap.js.map +1 -0
- package/dist/web/taxonomy.d.ts +152 -0
- package/dist/web/taxonomy.d.ts.map +1 -0
- package/dist/web/taxonomy.js +237 -0
- package/dist/web/taxonomy.js.map +1 -0
- package/dist/web/templates.d.ts +54 -16
- package/dist/web/templates.d.ts.map +1 -1
- package/dist/web/templates.js +109 -28
- package/dist/web/templates.js.map +1 -1
- package/dist/web/themes.d.ts +226 -0
- package/dist/web/themes.d.ts.map +1 -0
- package/dist/web/themes.js +314 -0
- package/dist/web/themes.js.map +1 -0
- package/dist/webmention/discovery.d.ts +51 -0
- package/dist/webmention/discovery.d.ts.map +1 -0
- package/dist/webmention/discovery.js +176 -0
- package/dist/webmention/discovery.js.map +1 -0
- package/dist/webmention/html.d.ts +71 -0
- package/dist/webmention/html.d.ts.map +1 -0
- package/dist/webmention/html.js +285 -0
- package/dist/webmention/html.js.map +1 -0
- package/dist/webmention/index.d.ts +12 -0
- package/dist/webmention/index.d.ts.map +1 -0
- package/dist/webmention/index.js +8 -0
- package/dist/webmention/index.js.map +1 -0
- package/dist/webmention/links.d.ts +18 -0
- package/dist/webmention/links.d.ts.map +1 -0
- package/dist/webmention/links.js +64 -0
- package/dist/webmention/links.js.map +1 -0
- package/dist/webmention/microformats.d.ts +93 -0
- package/dist/webmention/microformats.d.ts.map +1 -0
- package/dist/webmention/microformats.js +376 -0
- package/dist/webmention/microformats.js.map +1 -0
- package/dist/webmention/receive.d.ts +141 -0
- package/dist/webmention/receive.d.ts.map +1 -0
- package/dist/webmention/receive.js +264 -0
- package/dist/webmention/receive.js.map +1 -0
- package/dist/webmention/routes.d.ts +37 -0
- package/dist/webmention/routes.d.ts.map +1 -0
- package/dist/webmention/routes.js +75 -0
- package/dist/webmention/routes.js.map +1 -0
- package/dist/webmention/service.d.ts +94 -0
- package/dist/webmention/service.d.ts.map +1 -0
- package/dist/webmention/service.js +207 -0
- package/dist/webmention/service.js.map +1 -0
- package/package.json +11 -6
- package/templates/site/content/_data/site.json +8 -0
- package/templates/site/content/pages/about.md +7 -0
- package/templates/site/content/posts/2026-01-01-hello-world.md +5 -3
- package/templates/site/geekity.config.ts +11 -1
- package/templates/site/tsconfig.json +1 -1
- package/themes/default/README.md +1216 -50
- package/themes/default/layouts/404.njk +2 -3
- package/themes/default/layouts/author.njk +36 -0
- package/themes/default/layouts/base.njk +161 -31
- package/themes/default/layouts/category.njk +27 -0
- package/themes/default/layouts/front-page.njk +56 -0
- package/themes/default/layouts/home.njk +17 -1
- package/themes/default/layouts/page.njk +57 -5
- package/themes/default/layouts/post.njk +78 -19
- package/themes/default/layouts/search.njk +57 -0
- package/themes/default/layouts/tag.njk +3 -6
- package/themes/default/mail/comment-digest.html.njk +37 -0
- package/themes/default/mail/comment-digest.subject.njk +3 -0
- package/themes/default/mail/comment-digest.txt.njk +40 -0
- package/themes/default/mail/comment-pending.html.njk +27 -0
- package/themes/default/mail/comment-pending.subject.njk +2 -0
- package/themes/default/mail/comment-pending.txt.njk +24 -0
- package/themes/default/mail/comment-reply.html.njk +21 -0
- package/themes/default/mail/comment-reply.subject.njk +2 -0
- package/themes/default/mail/comment-reply.txt.njk +22 -0
- package/themes/default/mail/contact-message.html.njk +24 -0
- package/themes/default/mail/contact-message.subject.njk +5 -0
- package/themes/default/mail/contact-message.txt.njk +20 -0
- package/themes/default/mail/password-changed.html.njk +18 -0
- package/themes/default/mail/password-changed.subject.njk +2 -0
- package/themes/default/mail/password-changed.txt.njk +17 -0
- package/themes/default/mail/password-reset.html.njk +22 -0
- package/themes/default/mail/password-reset.subject.njk +2 -0
- package/themes/default/mail/password-reset.txt.njk +18 -0
- package/themes/default/mail/test.html.njk +14 -0
- package/themes/default/mail/test.subject.njk +2 -0
- package/themes/default/mail/test.txt.njk +12 -0
- package/themes/default/partials/archive.njk +27 -0
- package/themes/default/partials/bio.njk +71 -0
- package/themes/default/partials/comment-form.njk +137 -0
- package/themes/default/partials/contact-form.njk +88 -0
- package/themes/default/partials/conversation.njk +139 -0
- package/themes/default/partials/feeds.njk +26 -0
- package/themes/default/partials/jsonld.njk +120 -0
- package/themes/default/partials/menu.njk +32 -0
- package/themes/default/partials/pagination.njk +12 -6
- package/themes/default/partials/post-list.njk +51 -18
- package/themes/default/partials/search-form.njk +22 -0
- package/themes/default/partials/tags.njk +26 -5
- package/themes/default/static/highlight.js +4 -0
- package/themes/default/static/style.css +1142 -194
- package/themes/default/theme.json +9 -0
- package/admin/layouts/federation.njk +0 -145
- package/admin/layouts/login.njk +0 -23
- package/admin/layouts/settings.njk +0 -116
- package/admin/layouts/setup.njk +0 -27
- package/admin/layouts/users.njk +0 -91
- /package/admin/{layouts/_flash.njk → components/flash.njk} +0 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { csrfTokenMatches } from '../admin/session.js';
|
|
2
|
+
import { clientAddress, createLoginThrottle } from '../admin/throttle.js';
|
|
3
|
+
import { isPublicDocument } from '../web/documents.js';
|
|
4
|
+
import { PRIVATE_CACHE_CONTROL } from '../web/negotiate.js';
|
|
5
|
+
import { COMMENT_NOTICE_PARAM, COMMENT_NOTICES, COMMENT_POST_PATH, commentForm, refilledCommentForm, signedInCommentForm, valuesOf, } from './form.js';
|
|
6
|
+
import { commentPolicyOf, commentsOpen } from './policy.js';
|
|
7
|
+
import { commentAnchor } from '../web/conversation.js';
|
|
8
|
+
import { COMMENT_FIELDS, COMMENT_RATE_LIMIT, COMMENT_RATE_WINDOW_SECONDS, submitComment, } from './submission.js';
|
|
9
|
+
import { signedInCommenter } from './viewer.js';
|
|
10
|
+
/**
|
|
11
|
+
* The one public endpoint comments add: where the form under a post posts to.
|
|
12
|
+
*
|
|
13
|
+
* It is a single path rather than one per post because the post is a field of
|
|
14
|
+
* the form. That keeps it out of the way of every permalink a site might ever
|
|
15
|
+
* mint — a path under `/_geekity/` is the CMS's own, like the health check —
|
|
16
|
+
* and means the route table does not grow with the site.
|
|
17
|
+
*
|
|
18
|
+
* Everything it answers is either a redirect or the post's own page rendered
|
|
19
|
+
* again with the form still filled in. There is no JSON, no fragment and no
|
|
20
|
+
* script: a comment form has worked without JavaScript since 2003 and there is
|
|
21
|
+
* no reason for this one to stop.
|
|
22
|
+
*/
|
|
23
|
+
export { COMMENT_POST_PATH, COMMENT_REPLY_PARAM } from './form.js';
|
|
24
|
+
/** Register the comment endpoint. Mounted by the public site. */
|
|
25
|
+
export function mountComments(app) {
|
|
26
|
+
// One limiter for the whole mount, built on the first submission because the
|
|
27
|
+
// clock is on the context. It holds nothing but recent submissions, so it
|
|
28
|
+
// belongs to the process rather than the database: a restart clears it,
|
|
29
|
+
// which is the right trade for state an anonymous caller can create.
|
|
30
|
+
let limiter;
|
|
31
|
+
function throttle(config) {
|
|
32
|
+
limiter ??= createLoginThrottle({
|
|
33
|
+
attempts: COMMENT_RATE_LIMIT,
|
|
34
|
+
lockoutSeconds: COMMENT_RATE_WINDOW_SECONDS,
|
|
35
|
+
now: config.now,
|
|
36
|
+
});
|
|
37
|
+
return limiter;
|
|
38
|
+
}
|
|
39
|
+
app.post(COMMENT_POST_PATH, async (c) => {
|
|
40
|
+
const { store, admin, renderer, config } = c.var;
|
|
41
|
+
const body = await c.req.parseBody();
|
|
42
|
+
const form = formOf(body);
|
|
43
|
+
// Who the session says this is, read before anything else is decided: it
|
|
44
|
+
// settles the token, the attribution and where the comment lands.
|
|
45
|
+
const viewer = signedInCommenter(c);
|
|
46
|
+
// A form that acts on nobody's behalf needs no token, and the public one
|
|
47
|
+
// still carries none. This one posts under somebody's name, so without a
|
|
48
|
+
// matching token a page on another site could make them say something they
|
|
49
|
+
// never typed. Refused in the words and with the status the admin guard
|
|
50
|
+
// uses, because it is the same check on the same token.
|
|
51
|
+
if (viewer !== undefined && !csrfTokenMatches(viewer.csrfToken, form.csrf)) {
|
|
52
|
+
return c.text('That form was stale or came from somewhere else. Reload and try again.', 403);
|
|
53
|
+
}
|
|
54
|
+
const document = store.getBySlug(form.post);
|
|
55
|
+
if (document === undefined || !isPublicDocument(document, store.now())) {
|
|
56
|
+
return c.text('There is no such post to comment on.', 404);
|
|
57
|
+
}
|
|
58
|
+
const now = config.now();
|
|
59
|
+
if (!commentsOpen(document, commentPolicyOf(renderer.site()), now)) {
|
|
60
|
+
// 403 rather than 404: the post is there, and the reader can see for
|
|
61
|
+
// themselves that it is. Saying so is more honest than pretending the
|
|
62
|
+
// URL is wrong, and a closed post is a state rather than a mistake.
|
|
63
|
+
return page(c, document, 403, viewer, {
|
|
64
|
+
...drawnFor(refilledCommentForm(document, valuesOf(form), {}, now), viewer),
|
|
65
|
+
error: 'This post is not taking comments any more.',
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const outcome = await submitComment({
|
|
69
|
+
records: { admin, contentDir: config.contentDir },
|
|
70
|
+
document,
|
|
71
|
+
form,
|
|
72
|
+
dataDir: config.dataDir,
|
|
73
|
+
baseUrl: config.baseUrl,
|
|
74
|
+
checker: config.commentChecker,
|
|
75
|
+
// Who the site knows is writing, when it knows (TASK-103). Set, it is
|
|
76
|
+
// the whole of the comment's attribution and the reason it is approved
|
|
77
|
+
// on arrival.
|
|
78
|
+
author: viewer,
|
|
79
|
+
// Who hears about what lands is the intake's to decide, and neither
|
|
80
|
+
// message is awaited: the reader is redirected now and they go out
|
|
81
|
+
// behind them (TASK-55).
|
|
82
|
+
notices: c.var.notifications,
|
|
83
|
+
address: clientAddress(c, config),
|
|
84
|
+
userAgent: c.req.header('user-agent'),
|
|
85
|
+
referrer: c.req.header('referer'),
|
|
86
|
+
throttle: throttle(config),
|
|
87
|
+
// Whether the box on the form meant anything, read per submission so a
|
|
88
|
+
// credential saved a moment ago is honoured now (TASK-55).
|
|
89
|
+
notifiable: c.var.mail.configured(),
|
|
90
|
+
now,
|
|
91
|
+
});
|
|
92
|
+
if (outcome.kind === 'stored') {
|
|
93
|
+
const stored = outcome.comment;
|
|
94
|
+
// A redirect rather than a rendered page, so a refresh does not post the
|
|
95
|
+
// comment a second time. An approved comment is on the page already, so
|
|
96
|
+
// the reader is sent to it; one waiting for a moderator has nothing to
|
|
97
|
+
// point at, so the reader is sent to the form they just used.
|
|
98
|
+
const anchor = stored.status === 'approved' ? commentAnchor(stored.id) : 'respond';
|
|
99
|
+
const notice = stored.status === 'approved' ? 'posted' : 'pending';
|
|
100
|
+
return c.redirect(`${document.permalink}?${COMMENT_NOTICE_PARAM}=${notice}#${anchor}`, 303);
|
|
101
|
+
}
|
|
102
|
+
const refusal = outcome.refusal;
|
|
103
|
+
if (refusal.kind === 'discarded') {
|
|
104
|
+
// Nothing is said about why. A robot that filled the honeypot, or that a
|
|
105
|
+
// checker recognised, learns exactly as much from this as from a
|
|
106
|
+
// successful post — which is the point of both defences.
|
|
107
|
+
return c.redirect(`${document.permalink}?${COMMENT_NOTICE_PARAM}=pending#respond`, 303);
|
|
108
|
+
}
|
|
109
|
+
if (refusal.kind === 'rate-limited') {
|
|
110
|
+
c.header('Retry-After', String(refusal.retryAfter));
|
|
111
|
+
return page(c, document, 429, viewer, {
|
|
112
|
+
...drawnFor(refilledCommentForm(document, valuesOf(form), {}, now), viewer),
|
|
113
|
+
error: 'That is a lot of comments in a short time. Try again in a few minutes.',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const message = refusal.kind === 'too-quick'
|
|
117
|
+
? 'That was posted faster than anybody types. Try again.'
|
|
118
|
+
: refusal.kind === 'stale'
|
|
119
|
+
? 'That form had been open a long time. Here it is again — the words are still there.'
|
|
120
|
+
: undefined;
|
|
121
|
+
return page(c, document, 400, viewer, {
|
|
122
|
+
...drawnFor(refilledCommentForm(document, valuesOf(form), problemsOf(refusal), now), viewer),
|
|
123
|
+
...(message === undefined ? {} : { error: message }),
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The same form drawn for whoever is filling it in: the short one when the
|
|
129
|
+
* site knows them, and the stranger's one when it does not.
|
|
130
|
+
*/
|
|
131
|
+
function drawnFor(form, viewer) {
|
|
132
|
+
return viewer === undefined ? form : signedInCommentForm(form, viewer);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The post's own page, rendered again with this form on it.
|
|
136
|
+
*
|
|
137
|
+
* A page drawn for a named reader says so, for the reason the rendered post
|
|
138
|
+
* does: it is one person's page rather than the post, and nothing in front of
|
|
139
|
+
* the site may hold it and hand it to the next reader.
|
|
140
|
+
*/
|
|
141
|
+
function page(c, document, status, viewer, form) {
|
|
142
|
+
c.status(status);
|
|
143
|
+
if (viewer !== undefined)
|
|
144
|
+
c.header('cache-control', PRIVATE_CACHE_CONTROL);
|
|
145
|
+
return c.html(c.var.renderer.renderDocument(document, { commentForm: form }, viewer));
|
|
146
|
+
}
|
|
147
|
+
/** The per-field messages a refusal carries, if it carries any. */
|
|
148
|
+
function problemsOf(refusal) {
|
|
149
|
+
return refusal.kind === 'invalid' ? (refusal.problems ?? {}) : {};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* The thank-you a reader is shown after posting, from the query the redirect
|
|
153
|
+
* carried, or `undefined` when the URL says nothing.
|
|
154
|
+
*
|
|
155
|
+
* A query rather than a flash message, because a reader has no session to hang
|
|
156
|
+
* one on, and because a comment form that only works for people with cookies
|
|
157
|
+
* is not a comment form.
|
|
158
|
+
*/
|
|
159
|
+
export function commentNoticeFor(query) {
|
|
160
|
+
return query === undefined ? undefined : COMMENT_NOTICES[query];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* The comment a `?reply_to=` query points at, as the theme needs it, or an
|
|
164
|
+
* empty object when the query names nothing on this post.
|
|
165
|
+
*
|
|
166
|
+
* Checked against the index rather than trusted, so a made-up id — or one from
|
|
167
|
+
* another page — cannot put a stranger's name on somebody's reply form, and so
|
|
168
|
+
* a comment waiting for a moderator cannot be discovered by guessing.
|
|
169
|
+
*/
|
|
170
|
+
export function commentReplyTarget(options) {
|
|
171
|
+
if (options.id === undefined || options.id === '')
|
|
172
|
+
return {};
|
|
173
|
+
const parent = options.admin.getComment(options.id);
|
|
174
|
+
if (parent === undefined || parent.slug !== options.document.slug)
|
|
175
|
+
return {};
|
|
176
|
+
if (parent.status !== 'approved')
|
|
177
|
+
return {};
|
|
178
|
+
return { commentReplyTo: parent.id, commentReplyingTo: parent.author.name };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The form for a post, or `undefined` when it is not taking comments.
|
|
182
|
+
*
|
|
183
|
+
* What the renderer is handed at boot. It reads the settings and the clock on
|
|
184
|
+
* every render, so a post that closed an hour ago stops offering a form on the
|
|
185
|
+
* very next request.
|
|
186
|
+
*/
|
|
187
|
+
export function commentFormFor(options) {
|
|
188
|
+
if (!commentsOpen(options.document, commentPolicyOf(options.site), options.now))
|
|
189
|
+
return undefined;
|
|
190
|
+
const form = commentForm(options.document, options.now, options.notifiable ?? false);
|
|
191
|
+
return drawnFor(form, options.viewer);
|
|
192
|
+
}
|
|
193
|
+
/** A submitted body as the form it is, every field a string. */
|
|
194
|
+
function formOf(body) {
|
|
195
|
+
return {
|
|
196
|
+
post: text(body[COMMENT_FIELDS.post]),
|
|
197
|
+
name: text(body[COMMENT_FIELDS.name]),
|
|
198
|
+
email: text(body[COMMENT_FIELDS.email]),
|
|
199
|
+
url: text(body[COMMENT_FIELDS.url]),
|
|
200
|
+
body: text(body[COMMENT_FIELDS.body]),
|
|
201
|
+
inReplyTo: text(body[COMMENT_FIELDS.inReplyTo]),
|
|
202
|
+
trap: text(body[COMMENT_FIELDS.trap]),
|
|
203
|
+
loaded: text(body[COMMENT_FIELDS.loaded]),
|
|
204
|
+
notify: text(body[COMMENT_FIELDS.notify]),
|
|
205
|
+
csrf: text(body[COMMENT_FIELDS.csrf]),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/** A form field as a string. A file upload, or a missing field, is the empty one. */
|
|
209
|
+
function text(value) {
|
|
210
|
+
return typeof value === 'string' ? value : '';
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/comments/routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAI1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,QAAQ,GACT,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,2BAA2B,EAC3B,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEnE,iEAAiE;AACjE,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,6EAA6E;IAC7E,0EAA0E;IAC1E,wEAAwE;IACxE,qEAAqE;IACrE,IAAI,OAAoC,CAAC;IAEzC,SAAS,QAAQ,CAAC,MAAsB;QACtC,OAAO,KAAK,mBAAmB,CAAC;YAC9B,QAAQ,EAAE,kBAAkB;YAC5B,cAAc,EAAE,2BAA2B;YAC3C,GAAG,EAAE,MAAM,CAAC,GAAG;SAChB,CAAC,CAAC;QACH,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC;QACjD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,yEAAyE;QACzE,kEAAkE;QAClE,MAAM,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAEpC,yEAAyE;QACzE,yEAAyE;QACzE,2EAA2E;QAC3E,wEAAwE;QACxE,wDAAwD;QACxD,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3E,OAAO,CAAC,CAAC,IAAI,CAAC,wEAAwE,EAAE,GAAG,CAAC,CAAC;QAC/F,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;YACvE,OAAO,CAAC,CAAC,IAAI,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;YACnE,qEAAqE;YACrE,sEAAsE;YACtE,oEAAoE;YACpE,OAAO,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE;gBACpC,GAAG,QAAQ,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC;gBAC3E,KAAK,EAAE,4CAA4C;aACpD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC;YAClC,OAAO,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE;YACjD,QAAQ;YACR,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,OAAO,EAAE,MAAM,CAAC,cAAc;YAC9B,sEAAsE;YACtE,uEAAuE;YACvE,cAAc;YACd,MAAM,EAAE,MAAM;YACd,oEAAoE;YACpE,mEAAmE;YACnE,yBAAyB;YACzB,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa;YAC5B,OAAO,EAAE,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC;YACjC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC;YACrC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;YACjC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC;YAC1B,uEAAuE;YACvE,2DAA2D;YAC3D,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE;YACnC,GAAG;SACJ,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAC/B,yEAAyE;YACzE,wEAAwE;YACxE,uEAAuE;YACvE,8DAA8D;YAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACnF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;YACnE,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,SAAS,IAAI,oBAAoB,IAAI,MAAM,IAAI,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9F,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAChC,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACjC,yEAAyE;YACzE,iEAAiE;YACjE,yDAAyD;YACzD,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,SAAS,IAAI,oBAAoB,kBAAkB,EAAE,GAAG,CAAC,CAAC;QAC1F,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACpC,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;YACpD,OAAO,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE;gBACpC,GAAG,QAAQ,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC;gBAC3E,KAAK,EAAE,wEAAwE;aAChF,CAAC,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GACX,OAAO,CAAC,IAAI,KAAK,WAAW;YAC1B,CAAC,CAAC,uDAAuD;YACzD,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO;gBACxB,CAAC,CAAC,oFAAoF;gBACtF,CAAC,CAAC,SAAS,CAAC;QAElB,OAAO,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE;YACpC,GAAG,QAAQ,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC;YAC5F,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;SACrD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAKD;;;GAGG;AACH,SAAS,QAAQ,CAAC,IAAwB,EAAE,MAAiC;IAC3E,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,IAAI,CACX,CAAsB,EACtB,QAAkB,EAClB,MAAqB,EACrB,MAAiC,EACjC,IAAwB;IAExB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACjB,IAAI,MAAM,KAAK,SAAS;QAAE,CAAC,CAAC,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC,CAAC;IAC3E,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,mEAAmE;AACnE,SAAS,UAAU,CAAC,OAA6C;IAC/D,OAAO,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAA4B,CAAC,CAAC,CAAC,EAAE,CAAC;AAChG,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAyB;IACxD,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAIlC;IACC,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,IAAI,OAAO,CAAC,EAAE,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAE7D,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACpD,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAC7E,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,EAAE,CAAC;IAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,EAAE,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,OAQ9B;IACC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAElG,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC,CAAC;IACrF,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,gEAAgE;AAChE,SAAS,MAAM,CAAC,IAA6B;IAC3C,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACrC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACvC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACrC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,qFAAqF;AACrF,SAAS,IAAI,CAAC,KAAc;IAC1B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import type { CommentAuthor, PostComment } from '../admin/store.ts';
|
|
2
|
+
import type { Document } from '../content/document.ts';
|
|
3
|
+
import type { CommentNotices, CommentRecords } from './records.ts';
|
|
4
|
+
/**
|
|
5
|
+
* What happens between somebody pressing Post and a proposed comment.
|
|
6
|
+
*
|
|
7
|
+
* Three defences run before anything is proposed, in the order that costs least
|
|
8
|
+
* and gives away least — the honeypot, the age of the form and the per-address
|
|
9
|
+
* rate limit. The first two are `forms/protection.ts`, shared with the contact
|
|
10
|
+
* form (TASK-56) so the two public forms cannot drift into different rules; the
|
|
11
|
+
* third is the same limiter the login form uses, over the commenter's address,
|
|
12
|
+
* so one machine cannot post a hundred comments while a moderator sleeps.
|
|
13
|
+
*
|
|
14
|
+
* What survives all three is handed to {@link intakeComment}, which is where
|
|
15
|
+
* every comment on this site is written whatever proposed it: the checker, the
|
|
16
|
+
* verdict-to-status rule, the file, the index and the notice all live there, so
|
|
17
|
+
* a form submission and a webmention cannot be treated by two sets of rules.
|
|
18
|
+
*
|
|
19
|
+
* The {@link CommentChecker} interface stays here because this is where it
|
|
20
|
+
* reads: it is the one seam a third-party service plugs into, everything
|
|
21
|
+
* Akismet's API asks for is on the submission it is handed, and its four
|
|
22
|
+
* answers are the four the intake understands. Nothing else in the CMS has to
|
|
23
|
+
* know such a service exists.
|
|
24
|
+
*/
|
|
25
|
+
export { hashClientAddress, MAXIMUM_FORM_AGE_SECONDS, MINIMUM_SUBMIT_SECONDS, } from '../forms/protection.ts';
|
|
26
|
+
/** Where the salt that hides commenters' addresses lives, under `dataDir`. */
|
|
27
|
+
export declare const COMMENT_SALT_FILE = "comment-salt";
|
|
28
|
+
/** The fields the comment form submits. */
|
|
29
|
+
export declare const COMMENT_FIELDS: {
|
|
30
|
+
/** The post being commented on, as its slug. */
|
|
31
|
+
readonly post: 'post';
|
|
32
|
+
/** The commenter's name. Required. */
|
|
33
|
+
readonly name: 'name';
|
|
34
|
+
/** Their email. Optional, and never shown. */
|
|
35
|
+
readonly email: 'email';
|
|
36
|
+
/** Their website. Optional. */
|
|
37
|
+
readonly url: 'url';
|
|
38
|
+
/** The comment itself, as Markdown. Required. */
|
|
39
|
+
readonly body: 'body';
|
|
40
|
+
/** The comment being answered, or empty for one answering the post. */
|
|
41
|
+
readonly inReplyTo: 'in_reply_to';
|
|
42
|
+
/** The honeypot, which every public form here spells the same way. */
|
|
43
|
+
readonly trap: "website";
|
|
44
|
+
/** When the form was rendered, in epoch milliseconds. */
|
|
45
|
+
readonly loaded: "loaded";
|
|
46
|
+
/**
|
|
47
|
+
* The CSRF token, which only the signed-in form carries (TASK-103).
|
|
48
|
+
*
|
|
49
|
+
* Spelled exactly as every admin form spells it, because it is the same
|
|
50
|
+
* per-session token and is checked by the same comparison.
|
|
51
|
+
*/
|
|
52
|
+
readonly csrf: "csrf_token";
|
|
53
|
+
/**
|
|
54
|
+
* "Tell me when somebody answers this."
|
|
55
|
+
*
|
|
56
|
+
* A checkbox, so any non-empty value is a yes. It only ever means anything
|
|
57
|
+
* alongside an email address, and the form only offers it when the site can
|
|
58
|
+
* actually send mail (TASK-55).
|
|
59
|
+
*/
|
|
60
|
+
readonly notify: 'notify';
|
|
61
|
+
};
|
|
62
|
+
/** A submitted comment form, as strings, which is what a form has. */
|
|
63
|
+
export type CommentForm = Record<'post' | 'name' | 'email' | 'url' | 'body' | 'inReplyTo' | 'trap' | 'loaded' | 'notify' | 'csrf', string>;
|
|
64
|
+
/** How many comments one address may post before it has to wait. */
|
|
65
|
+
export declare const COMMENT_RATE_LIMIT = 5;
|
|
66
|
+
/** How long that window is, and how long the first wait after it lasts. */
|
|
67
|
+
export declare const COMMENT_RATE_WINDOW_SECONDS = 600;
|
|
68
|
+
/** The longest a name may be. */
|
|
69
|
+
export declare const MAXIMUM_NAME_LENGTH = 80;
|
|
70
|
+
/** The longest an email or a website may be. */
|
|
71
|
+
export declare const MAXIMUM_URL_LENGTH = 500;
|
|
72
|
+
/** The longest a comment may be, in characters. */
|
|
73
|
+
export declare const MAXIMUM_BODY_LENGTH = 10000;
|
|
74
|
+
/** What a form got wrong, one message per field. Empty means it is fine. */
|
|
75
|
+
export type CommentProblems = Partial<Record<'name' | 'email' | 'url' | 'body', string>>;
|
|
76
|
+
/**
|
|
77
|
+
* What is wrong with a submitted comment, as a person would be told it.
|
|
78
|
+
*
|
|
79
|
+
* Only the things a person can fix. The honeypot, the form's age and the rate
|
|
80
|
+
* limit are not here: none of them is the commenter's mistake, and two of them
|
|
81
|
+
* should not be explained to whoever tripped them.
|
|
82
|
+
*
|
|
83
|
+
* A signed-in commenter is asked for nothing but the comment (TASK-103), so
|
|
84
|
+
* only the comment is checked: the name, the email and the website come off
|
|
85
|
+
* the account and there are no boxes on the form to put anything right in.
|
|
86
|
+
*/
|
|
87
|
+
export declare function commentProblems(form: CommentForm, signedIn?: boolean): CommentProblems;
|
|
88
|
+
/**
|
|
89
|
+
* What a checker is told a submission is.
|
|
90
|
+
*
|
|
91
|
+
* Akismet's `comment_type`, which is an open vocabulary with a handful of
|
|
92
|
+
* documented values. A checker is free to ignore it; the three here are the
|
|
93
|
+
* three this CMS can produce.
|
|
94
|
+
*/
|
|
95
|
+
export type SubmissionType =
|
|
96
|
+
/** Somebody filled in the comment form under a post. */
|
|
97
|
+
'comment'
|
|
98
|
+
/** Another site's page said it links here (TASK-51). */
|
|
99
|
+
| 'webmention'
|
|
100
|
+
/** Somebody filled in the contact form on a page (TASK-56). */
|
|
101
|
+
| 'contact-form';
|
|
102
|
+
/** Everything a checker is told about a comment on its way in. */
|
|
103
|
+
export interface CommentSubmission {
|
|
104
|
+
/** The comment as it would be stored, before anything has judged it. */
|
|
105
|
+
comment: Omit<PostComment, 'id'>;
|
|
106
|
+
/**
|
|
107
|
+
* What this is, when it is not what the comment's `source` would say.
|
|
108
|
+
*
|
|
109
|
+
* A contact message is judged through this same seam — the rules, the fields
|
|
110
|
+
* and the answers are the ones a comment gets, and a site that named a
|
|
111
|
+
* `commentChecker` of its own meant that checker to see everything the
|
|
112
|
+
* public can post at it. But it is not a comment on a post, and Akismet has
|
|
113
|
+
* a word for what it is, so the caller names it. Absent means the comment
|
|
114
|
+
* speaks for itself: `webmention` for one, `comment` for everything else.
|
|
115
|
+
*/
|
|
116
|
+
type?: SubmissionType | undefined;
|
|
117
|
+
/** The post it is on. */
|
|
118
|
+
post: {
|
|
119
|
+
/** Its slug. */
|
|
120
|
+
slug: string;
|
|
121
|
+
/** Its title, for a checker that reports to a human. */
|
|
122
|
+
title: string;
|
|
123
|
+
/** Its absolute URL, which is what Akismet calls the permalink. */
|
|
124
|
+
url: string;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Where the request came from, **unhashed**.
|
|
128
|
+
*
|
|
129
|
+
* A checker needs the address itself, and this is the only place it exists:
|
|
130
|
+
* the stored comment keeps a salted hash, because the file it lives in is
|
|
131
|
+
* published with the site.
|
|
132
|
+
*/
|
|
133
|
+
address: string | undefined;
|
|
134
|
+
/** The `User-Agent` the browser sent, as it sent it. */
|
|
135
|
+
userAgent: string | undefined;
|
|
136
|
+
/** The `Referer` the browser sent, which is the page the form was on. */
|
|
137
|
+
referrer: string | undefined;
|
|
138
|
+
/** The site's public origin. */
|
|
139
|
+
baseUrl: string;
|
|
140
|
+
}
|
|
141
|
+
/** What a stored comment's later reclassification tells the checker. */
|
|
142
|
+
export interface CommentReport {
|
|
143
|
+
/** The comment, as it now stands. */
|
|
144
|
+
comment: PostComment;
|
|
145
|
+
/** Its post's absolute URL. */
|
|
146
|
+
url: string;
|
|
147
|
+
/** The site's public origin. */
|
|
148
|
+
baseUrl: string;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* What a checker can say.
|
|
152
|
+
*
|
|
153
|
+
* `spam` files the comment as spam, where a moderator can see it and change
|
|
154
|
+
* its mind. `discard` throws it away without storing it at all, which is what
|
|
155
|
+
* a service says about traffic so obviously mechanical that a queue of it
|
|
156
|
+
* would only be noise. `ham` is a positive opinion and lets the comment
|
|
157
|
+
* through even where the site would have held it. `unknown` is no opinion, and
|
|
158
|
+
* is what a checker that could not be reached should return.
|
|
159
|
+
*/
|
|
160
|
+
export type CommentVerdict = 'spam' | 'discard' | 'ham' | 'unknown';
|
|
161
|
+
/**
|
|
162
|
+
* A third-party opinion on comments: the one seam anything like Akismet plugs
|
|
163
|
+
* into.
|
|
164
|
+
*
|
|
165
|
+
* A site names one as `commentChecker` in its config, and nothing else in the
|
|
166
|
+
* CMS knows the service exists. The two report methods are optional and are
|
|
167
|
+
* called when a moderator disagrees with what happened — marking an approved
|
|
168
|
+
* comment as spam, or letting one out of the spam list — because that
|
|
169
|
+
* correction is the only training signal such a service gets.
|
|
170
|
+
*/
|
|
171
|
+
export interface CommentChecker {
|
|
172
|
+
/** Judge a comment on its way in. */
|
|
173
|
+
check(submission: CommentSubmission): CommentVerdict | Promise<CommentVerdict>;
|
|
174
|
+
/** Told when a moderator files something as spam. */
|
|
175
|
+
reportSpam?(report: CommentReport): void | Promise<void>;
|
|
176
|
+
/** Told when a moderator says something was not spam after all. */
|
|
177
|
+
reportHam?(report: CommentReport): void | Promise<void>;
|
|
178
|
+
}
|
|
179
|
+
/** Why a submission did not become a comment. */
|
|
180
|
+
export type CommentRefusal =
|
|
181
|
+
/** The form said something a person can put right. */
|
|
182
|
+
{
|
|
183
|
+
kind: 'invalid';
|
|
184
|
+
problems: CommentProblems;
|
|
185
|
+
}
|
|
186
|
+
/** The form was submitted faster than a person types. */
|
|
187
|
+
| {
|
|
188
|
+
kind: 'too-quick';
|
|
189
|
+
}
|
|
190
|
+
/** The form was rendered too long ago to still be one. */
|
|
191
|
+
| {
|
|
192
|
+
kind: 'stale';
|
|
193
|
+
}
|
|
194
|
+
/** This address has posted enough for now. `retryAfter` is in seconds. */
|
|
195
|
+
| {
|
|
196
|
+
kind: 'rate-limited';
|
|
197
|
+
retryAfter: number;
|
|
198
|
+
}
|
|
199
|
+
/** The honeypot was filled in, or a checker said to throw it away. */
|
|
200
|
+
| {
|
|
201
|
+
kind: 'discarded';
|
|
202
|
+
};
|
|
203
|
+
/** What became of a submission. */
|
|
204
|
+
export type CommentOutcome = {
|
|
205
|
+
kind: 'stored';
|
|
206
|
+
comment: PostComment;
|
|
207
|
+
} | {
|
|
208
|
+
kind: 'refused';
|
|
209
|
+
refusal: CommentRefusal;
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* A comment's author as somebody other than the form says it.
|
|
213
|
+
*
|
|
214
|
+
* What a signed-in submission is attributed from: the account's name, its
|
|
215
|
+
* author archive as the website, and its email — which is stored and never
|
|
216
|
+
* shown, exactly as a stranger's is never shown. It is the stored author minus
|
|
217
|
+
* the one field no account can supply: a picture only ever arrives with a
|
|
218
|
+
* webmention (TASK-51).
|
|
219
|
+
*/
|
|
220
|
+
export type SignedInAuthor = Omit<CommentAuthor, 'avatar'>;
|
|
221
|
+
/** What {@link submitComment} needs around it. */
|
|
222
|
+
export interface SubmitCommentOptions {
|
|
223
|
+
/** The files and the index a stored comment goes into. */
|
|
224
|
+
records: CommentRecords;
|
|
225
|
+
/** The post being commented on. */
|
|
226
|
+
document: Document;
|
|
227
|
+
/** What was submitted. */
|
|
228
|
+
form: CommentForm;
|
|
229
|
+
/** Where the site keeps the address salt. */
|
|
230
|
+
dataDir: string;
|
|
231
|
+
/** The site's public origin, for the checker and the stored links. */
|
|
232
|
+
baseUrl: string;
|
|
233
|
+
/** The checker, when the site named one. */
|
|
234
|
+
checker?: CommentChecker | undefined;
|
|
235
|
+
/**
|
|
236
|
+
* Who the session says is commenting, when one does (TASK-103).
|
|
237
|
+
*
|
|
238
|
+
* Set, it is the whole of the comment's attribution: what was typed in a
|
|
239
|
+
* name, email or website field is ignored, because the signed-in form has no
|
|
240
|
+
* such fields and anything arriving in them was not put there by the person
|
|
241
|
+
* the session names. It also settles the three cheap defences — the honeypot
|
|
242
|
+
* and the form's age are there to catch a robot filling a public form, and a
|
|
243
|
+
* session is better evidence than either, so neither is checked — and it
|
|
244
|
+
* makes this a comment the site's own author is writing, which the intake
|
|
245
|
+
* approves on arrival and never offers to a checker.
|
|
246
|
+
*/
|
|
247
|
+
author?: SignedInAuthor | undefined;
|
|
248
|
+
/** Who to tell about what lands, handed straight to the intake (TASK-55). */
|
|
249
|
+
notices?: CommentNotices | undefined;
|
|
250
|
+
/** Where the request came from, as far as the site can tell. */
|
|
251
|
+
address?: string | undefined;
|
|
252
|
+
/** The `User-Agent` header, for the checker. */
|
|
253
|
+
userAgent?: string | undefined;
|
|
254
|
+
/** The `Referer` header, for the checker. */
|
|
255
|
+
referrer?: string | undefined;
|
|
256
|
+
/** The rate limiter, kept by the mount so it outlives one request. */
|
|
257
|
+
throttle: CommentThrottle;
|
|
258
|
+
/**
|
|
259
|
+
* Whether "tell me about replies" is worth recording, which it is when the
|
|
260
|
+
* site can send mail at all (TASK-55).
|
|
261
|
+
*
|
|
262
|
+
* Read per submission rather than assumed, so a site that has just pasted a
|
|
263
|
+
* mail credential starts honouring the box on the very next comment, and one
|
|
264
|
+
* that removed the credential stops storing an intention it cannot keep.
|
|
265
|
+
*/
|
|
266
|
+
notifiable?: boolean | undefined;
|
|
267
|
+
/** The clock. */
|
|
268
|
+
now?: Date | undefined;
|
|
269
|
+
}
|
|
270
|
+
/** The part of the login throttle a comment needs. */
|
|
271
|
+
export interface CommentThrottle {
|
|
272
|
+
/** Seconds before this address may post again, or `undefined`. */
|
|
273
|
+
retryAfter(keys: readonly string[]): number | undefined;
|
|
274
|
+
/** Count one submission against it. */
|
|
275
|
+
fail(keys: readonly string[]): void;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Take a submitted form and, if it survives everything, store the comment.
|
|
279
|
+
*
|
|
280
|
+
* The caller has already decided that the post is open: whether a form should
|
|
281
|
+
* exist at all is {@link commentsOpen}'s question, and asking it here as well
|
|
282
|
+
* would let the two answers differ.
|
|
283
|
+
*/
|
|
284
|
+
export declare function submitComment(options: SubmitCommentOptions): Promise<CommentOutcome>;
|
|
285
|
+
/** The keys a submission is rate limited against. */
|
|
286
|
+
export declare function commentKeys(address: string | undefined): string[];
|
|
287
|
+
/**
|
|
288
|
+
* A submitted website as the absolute URL it means, or `undefined` when it
|
|
289
|
+
* means none.
|
|
290
|
+
*
|
|
291
|
+
* A bare `example.com` becomes `https://example.com/`, because that is what
|
|
292
|
+
* somebody typing it meant and refusing it would be pedantry; anything whose
|
|
293
|
+
* scheme is not http or https is refused, because it is going on a page as a
|
|
294
|
+
* link.
|
|
295
|
+
*/
|
|
296
|
+
export declare function normalizeWebsite(value: string): string | undefined;
|
|
297
|
+
//# sourceMappingURL=submission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submission.d.ts","sourceRoot":"","sources":["../../src/comments/submission.ts"],"names":[],"mappings":"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"}
|