@geekity/cms 0.3.0 → 0.4.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 +2091 -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/pages/documents/editor.njk +196 -0
- 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/media/library.njk +160 -0
- package/admin/pages/messages/all.njk +110 -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/federation.njk +75 -0
- package/admin/pages/settings/general.njk +29 -0
- package/admin/pages/settings/permalinks.njk +50 -0
- package/admin/pages/settings/reading.njk +72 -0
- package/admin/pages/users/edit.njk +239 -0
- package/admin/pages/users/list.njk +48 -0
- package/admin/pages/users/new.njk +41 -0
- package/admin/static/admin.css +498 -3
- package/admin/static/copy.js +52 -0
- package/admin/static/editor.js +16 -16
- package/admin/static/slug.js +61 -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 +127 -10
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +360 -41
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/federation.d.ts +151 -50
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +225 -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 +126 -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/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 +155 -105
- package/dist/admin/routes.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 +39 -0
- package/dist/admin/settings-federation.d.ts.map +1 -0
- package/dist/admin/settings-federation.js +103 -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 +102 -0
- package/dist/admin/settings-page.d.ts.map +1 -0
- package/dist/admin/settings-page.js +126 -0
- package/dist/admin/settings-page.js.map +1 -0
- package/dist/admin/settings-pages.d.ts +19 -0
- package/dist/admin/settings-pages.d.ts.map +1 -0
- package/dist/admin/settings-pages.js +33 -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 +33 -0
- package/dist/admin/settings-reading.d.ts.map +1 -0
- package/dist/admin/settings-reading.js +48 -0
- package/dist/admin/settings-reading.js.map +1 -0
- package/dist/admin/settings.d.ts +325 -96
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +650 -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 +44 -14
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +44 -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/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 +424 -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 +75 -0
- package/dist/comments/form.d.ts.map +1 -0
- package/dist/comments/form.js +64 -0
- package/dist/comments/form.js.map +1 -0
- package/dist/comments/index.d.ts +15 -0
- package/dist/comments/index.d.ts.map +1 -0
- package/dist/comments/index.js +9 -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 +58 -0
- package/dist/comments/routes.d.ts.map +1 -0
- package/dist/comments/routes.js +177 -0
- package/dist/comments/routes.js.map +1 -0
- package/dist/comments/submission.d.ts +263 -0
- package/dist/comments/submission.d.ts.map +1 -0
- package/dist/comments/submission.js +241 -0
- package/dist/comments/submission.js.map +1 -0
- package/dist/config.d.ts +190 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +118 -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 +202 -7
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +374 -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 +58 -4
- 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 +42 -10
- package/dist/federation/mount.d.ts.map +1 -1
- package/dist/federation/mount.js +266 -26
- 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 +327 -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 +73 -0
- package/dist/web/navigation.d.ts.map +1 -0
- package/dist/web/navigation.js +110 -0
- package/dist/web/navigation.js.map +1 -0
- package/dist/web/negotiate.d.ts +9 -0
- package/dist/web/negotiate.d.ts.map +1 -1
- package/dist/web/negotiate.js +6 -1
- 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 +197 -9
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +334 -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 +845 -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 +205 -0
- package/dist/web/themes.d.ts.map +1 -0
- package/dist/web/themes.js +277 -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 +1 -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 +1096 -50
- package/themes/default/layouts/404.njk +2 -3
- package/themes/default/layouts/author.njk +37 -0
- package/themes/default/layouts/base.njk +172 -31
- package/themes/default/layouts/category.njk +27 -0
- package/themes/default/layouts/front-page.njk +57 -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 +77 -0
- package/themes/default/partials/comment-form.njk +109 -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/pagination.njk +12 -6
- package/themes/default/partials/post-list.njk +51 -18
- package/themes/default/partials/search-form.njk +17 -0
- package/themes/default/partials/tags.njk +26 -5
- package/themes/default/static/highlight.js +4 -0
- package/themes/default/static/style.css +1119 -194
- package/themes/default/theme.json +5 -0
- package/admin/layouts/document-editor.njk +0 -167
- 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,141 @@
|
|
|
1
|
+
import type { PostComment } from '../admin/store.ts';
|
|
2
|
+
import type { CommentNotices, CommentRecords } from '../comments/records.ts';
|
|
3
|
+
import type { CommentChecker } from '../comments/submission.ts';
|
|
4
|
+
import type { Document } from '../content/document.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Taking a webmention somebody sent this site.
|
|
7
|
+
*
|
|
8
|
+
* Two steps, and the split is the whole design. The endpoint decides in one
|
|
9
|
+
* request whether the thing it was handed could possibly be a webmention —
|
|
10
|
+
* two http URLs, not the same one, the target a page here — and answers 202 or
|
|
11
|
+
* 400 without touching the network. Everything that needs somebody else's
|
|
12
|
+
* server is done afterwards, out of the request: fetching the source, checking
|
|
13
|
+
* that it really links here, reading its microformats, and putting the result
|
|
14
|
+
* in the moderation queue.
|
|
15
|
+
*
|
|
16
|
+
* That is why a source that turns out to say nothing about this site still
|
|
17
|
+
* gets a 202. The spec allows exactly this, and the alternative — holding the
|
|
18
|
+
* connection open while a stranger's server is fetched — is a way of being
|
|
19
|
+
* held open by a stranger's server.
|
|
20
|
+
*
|
|
21
|
+
* What lands is a comment like any other (doc-6), and it lands the same way:
|
|
22
|
+
* this module reads what the source says and hands `intakeComment` a proposed
|
|
23
|
+
* comment, so the file, the index, the {@link CommentChecker} seam, the
|
|
24
|
+
* verdict-to-status rule and the notice are the very ones a form submission
|
|
25
|
+
* gets. That is how TASK-52 sends it to Akismet as a `webmention` without this
|
|
26
|
+
* module knowing Akismet exists, and how a moderator's decision on a mention
|
|
27
|
+
* survives the page that sent it being edited and re-sent.
|
|
28
|
+
*
|
|
29
|
+
* What it is not held by is the closing rules: a post that stopped taking
|
|
30
|
+
* comments a year ago still hears about a page that links to it, exactly as it
|
|
31
|
+
* still hears a fediverse reply, because neither is something this site can
|
|
32
|
+
* stop happening.
|
|
33
|
+
*/
|
|
34
|
+
/** How long the source is given to answer before it is abandoned. */
|
|
35
|
+
export declare const VERIFY_TIMEOUT_MS = 15000;
|
|
36
|
+
/** One webmention as it arrived, before anything has been fetched. */
|
|
37
|
+
export interface IncomingWebmention {
|
|
38
|
+
/** The page claiming to link here. */
|
|
39
|
+
readonly source: string;
|
|
40
|
+
/** The page on this site it claims to link to. */
|
|
41
|
+
readonly target: string;
|
|
42
|
+
/** The post that target names. */
|
|
43
|
+
readonly document: Document;
|
|
44
|
+
/** Where the request came from, **unhashed**, for the checker. */
|
|
45
|
+
readonly address?: string | undefined;
|
|
46
|
+
/** The `User-Agent` the sender sent. */
|
|
47
|
+
readonly userAgent?: string | undefined;
|
|
48
|
+
/** The `Referer` the sender sent. */
|
|
49
|
+
readonly referrer?: string | undefined;
|
|
50
|
+
}
|
|
51
|
+
/** What one submitted pair turned out to be. */
|
|
52
|
+
export type WebmentionRequest =
|
|
53
|
+
/** Worth checking: the target is a page here and the source might link to it. */
|
|
54
|
+
{
|
|
55
|
+
readonly ok: true;
|
|
56
|
+
readonly source: string;
|
|
57
|
+
readonly target: string;
|
|
58
|
+
readonly document: Document;
|
|
59
|
+
}
|
|
60
|
+
/** Not a webmention at all, with the reason a sender is told. */
|
|
61
|
+
| {
|
|
62
|
+
readonly ok: false;
|
|
63
|
+
readonly message: string;
|
|
64
|
+
};
|
|
65
|
+
/** What {@link checkWebmentionRequest} needs to answer. */
|
|
66
|
+
export interface CheckWebmentionOptions {
|
|
67
|
+
/** The site's public origin. */
|
|
68
|
+
readonly baseUrl: string;
|
|
69
|
+
/** The public document one of this site's paths names, or `undefined`. */
|
|
70
|
+
readonly documentAt: (pathname: string) => Document | undefined;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Whether a submitted `source` and `target` are worth going and looking at.
|
|
74
|
+
*
|
|
75
|
+
* Everything here is decided from the two strings and this site's own index —
|
|
76
|
+
* nothing is fetched — because this is what a 400 has to be decided from: the
|
|
77
|
+
* spec wants a synchronous answer, and a synchronous answer must not depend on
|
|
78
|
+
* a stranger's server.
|
|
79
|
+
*/
|
|
80
|
+
export declare function checkWebmentionRequest(source: string, target: string, options: CheckWebmentionOptions): WebmentionRequest;
|
|
81
|
+
/** What {@link verifyWebmention} needs around it. */
|
|
82
|
+
export interface VerifyWebmentionOptions {
|
|
83
|
+
/** The webmention to check. */
|
|
84
|
+
readonly incoming: IncomingWebmention;
|
|
85
|
+
/** The comment files and the index over them. */
|
|
86
|
+
readonly records: CommentRecords;
|
|
87
|
+
/** Where the address salt lives. */
|
|
88
|
+
readonly dataDir: string;
|
|
89
|
+
/** The site's public origin. */
|
|
90
|
+
readonly baseUrl: string;
|
|
91
|
+
/** The checker, when the site named one. */
|
|
92
|
+
readonly checker?: CommentChecker | undefined;
|
|
93
|
+
/** Who to tell when one lands in the queue, handed to the intake (TASK-55). */
|
|
94
|
+
readonly notices?: CommentNotices | undefined;
|
|
95
|
+
/** The clock. */
|
|
96
|
+
readonly now: Date;
|
|
97
|
+
/** Where failures are reported. */
|
|
98
|
+
readonly logger: {
|
|
99
|
+
warn(message: string): void;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** What became of one verification. */
|
|
103
|
+
export type WebmentionOutcome =
|
|
104
|
+
/**
|
|
105
|
+
* The source links here and the comment was written or rewritten.
|
|
106
|
+
*
|
|
107
|
+
* `created` says which. A page that sends its webmention again every time it
|
|
108
|
+
* is edited would otherwise put the moderators through a notification each
|
|
109
|
+
* time (TASK-55), for an entry that has been in the queue all along.
|
|
110
|
+
*/
|
|
111
|
+
{
|
|
112
|
+
readonly kind: 'stored';
|
|
113
|
+
readonly comment: PostComment;
|
|
114
|
+
readonly created: boolean;
|
|
115
|
+
}
|
|
116
|
+
/** The source does not link here any more, and what it left is gone. */
|
|
117
|
+
| {
|
|
118
|
+
readonly kind: 'deleted';
|
|
119
|
+
}
|
|
120
|
+
/** The source does not link here, and there was nothing to remove. */
|
|
121
|
+
| {
|
|
122
|
+
readonly kind: 'ignored';
|
|
123
|
+
}
|
|
124
|
+
/** The source could not be read this time; whatever is stored stands. */
|
|
125
|
+
| {
|
|
126
|
+
readonly kind: 'unreachable';
|
|
127
|
+
readonly reason: string;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Go and look at the source, and put what it says in the queue.
|
|
131
|
+
*
|
|
132
|
+
* The three endings are the three things a source can be. A page that links
|
|
133
|
+
* here is stored, or rewritten where this site already has one from it — the
|
|
134
|
+
* source URL is the identity, so a blog post edited and re-sent updates its
|
|
135
|
+
* comment instead of adding a second. A page that has stopped linking here, or
|
|
136
|
+
* that has gone, takes its comment with it, which is the only way a webmention
|
|
137
|
+
* can be withdrawn. A page that could not be read at all changes nothing: a
|
|
138
|
+
* server having a bad afternoon must not delete what it said last week.
|
|
139
|
+
*/
|
|
140
|
+
export declare function verifyWebmention(options: VerifyWebmentionOptions): Promise<WebmentionOutcome>;
|
|
141
|
+
//# sourceMappingURL=receive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../../src/webmention/receive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { deleteComment, heldWebmention, intakeComment } from '../comments/records.js';
|
|
2
|
+
import { sanitizeCommentHtml } from '../web/sanitize.js';
|
|
3
|
+
import { readCapped, WEBMENTION_USER_AGENT } from './discovery.js';
|
|
4
|
+
import { linksTo, sourceEntry } from './microformats.js';
|
|
5
|
+
/**
|
|
6
|
+
* Taking a webmention somebody sent this site.
|
|
7
|
+
*
|
|
8
|
+
* Two steps, and the split is the whole design. The endpoint decides in one
|
|
9
|
+
* request whether the thing it was handed could possibly be a webmention —
|
|
10
|
+
* two http URLs, not the same one, the target a page here — and answers 202 or
|
|
11
|
+
* 400 without touching the network. Everything that needs somebody else's
|
|
12
|
+
* server is done afterwards, out of the request: fetching the source, checking
|
|
13
|
+
* that it really links here, reading its microformats, and putting the result
|
|
14
|
+
* in the moderation queue.
|
|
15
|
+
*
|
|
16
|
+
* That is why a source that turns out to say nothing about this site still
|
|
17
|
+
* gets a 202. The spec allows exactly this, and the alternative — holding the
|
|
18
|
+
* connection open while a stranger's server is fetched — is a way of being
|
|
19
|
+
* held open by a stranger's server.
|
|
20
|
+
*
|
|
21
|
+
* What lands is a comment like any other (doc-6), and it lands the same way:
|
|
22
|
+
* this module reads what the source says and hands `intakeComment` a proposed
|
|
23
|
+
* comment, so the file, the index, the {@link CommentChecker} seam, the
|
|
24
|
+
* verdict-to-status rule and the notice are the very ones a form submission
|
|
25
|
+
* gets. That is how TASK-52 sends it to Akismet as a `webmention` without this
|
|
26
|
+
* module knowing Akismet exists, and how a moderator's decision on a mention
|
|
27
|
+
* survives the page that sent it being edited and re-sent.
|
|
28
|
+
*
|
|
29
|
+
* What it is not held by is the closing rules: a post that stopped taking
|
|
30
|
+
* comments a year ago still hears about a page that links to it, exactly as it
|
|
31
|
+
* still hears a fediverse reply, because neither is something this site can
|
|
32
|
+
* stop happening.
|
|
33
|
+
*/
|
|
34
|
+
/** How long the source is given to answer before it is abandoned. */
|
|
35
|
+
export const VERIFY_TIMEOUT_MS = 15_000;
|
|
36
|
+
/**
|
|
37
|
+
* Whether a submitted `source` and `target` are worth going and looking at.
|
|
38
|
+
*
|
|
39
|
+
* Everything here is decided from the two strings and this site's own index —
|
|
40
|
+
* nothing is fetched — because this is what a 400 has to be decided from: the
|
|
41
|
+
* spec wants a synchronous answer, and a synchronous answer must not depend on
|
|
42
|
+
* a stranger's server.
|
|
43
|
+
*/
|
|
44
|
+
export function checkWebmentionRequest(source, target, options) {
|
|
45
|
+
if (source.trim() === '' || target.trim() === '') {
|
|
46
|
+
return refuse('A webmention needs both a source and a target.');
|
|
47
|
+
}
|
|
48
|
+
const from = webUrl(source);
|
|
49
|
+
const to = webUrl(target);
|
|
50
|
+
if (from === undefined)
|
|
51
|
+
return refuse('The source is not an http or https URL.');
|
|
52
|
+
if (to === undefined)
|
|
53
|
+
return refuse('The target is not an http or https URL.');
|
|
54
|
+
if (from.href === to.href)
|
|
55
|
+
return refuse('The source and the target are the same page.');
|
|
56
|
+
// A source on a loopback or private address is not somebody else's page: it
|
|
57
|
+
// is this network, and fetching it would make the site a way of reaching
|
|
58
|
+
// machines nobody outside can reach. This stops the obvious spelling of that
|
|
59
|
+
// and not a name that resolves to one — a receiver that has to be sure needs
|
|
60
|
+
// to check the address it actually connects to.
|
|
61
|
+
if (isPrivateHost(from.hostname))
|
|
62
|
+
return refuse('The source is not a public URL.');
|
|
63
|
+
const site = webUrl(options.baseUrl);
|
|
64
|
+
if (site === undefined || to.origin !== site.origin) {
|
|
65
|
+
return refuse('The target is not a page on this site.');
|
|
66
|
+
}
|
|
67
|
+
const document = options.documentAt(to.pathname);
|
|
68
|
+
if (document === undefined)
|
|
69
|
+
return refuse('There is no page here at that address.');
|
|
70
|
+
return { ok: true, source: from.href, target: to.href, document };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Go and look at the source, and put what it says in the queue.
|
|
74
|
+
*
|
|
75
|
+
* The three endings are the three things a source can be. A page that links
|
|
76
|
+
* here is stored, or rewritten where this site already has one from it — the
|
|
77
|
+
* source URL is the identity, so a blog post edited and re-sent updates its
|
|
78
|
+
* comment instead of adding a second. A page that has stopped linking here, or
|
|
79
|
+
* that has gone, takes its comment with it, which is the only way a webmention
|
|
80
|
+
* can be withdrawn. A page that could not be read at all changes nothing: a
|
|
81
|
+
* server having a bad afternoon must not delete what it said last week.
|
|
82
|
+
*/
|
|
83
|
+
export async function verifyWebmention(options) {
|
|
84
|
+
const { incoming, records, now } = options;
|
|
85
|
+
const held = heldWebmention(records, incoming.document.slug, incoming.source);
|
|
86
|
+
const fetched = await readSource(incoming.source);
|
|
87
|
+
if (fetched.kind === 'unreachable') {
|
|
88
|
+
options.logger.warn(`Could not read ${incoming.source} to verify a webmention: ${fetched.reason}`);
|
|
89
|
+
return { kind: 'unreachable', reason: fetched.reason };
|
|
90
|
+
}
|
|
91
|
+
if (fetched.kind === 'gone' || !mentions(fetched, incoming)) {
|
|
92
|
+
if (held === undefined)
|
|
93
|
+
return { kind: 'ignored' };
|
|
94
|
+
await deleteComment(records, held.id);
|
|
95
|
+
return { kind: 'deleted' };
|
|
96
|
+
}
|
|
97
|
+
const entry = fetched.html
|
|
98
|
+
? sourceEntry(fetched.body, fetched.url, incoming.target)
|
|
99
|
+
: // A source that is not HTML — plain text, JSON, anything — has no
|
|
100
|
+
// microformats to read, so all that can be said about it is that it
|
|
101
|
+
// links here.
|
|
102
|
+
undefined;
|
|
103
|
+
const kind = entry?.kind ?? 'mention';
|
|
104
|
+
const author = {
|
|
105
|
+
name: entry?.author.name !== undefined && entry.author.name !== ''
|
|
106
|
+
? entry.author.name
|
|
107
|
+
: hostOf(incoming.source),
|
|
108
|
+
url: entry?.author.url ?? null,
|
|
109
|
+
email: null,
|
|
110
|
+
avatar: entry?.author.photo ?? null,
|
|
111
|
+
};
|
|
112
|
+
// A like and a repost say nothing: the page's title is a title, not a
|
|
113
|
+
// comment, and printing it under a post as though somebody wrote it would be
|
|
114
|
+
// putting words in their mouth.
|
|
115
|
+
const wordless = kind === 'like' || kind === 'repost';
|
|
116
|
+
const text = wordless ? '' : (entry?.content.text ?? '');
|
|
117
|
+
const html = wordless
|
|
118
|
+
? ''
|
|
119
|
+
: entry !== undefined && entry.content.html !== ''
|
|
120
|
+
? sanitizeCommentHtml(entry.content.html)
|
|
121
|
+
: paragraph(text);
|
|
122
|
+
const proposed = {
|
|
123
|
+
slug: incoming.document.slug,
|
|
124
|
+
permalink: incoming.document.permalink,
|
|
125
|
+
source: 'webmention',
|
|
126
|
+
kind,
|
|
127
|
+
author,
|
|
128
|
+
content: { markdown: text, html },
|
|
129
|
+
submitted: entry?.published ?? now.toISOString(),
|
|
130
|
+
inReplyTo: null,
|
|
131
|
+
// The URL it was sent from rather than the entry's own `u-url`: this is
|
|
132
|
+
// the identity a later webmention is matched against, and the sender is
|
|
133
|
+
// the one who chose it.
|
|
134
|
+
url: incoming.source,
|
|
135
|
+
// A page has nobody to ask, and no address to ask them at.
|
|
136
|
+
notify: false,
|
|
137
|
+
};
|
|
138
|
+
const outcome = await intakeComment({
|
|
139
|
+
records,
|
|
140
|
+
origin: 'webmention',
|
|
141
|
+
comment: proposed,
|
|
142
|
+
// The target as its sender named it, rather than this site's own idea of
|
|
143
|
+
// the permalink: that is the URL the conversation is about.
|
|
144
|
+
post: { title: incoming.document.title, url: incoming.target },
|
|
145
|
+
dataDir: options.dataDir,
|
|
146
|
+
baseUrl: options.baseUrl,
|
|
147
|
+
checker: options.checker,
|
|
148
|
+
notices: options.notices,
|
|
149
|
+
address: incoming.address,
|
|
150
|
+
userAgent: incoming.userAgent,
|
|
151
|
+
referrer: incoming.referrer,
|
|
152
|
+
logger: options.logger,
|
|
153
|
+
});
|
|
154
|
+
if (outcome.kind === 'stored') {
|
|
155
|
+
return { kind: 'stored', comment: outcome.comment, created: outcome.created };
|
|
156
|
+
}
|
|
157
|
+
// A source nobody was holding anything from leaves nothing behind, and one
|
|
158
|
+
// whose entry went while this was deciding has already been dealt with.
|
|
159
|
+
return outcome.kind === 'discarded' && outcome.removed
|
|
160
|
+
? { kind: 'deleted' }
|
|
161
|
+
: { kind: 'ignored' };
|
|
162
|
+
}
|
|
163
|
+
/** Fetch a source page, following redirects and reading no more than a page. */
|
|
164
|
+
async function readSource(source) {
|
|
165
|
+
let response;
|
|
166
|
+
try {
|
|
167
|
+
response = await fetch(source, {
|
|
168
|
+
headers: { accept: 'text/html, */*;q=0.8', 'user-agent': WEBMENTION_USER_AGENT },
|
|
169
|
+
redirect: 'follow',
|
|
170
|
+
signal: AbortSignal.timeout(VERIFY_TIMEOUT_MS),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
catch (thrown) {
|
|
174
|
+
return { kind: 'unreachable', reason: messageOf(thrown) };
|
|
175
|
+
}
|
|
176
|
+
if (!response.ok) {
|
|
177
|
+
await response.body?.cancel();
|
|
178
|
+
// A page the server says is not there is a page that is not linking here.
|
|
179
|
+
// A server that is broken is a different thing and takes nothing with it.
|
|
180
|
+
if (response.status >= 400 && response.status < 500)
|
|
181
|
+
return { kind: 'gone' };
|
|
182
|
+
return { kind: 'unreachable', reason: `answered ${String(response.status)}` };
|
|
183
|
+
}
|
|
184
|
+
const type = response.headers.get('content-type') ?? '';
|
|
185
|
+
return {
|
|
186
|
+
kind: 'read',
|
|
187
|
+
body: await readCapped(response),
|
|
188
|
+
url: response.url === '' ? source : response.url,
|
|
189
|
+
html: /^\s*(text\/html|application\/xhtml\+xml)/i.test(type),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Whether what was read really links to the target.
|
|
194
|
+
*
|
|
195
|
+
* HTML is parsed, because a link is a link and the target written out in the
|
|
196
|
+
* prose is not one. Anything else — plain text, JSON, whatever somebody chose
|
|
197
|
+
* to publish — is searched for the target as it stands, which is all a format
|
|
198
|
+
* with no links can offer and what the spec asks for.
|
|
199
|
+
*/
|
|
200
|
+
function mentions(fetched, incoming) {
|
|
201
|
+
return fetched.html
|
|
202
|
+
? linksTo(fetched.body, fetched.url, incoming.target)
|
|
203
|
+
: fetched.body.includes(incoming.target);
|
|
204
|
+
}
|
|
205
|
+
/** A URL, when it is an http or https one, and `undefined` otherwise. */
|
|
206
|
+
function webUrl(value) {
|
|
207
|
+
let url;
|
|
208
|
+
try {
|
|
209
|
+
url = new URL(value.trim());
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:')
|
|
215
|
+
return undefined;
|
|
216
|
+
if (url.hostname === '')
|
|
217
|
+
return undefined;
|
|
218
|
+
return url;
|
|
219
|
+
}
|
|
220
|
+
/** Whether a hostname is one only this network can see. */
|
|
221
|
+
function isPrivateHost(hostname) {
|
|
222
|
+
const host = hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
|
223
|
+
if (host === 'localhost' || host.endsWith('.localhost') || host.endsWith('.local'))
|
|
224
|
+
return true;
|
|
225
|
+
if (host === '::1' || host === '0.0.0.0')
|
|
226
|
+
return true;
|
|
227
|
+
if (host.startsWith('fc') || host.startsWith('fd') || host.startsWith('fe80:'))
|
|
228
|
+
return true;
|
|
229
|
+
const parts = host.split('.');
|
|
230
|
+
if (parts.length !== 4 || parts.some((part) => !/^\d{1,3}$/.test(part)))
|
|
231
|
+
return false;
|
|
232
|
+
const [a = 0, b = 0] = parts.map(Number);
|
|
233
|
+
if (a === 127 || a === 10 || a === 0)
|
|
234
|
+
return true;
|
|
235
|
+
if (a === 192 && b === 168)
|
|
236
|
+
return true;
|
|
237
|
+
if (a === 169 && b === 254)
|
|
238
|
+
return true;
|
|
239
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
240
|
+
return true;
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
/** The host a source is on, for a page that never says who wrote it. */
|
|
244
|
+
function hostOf(source) {
|
|
245
|
+
try {
|
|
246
|
+
return new URL(source).host;
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return source;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/** A line of text as the one paragraph of HTML it is. */
|
|
253
|
+
function paragraph(text) {
|
|
254
|
+
if (text === '')
|
|
255
|
+
return '';
|
|
256
|
+
return `<p>${text.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>')}</p>`;
|
|
257
|
+
}
|
|
258
|
+
function refuse(message) {
|
|
259
|
+
return { ok: false, message };
|
|
260
|
+
}
|
|
261
|
+
function messageOf(error) {
|
|
262
|
+
return error instanceof Error ? error.message : String(error);
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=receive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receive.js","sourceRoot":"","sources":["../../src/webmention/receive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
import type { GeekityEnv } from '../env.ts';
|
|
3
|
+
/**
|
|
4
|
+
* The one public endpoint webmentions add.
|
|
5
|
+
*
|
|
6
|
+
* A single path under `/_geekity/`, like the comment form's, so it is out of
|
|
7
|
+
* the way of every permalink a site might ever mint and the route table does
|
|
8
|
+
* not grow with the site. It is what the `Link` header and the `<link>` in
|
|
9
|
+
* every post's head point at, and it takes nothing but a form with a `source`
|
|
10
|
+
* and a `target` in it.
|
|
11
|
+
*/
|
|
12
|
+
/** Where a webmention is sent. */
|
|
13
|
+
export declare const WEBMENTION_PATH = "/_geekity/webmention";
|
|
14
|
+
/** The fields a webmention carries, which the spec fixes. */
|
|
15
|
+
export declare const WEBMENTION_FIELDS: {
|
|
16
|
+
readonly source: 'source';
|
|
17
|
+
readonly target: 'target';
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The endpoint a page should advertise, or `undefined` when the site is not
|
|
21
|
+
* taking webmentions.
|
|
22
|
+
*
|
|
23
|
+
* Read off the site data the renderer already has rather than the settings, so
|
|
24
|
+
* a template asks one question and gets the same answer the endpoint gives.
|
|
25
|
+
* A file that does not mention the setting is a site that takes them: that is
|
|
26
|
+
* the default, and an older `site.json` should not quietly stop.
|
|
27
|
+
*/
|
|
28
|
+
export declare function webmentionEndpointFor(site: Record<string, unknown>): string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Register the webmention endpoint. Mounted by the public site.
|
|
31
|
+
*
|
|
32
|
+
* The answer is a 202 for anything worth going and looking at and a 400 for
|
|
33
|
+
* anything that is not, and the looking happens afterwards — see
|
|
34
|
+
* `receive.ts` for why that split is the whole design.
|
|
35
|
+
*/
|
|
36
|
+
export declare function mountWebmentions(app: Hono<GeekityEnv>): void;
|
|
37
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/webmention/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAIjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAI5C;;;;;;;;GAQG;AAEH,kCAAkC;AAClC,eAAO,MAAM,eAAe,yBAAyB,CAAC;AAEtD,6DAA6D;AAC7D,eAAO,MAAM,iBAAiB;aAAK,MAAM,EAAE,QAAQ;aAAE,MAAM,EAAE,QAAQ;CAAW,CAAC;AAEjF;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAEvF;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CA0C5D"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { readSiteSettings } from '../admin/settings.js';
|
|
2
|
+
import { clientAddress } from '../admin/throttle.js';
|
|
3
|
+
import { publicDocumentAt } from '../web/documents.js';
|
|
4
|
+
import { checkWebmentionRequest } from './receive.js';
|
|
5
|
+
/**
|
|
6
|
+
* The one public endpoint webmentions add.
|
|
7
|
+
*
|
|
8
|
+
* A single path under `/_geekity/`, like the comment form's, so it is out of
|
|
9
|
+
* the way of every permalink a site might ever mint and the route table does
|
|
10
|
+
* not grow with the site. It is what the `Link` header and the `<link>` in
|
|
11
|
+
* every post's head point at, and it takes nothing but a form with a `source`
|
|
12
|
+
* and a `target` in it.
|
|
13
|
+
*/
|
|
14
|
+
/** Where a webmention is sent. */
|
|
15
|
+
export const WEBMENTION_PATH = '/_geekity/webmention';
|
|
16
|
+
/** The fields a webmention carries, which the spec fixes. */
|
|
17
|
+
export const WEBMENTION_FIELDS = { source: 'source', target: 'target' };
|
|
18
|
+
/**
|
|
19
|
+
* The endpoint a page should advertise, or `undefined` when the site is not
|
|
20
|
+
* taking webmentions.
|
|
21
|
+
*
|
|
22
|
+
* Read off the site data the renderer already has rather than the settings, so
|
|
23
|
+
* a template asks one question and gets the same answer the endpoint gives.
|
|
24
|
+
* A file that does not mention the setting is a site that takes them: that is
|
|
25
|
+
* the default, and an older `site.json` should not quietly stop.
|
|
26
|
+
*/
|
|
27
|
+
export function webmentionEndpointFor(site) {
|
|
28
|
+
return site['webmentionsReceive'] === false ? undefined : WEBMENTION_PATH;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Register the webmention endpoint. Mounted by the public site.
|
|
32
|
+
*
|
|
33
|
+
* The answer is a 202 for anything worth going and looking at and a 400 for
|
|
34
|
+
* anything that is not, and the looking happens afterwards — see
|
|
35
|
+
* `receive.ts` for why that split is the whole design.
|
|
36
|
+
*/
|
|
37
|
+
export function mountWebmentions(app) {
|
|
38
|
+
app.post(WEBMENTION_PATH, async (c) => {
|
|
39
|
+
const { store, config, webmentions } = c.var;
|
|
40
|
+
if (!readSiteSettings(config.contentDir).webmentionsReceive) {
|
|
41
|
+
// A 404 rather than a 403: a site that does not take webmentions has no
|
|
42
|
+
// endpoint, and that is what having no endpoint looks like.
|
|
43
|
+
return c.text('This site does not take webmentions.', 404);
|
|
44
|
+
}
|
|
45
|
+
const body = await c.req.parseBody();
|
|
46
|
+
const checked = checkWebmentionRequest(text(body[WEBMENTION_FIELDS.source]), text(body[WEBMENTION_FIELDS.target]), {
|
|
47
|
+
baseUrl: config.baseUrl,
|
|
48
|
+
documentAt: (pathname) => publicDocumentAt(store, pathname),
|
|
49
|
+
});
|
|
50
|
+
if (!checked.ok)
|
|
51
|
+
return c.text(checked.message, 400);
|
|
52
|
+
// Nothing waits for the check: the sender is answered now and the source
|
|
53
|
+
// is fetched afterwards, and `receive` never rejects.
|
|
54
|
+
void webmentions.receive({
|
|
55
|
+
source: checked.source,
|
|
56
|
+
target: checked.target,
|
|
57
|
+
document: checked.document,
|
|
58
|
+
address: clientAddress(c, config),
|
|
59
|
+
userAgent: c.req.header('user-agent'),
|
|
60
|
+
referrer: c.req.header('referer'),
|
|
61
|
+
});
|
|
62
|
+
return c.text('Accepted. The source will be checked shortly.', 202);
|
|
63
|
+
});
|
|
64
|
+
// A GET on the endpoint is somebody looking rather than sending, and saying
|
|
65
|
+
// so is friendlier than a 404 on a URL that is really there.
|
|
66
|
+
app.get(WEBMENTION_PATH, (c) => {
|
|
67
|
+
c.header('allow', 'POST');
|
|
68
|
+
return c.text('Send a webmention here with a POST carrying source and target.', 405);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** A form field as a string. A file upload, or a missing field, is the empty one. */
|
|
72
|
+
function text(value) {
|
|
73
|
+
return typeof value === 'string' ? value : '';
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/webmention/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { AdminStore, SentWebmention } from '../admin/store.ts';
|
|
2
|
+
import type { CommentNotices } from '../comments/records.ts';
|
|
3
|
+
import type { ResolvedConfig } from '../config.ts';
|
|
4
|
+
import type { ContentStore } from '../content/store.ts';
|
|
5
|
+
import type { DocumentChange } from '../content/sync.ts';
|
|
6
|
+
import type { IncomingWebmention, WebmentionOutcome } from './receive.ts';
|
|
7
|
+
/**
|
|
8
|
+
* Telling the pages a post links to that it links to them.
|
|
9
|
+
*
|
|
10
|
+
* The other half of the same conversation the fediverse carries: a post is
|
|
11
|
+
* published, and everything it points at is asked whether it takes webmentions
|
|
12
|
+
* and told if it does. It is driven by the same index changes delivery is —
|
|
13
|
+
* a post saved in the editor and a post edited on disk are one thing here —
|
|
14
|
+
* and, like delivery, it ignores a full scan: the boot scan reports a cold
|
|
15
|
+
* index as a directory full of creations, and notifying every page the archive
|
|
16
|
+
* has ever linked to every time somebody deleted the database would be a
|
|
17
|
+
* denial of service with this site's name on it.
|
|
18
|
+
*
|
|
19
|
+
* What is recorded is a cache of outcomes, one row per (post, target), exactly
|
|
20
|
+
* as `ap_deliveries` is (decision-9): the links themselves are in the post's
|
|
21
|
+
* file, so a database thrown away costs the record of how it went and nothing
|
|
22
|
+
* else — and {@link WebmentionSender.send} reads the file again rather than
|
|
23
|
+
* replaying anything.
|
|
24
|
+
*/
|
|
25
|
+
/** How long one webmention POST is given before it is abandoned. */
|
|
26
|
+
export declare const SEND_TIMEOUT_MS = 10000;
|
|
27
|
+
/** What one post's links came to. */
|
|
28
|
+
export interface WebmentionReport {
|
|
29
|
+
/** The post they were in. */
|
|
30
|
+
readonly slug: string;
|
|
31
|
+
/** Its absolute URL, which is the `source` that was sent. */
|
|
32
|
+
readonly source: string;
|
|
33
|
+
/** One row per external link, in the order the post links to them. */
|
|
34
|
+
readonly sent: readonly SentWebmention[];
|
|
35
|
+
}
|
|
36
|
+
/** Where a service reports what it could not do. `console` will do. */
|
|
37
|
+
export interface WebmentionLogger {
|
|
38
|
+
warn(message: string): void;
|
|
39
|
+
}
|
|
40
|
+
/** What {@link createWebmentionService} needs. */
|
|
41
|
+
export interface CreateWebmentionServiceOptions {
|
|
42
|
+
/** Where the outcomes are recorded, and where the comment index lives. */
|
|
43
|
+
admin: AdminStore;
|
|
44
|
+
/** The content index, which a resend reads the post out of. */
|
|
45
|
+
store: ContentStore;
|
|
46
|
+
/**
|
|
47
|
+
* Config after defaults: the base URL, the content and data directories, the
|
|
48
|
+
* clock, and the checker an incoming webmention is put through.
|
|
49
|
+
*/
|
|
50
|
+
config: Pick<ResolvedConfig, 'baseUrl' | 'contentDir' | 'dataDir' | 'now' | 'commentChecker'>;
|
|
51
|
+
/** Where failures are reported. Defaults to `console`. */
|
|
52
|
+
logger?: WebmentionLogger | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Who to tell when an incoming webmention lands in the queue (TASK-55).
|
|
55
|
+
*
|
|
56
|
+
* Handed straight to the intake, which decides whether this one is worth a
|
|
57
|
+
* message. Optional, because a service built for a test of sending has
|
|
58
|
+
* nobody to tell; the CMS always hands one in.
|
|
59
|
+
*/
|
|
60
|
+
notifications?: CommentNotices | undefined;
|
|
61
|
+
}
|
|
62
|
+
/** Sends a site's webmentions, takes the ones sent to it, and remembers both. */
|
|
63
|
+
export interface WebmentionService {
|
|
64
|
+
/**
|
|
65
|
+
* Consider one index change and tell whatever pages it moved. Returns as
|
|
66
|
+
* soon as the sends are queued rather than when they are answered — a save
|
|
67
|
+
* is not something a stranger's server should be able to hold up.
|
|
68
|
+
*/
|
|
69
|
+
handle(change: DocumentChange): void;
|
|
70
|
+
/**
|
|
71
|
+
* Send one post's webmentions again, from the file as it now reads.
|
|
72
|
+
*
|
|
73
|
+
* Not "send those again": the links are read out of the post at the moment
|
|
74
|
+
* this is called (decision-9), so a link added since the last publish goes
|
|
75
|
+
* out and one taken out is told, which is what somebody pressing Resend is
|
|
76
|
+
* asking for. `undefined` when no post answers to that slug.
|
|
77
|
+
*/
|
|
78
|
+
send(slug: string): Promise<WebmentionReport | undefined>;
|
|
79
|
+
/**
|
|
80
|
+
* Take one webmention the endpoint has accepted and check it, out of the
|
|
81
|
+
* request that brought it.
|
|
82
|
+
*
|
|
83
|
+
* Returns as soon as it is queued — the sender has already had its 202, and
|
|
84
|
+
* fetching a stranger's page is not something a stranger's connection should
|
|
85
|
+
* be held open for. The promise it hands back is for a test, or for a caller
|
|
86
|
+
* that wants to know what became of one; nothing has to look at it.
|
|
87
|
+
*/
|
|
88
|
+
receive(incoming: IncomingWebmention): Promise<WebmentionOutcome>;
|
|
89
|
+
/** Resolve once every queued send and check has finished, however it finished. */
|
|
90
|
+
settled(): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
/** Build the webmention service for one site. */
|
|
93
|
+
export declare function createWebmentionService(options: CreateWebmentionServiceOptions): WebmentionService;
|
|
94
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/webmention/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAwB,MAAM,mBAAmB,CAAC;AAC1F,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAMzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE1E;;;;;;;;;;;;;;;;;GAiBG;AAEH,oEAAoE;AACpE,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,CAAC;CAC1C;AAED,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,kDAAkD;AAClD,MAAM,WAAW,8BAA8B;IAC7C,0EAA0E;IAC1E,KAAK,EAAE,UAAU,CAAC;IAClB,+DAA+D;IAC/D,KAAK,EAAE,YAAY,CAAC;IACpB;;;OAGG;IACH,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,gBAAgB,CAAC,CAAC;IAC9F,0DAA0D;IAC1D,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACtC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CAC5C;AAED,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACrC;;;;;;;OAOG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IAC1D;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClE,kFAAkF;IAClF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,iDAAiD;AACjD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,8BAA8B,GACtC,iBAAiB,CAsKnB"}
|