@geekity/cms 0.17.0 → 0.19.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 +163 -50
- package/admin/components/public-admin-bar.njk +3 -1
- package/admin/pages/documents/editor.njk +286 -158
- package/admin/pages/documents/list.njk +2 -0
- package/admin/pages/indieauth/consent.njk +4 -0
- package/admin/pages/settings/privacy.njk +37 -0
- package/admin/pages/users/apps.njk +109 -3
- package/admin/static/admin.css +37 -14
- package/dist/admin/documents.d.ts +34 -4
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +161 -23
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/editor-layout.d.ts +13 -0
- package/dist/admin/editor-layout.d.ts.map +1 -0
- package/dist/admin/editor-layout.js +61 -0
- package/dist/admin/editor-layout.js.map +1 -0
- package/dist/admin/enclosure-field.d.ts +2 -3
- package/dist/admin/enclosure-field.d.ts.map +1 -1
- package/dist/admin/enclosure-field.js +27 -7
- package/dist/admin/enclosure-field.js.map +1 -1
- package/dist/admin/index.d.ts +1 -0
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +1 -0
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/location-field.d.ts +27 -0
- package/dist/admin/location-field.d.ts.map +1 -0
- package/dist/admin/location-field.js +98 -0
- package/dist/admin/location-field.js.map +1 -0
- package/dist/admin/menu.d.ts.map +1 -1
- package/dist/admin/menu.js +1 -0
- package/dist/admin/menu.js.map +1 -1
- package/dist/admin/photo-field.d.ts +2 -3
- package/dist/admin/photo-field.d.ts.map +1 -1
- package/dist/admin/photo-field.js +4 -2
- package/dist/admin/photo-field.js.map +1 -1
- package/dist/admin/preview.d.ts.map +1 -1
- package/dist/admin/preview.js +18 -5
- package/dist/admin/preview.js.map +1 -1
- package/dist/admin/read-field.d.ts +22 -0
- package/dist/admin/read-field.d.ts.map +1 -0
- package/dist/admin/read-field.js +61 -0
- package/dist/admin/read-field.js.map +1 -0
- package/dist/admin/settings-page.d.ts +3 -3
- package/dist/admin/settings-page.js +2 -2
- package/dist/admin/settings-pages.d.ts +2 -2
- package/dist/admin/settings-pages.d.ts.map +1 -1
- package/dist/admin/settings-pages.js +4 -2
- package/dist/admin/settings-pages.js.map +1 -1
- package/dist/admin/settings-privacy.d.ts +3 -0
- package/dist/admin/settings-privacy.d.ts.map +1 -0
- package/dist/admin/settings-privacy.js +10 -0
- package/dist/admin/settings-privacy.js.map +1 -0
- package/dist/admin/settings-reading.js +2 -2
- package/dist/admin/settings-reading.js.map +1 -1
- package/dist/admin/settings.d.ts +18 -2
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +27 -0
- package/dist/admin/settings.js.map +1 -1
- package/dist/admin/templates.d.ts +1 -0
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +1 -0
- package/dist/admin/templates.js.map +1 -1
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +14 -1
- package/dist/admin/uploads.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +34 -0
- package/dist/cli.js.map +1 -1
- package/dist/comments/routes.js +2 -2
- package/dist/comments/routes.js.map +1 -1
- package/dist/contact/routes.js +2 -2
- package/dist/contact/routes.js.map +1 -1
- package/dist/content/kept-properties.d.ts +5 -0
- package/dist/content/kept-properties.d.ts.map +1 -0
- package/dist/content/kept-properties.js +12 -0
- package/dist/content/kept-properties.js.map +1 -0
- package/dist/content/location.d.ts +62 -0
- package/dist/content/location.d.ts.map +1 -0
- package/dist/content/location.js +240 -0
- package/dist/content/location.js.map +1 -0
- package/dist/content/locations.d.ts +6 -0
- package/dist/content/locations.d.ts.map +1 -0
- package/dist/content/locations.js +7 -0
- package/dist/content/locations.js.map +1 -0
- package/dist/content/metadata/gif.d.ts +3 -0
- package/dist/content/metadata/gif.d.ts.map +1 -0
- package/dist/content/metadata/gif.js +65 -0
- package/dist/content/metadata/gif.js.map +1 -0
- package/dist/content/metadata/index.d.ts +6 -0
- package/dist/content/metadata/index.d.ts.map +1 -0
- package/dist/content/metadata/index.js +24 -0
- package/dist/content/metadata/index.js.map +1 -0
- package/dist/content/metadata/isobmff.d.ts +22 -0
- package/dist/content/metadata/isobmff.d.ts.map +1 -0
- package/dist/content/metadata/isobmff.js +215 -0
- package/dist/content/metadata/isobmff.js.map +1 -0
- package/dist/content/metadata/jpeg.d.ts +3 -0
- package/dist/content/metadata/jpeg.d.ts.map +1 -0
- package/dist/content/metadata/jpeg.js +117 -0
- package/dist/content/metadata/jpeg.js.map +1 -0
- package/dist/content/metadata/png.d.ts +3 -0
- package/dist/content/metadata/png.d.ts.map +1 -0
- package/dist/content/metadata/png.js +74 -0
- package/dist/content/metadata/png.js.map +1 -0
- package/dist/content/metadata/shared.d.ts +17 -0
- package/dist/content/metadata/shared.d.ts.map +1 -0
- package/dist/content/metadata/shared.js +42 -0
- package/dist/content/metadata/shared.js.map +1 -0
- package/dist/content/metadata/sweep.d.ts +14 -0
- package/dist/content/metadata/sweep.d.ts.map +1 -0
- package/dist/content/metadata/sweep.js +54 -0
- package/dist/content/metadata/sweep.js.map +1 -0
- package/dist/content/metadata/tiff.d.ts +7 -0
- package/dist/content/metadata/tiff.d.ts.map +1 -0
- package/dist/content/metadata/tiff.js +56 -0
- package/dist/content/metadata/tiff.js.map +1 -0
- package/dist/content/metadata/webp.d.ts +3 -0
- package/dist/content/metadata/webp.d.ts.map +1 -0
- package/dist/content/metadata/webp.js +67 -0
- package/dist/content/metadata/webp.js.map +1 -0
- package/dist/content/permalink-file.d.ts +7 -0
- package/dist/content/permalink-file.d.ts.map +1 -0
- package/dist/content/permalink-file.js +77 -0
- package/dist/content/permalink-file.js.map +1 -0
- package/dist/content/post-type.d.ts +4 -2
- package/dist/content/post-type.d.ts.map +1 -1
- package/dist/content/post-type.js +9 -1
- package/dist/content/post-type.js.map +1 -1
- package/dist/content/read.d.ts +22 -0
- package/dist/content/read.d.ts.map +1 -0
- package/dist/content/read.js +67 -0
- package/dist/content/read.js.map +1 -0
- package/dist/content/store.d.ts +4 -4
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +19 -39
- package/dist/content/store.js.map +1 -1
- package/dist/content/sync.d.ts.map +1 -1
- package/dist/content/sync.js +3 -13
- package/dist/content/sync.js.map +1 -1
- package/dist/content/visibility.d.ts +11 -0
- package/dist/content/visibility.d.ts.map +1 -0
- package/dist/content/visibility.js +14 -0
- package/dist/content/visibility.js.map +1 -0
- package/dist/federation/article.d.ts +4 -3
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +66 -20
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/citations.d.ts +7 -6
- package/dist/federation/citations.d.ts.map +1 -1
- package/dist/federation/citations.js +44 -28
- package/dist/federation/citations.js.map +1 -1
- package/dist/federation/delivery.d.ts +3 -1
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +29 -21
- package/dist/federation/delivery.js.map +1 -1
- package/dist/federation/mount.d.ts.map +1 -1
- package/dist/federation/mount.js +3 -1
- package/dist/federation/mount.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/indexnow.js +2 -2
- package/dist/indexnow.js.map +1 -1
- package/dist/indieauth/activity-log.d.ts +2 -0
- package/dist/indieauth/activity-log.d.ts.map +1 -1
- package/dist/indieauth/activity-log.js +12 -2
- package/dist/indieauth/activity-log.js.map +1 -1
- package/dist/indieauth/app-activity.js +5 -1
- package/dist/indieauth/app-activity.js.map +1 -1
- package/dist/indieauth/bearer.d.ts +10 -6
- package/dist/indieauth/bearer.d.ts.map +1 -1
- package/dist/indieauth/bearer.js +28 -25
- package/dist/indieauth/bearer.js.map +1 -1
- package/dist/indieauth/client-id.d.ts +10 -0
- package/dist/indieauth/client-id.d.ts.map +1 -0
- package/dist/indieauth/client-id.js +30 -0
- package/dist/indieauth/client-id.js.map +1 -0
- package/dist/indieauth/connected-apps.d.ts +4 -0
- package/dist/indieauth/connected-apps.d.ts.map +1 -1
- package/dist/indieauth/connected-apps.js +149 -20
- package/dist/indieauth/connected-apps.js.map +1 -1
- package/dist/indieauth/consent.d.ts.map +1 -1
- package/dist/indieauth/consent.js +5 -1
- package/dist/indieauth/consent.js.map +1 -1
- package/dist/indieauth/grants.d.ts +2 -7
- package/dist/indieauth/grants.d.ts.map +1 -1
- package/dist/indieauth/grants.js.map +1 -1
- package/dist/indieauth/redeem.d.ts.map +1 -1
- package/dist/indieauth/redeem.js +10 -5
- package/dist/indieauth/redeem.js.map +1 -1
- package/dist/indieauth/request.d.ts +8 -4
- package/dist/indieauth/request.d.ts.map +1 -1
- package/dist/indieauth/request.js +29 -30
- package/dist/indieauth/request.js.map +1 -1
- package/dist/indieauth/token.js +2 -2
- package/dist/indieauth/token.js.map +1 -1
- package/dist/indieauth/tokens.d.ts +28 -7
- package/dist/indieauth/tokens.d.ts.map +1 -1
- package/dist/indieauth/tokens.js +26 -5
- package/dist/indieauth/tokens.js.map +1 -1
- package/dist/micropub/create.d.ts +26 -0
- package/dist/micropub/create.d.ts.map +1 -1
- package/dist/micropub/create.js +158 -13
- package/dist/micropub/create.js.map +1 -1
- package/dist/micropub/endpoint.d.ts +4 -5
- package/dist/micropub/endpoint.d.ts.map +1 -1
- package/dist/micropub/endpoint.js +83 -25
- package/dist/micropub/endpoint.js.map +1 -1
- package/dist/micropub/media.d.ts +6 -2
- package/dist/micropub/media.d.ts.map +1 -1
- package/dist/micropub/media.js +43 -37
- package/dist/micropub/media.js.map +1 -1
- package/dist/micropub/update.d.ts +13 -3
- package/dist/micropub/update.d.ts.map +1 -1
- package/dist/micropub/update.js +60 -7
- package/dist/micropub/update.js.map +1 -1
- package/dist/notify.d.ts.map +1 -1
- package/dist/notify.js +2 -5
- package/dist/notify.js.map +1 -1
- package/dist/web/absolute-urls.d.ts +2 -0
- package/dist/web/absolute-urls.d.ts.map +1 -0
- package/dist/web/absolute-urls.js +22 -0
- package/dist/web/absolute-urls.js.map +1 -0
- package/dist/web/admin-bar.d.ts.map +1 -1
- package/dist/web/admin-bar.js +25 -0
- package/dist/web/admin-bar.js.map +1 -1
- package/dist/web/context.d.ts +29 -1
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +33 -0
- package/dist/web/context.js.map +1 -1
- package/dist/web/conversation.d.ts.map +1 -1
- package/dist/web/conversation.js +5 -4
- package/dist/web/conversation.js.map +1 -1
- package/dist/web/documents.d.ts +34 -10
- package/dist/web/documents.d.ts.map +1 -1
- package/dist/web/documents.js +41 -15
- package/dist/web/documents.js.map +1 -1
- package/dist/web/feed-item.d.ts +25 -6
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +31 -7
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/feed-json.d.ts +3 -1
- package/dist/web/feed-json.d.ts.map +1 -1
- package/dist/web/feed-json.js +2 -0
- package/dist/web/feed-json.js.map +1 -1
- package/dist/web/feed-source.d.ts +6 -0
- package/dist/web/feed-source.d.ts.map +1 -1
- package/dist/web/feed-source.js.map +1 -1
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js +2 -0
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/html-attributes.d.ts +3 -0
- package/dist/web/html-attributes.d.ts.map +1 -0
- package/dist/web/html-attributes.js +15 -0
- package/dist/web/html-attributes.js.map +1 -0
- package/dist/web/index.d.ts +1 -1
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +1 -1
- package/dist/web/index.js.map +1 -1
- package/dist/web/negotiate.d.ts +2 -0
- package/dist/web/negotiate.d.ts.map +1 -1
- package/dist/web/negotiate.js +2 -1
- package/dist/web/negotiate.js.map +1 -1
- package/dist/web/render.d.ts +13 -4
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +25 -12
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +26 -11
- package/dist/web/routes.js.map +1 -1
- package/dist/webmention/fetch-public.d.ts +3 -1
- package/dist/webmention/fetch-public.d.ts.map +1 -1
- package/dist/webmention/fetch-public.js +17 -11
- package/dist/webmention/fetch-public.js.map +1 -1
- package/dist/webmention/reply-context.d.ts +18 -5
- package/dist/webmention/reply-context.d.ts.map +1 -1
- package/dist/webmention/reply-context.js +118 -19
- package/dist/webmention/reply-context.js.map +1 -1
- package/dist/webmention/reply-contexts.d.ts +17 -14
- package/dist/webmention/reply-contexts.d.ts.map +1 -1
- package/dist/webmention/reply-contexts.js +32 -21
- package/dist/webmention/reply-contexts.js.map +1 -1
- package/dist/webmention/service.d.ts.map +1 -1
- package/dist/webmention/service.js +7 -2
- package/dist/webmention/service.js.map +1 -1
- package/package.json +9 -9
- package/themes/default/README.md +45 -7
- package/themes/default/layouts/base.njk +2 -0
- package/themes/default/layouts/post.njk +12 -7
- package/themes/default/partials/citations.njk +12 -3
- package/themes/default/partials/cited-page.njk +41 -0
- package/themes/default/partials/location.njk +12 -0
- package/themes/default/partials/post-list.njk +10 -5
- package/themes/default/partials/read.njk +5 -0
- package/themes/default/partials/reply-context.njk +2 -9
package/README.md
CHANGED
|
@@ -94,12 +94,13 @@ site (or `npx geekity`, or a `package.json` script, which is how the generated
|
|
|
94
94
|
| `geekity rebuild` | Delete `data/geekity.db` and build it again from the files. |
|
|
95
95
|
| `geekity resend --all`, `<slug>...` | Send announced posts to every follower and relay again, as they now read. See [Quote posts](#quote-posts). |
|
|
96
96
|
| `geekity maintenance on`, `off`, `status` | Take the public site down on purpose with a 503 and `Retry-After`, or bring it back, without a restart. `on --until <time>` names when it should be back. |
|
|
97
|
+
| `geekity strip-metadata` | Remove location and camera metadata from files already in `content/uploads`. See [The media library](#the-media-library). |
|
|
97
98
|
| `geekity user add <name>` | Create an admin account, so a site can get its first login without the setup screen. |
|
|
98
99
|
| `geekity import wordpress-actor <name>` | Bring one person across from the WordPress ActivityPub plugin: their key pair, the actor id their followers hold, the plugin's numeric actor id, and their followers. |
|
|
99
100
|
| `geekity --help`, `-h` | The same table, on the terminal. |
|
|
100
101
|
| `geekity --version` | The installed version. |
|
|
101
102
|
|
|
102
|
-
`serve`, `sync`, `rebuild`, `resend`, `maintenance`, `user add` and `import wordpress-actor` take
|
|
103
|
+
`serve`, `sync`, `rebuild`, `resend`, `maintenance`, `strip-metadata`, `user add` and `import wordpress-actor` take
|
|
103
104
|
`--config <file>`; without it they look for `geekity.config.ts`, then
|
|
104
105
|
`geekity.config.js`, then `geekity.config.mjs` in the working directory, and run
|
|
105
106
|
on defaults if there is none.
|
|
@@ -267,29 +268,29 @@ export default defineConfig({
|
|
|
267
268
|
Every field is optional. Relative directories resolve against the working
|
|
268
269
|
directory; absolute ones are used as given.
|
|
269
270
|
|
|
270
|
-
| Field | Default | Environment override | Meaning
|
|
271
|
-
| ------------------ | ------------------------------------- | ---------------------------- |
|
|
272
|
-
| `port` | `3000` | `GEEKITY_PORT`, then `PORT` | Port the HTTP server listens on. `0` picks a free one.
|
|
273
|
-
| `contentDir` | `<cwd>/content` | `GEEKITY_CONTENT_DIR` | Markdown content.
|
|
274
|
-
| `dataDir` | `<cwd>/data` | `GEEKITY_DATA_DIR` | Derived state — the SQLite index, the image variants — and the
|
|
275
|
-
| `themesDir` | `<cwd>/themes` | `GEEKITY_THEMES_DIR` | The site's themes, one directory per theme, each with a `theme.json`. Which one is in use is the `theme` setting in `site.json`, not a path. Need not exist.
|
|
276
|
-
| `baseUrl` | `http://localhost:<port>` | `GEEKITY_BASE_URL` | Public origin for canonical URLs, feeds and ActivityPub ids. A trailing slash is stripped.
|
|
277
|
-
| `watch` | `true` | `GEEKITY_WATCH` | Watch `contentDir` while serving and keep the index in step.
|
|
278
|
-
| `sessionLifetime` | `1209600` (14 days) | `GEEKITY_SESSION_LIFETIME` | How long an admin login lasts, in seconds.
|
|
279
|
-
| `loginAttempts` | `5` | `GEEKITY_LOGIN_ATTEMPTS` | Failed sign-ins a username or an address may make before it is locked out.
|
|
280
|
-
| `loginLockout` | `900` (15 minutes) | `GEEKITY_LOGIN_LOCKOUT` | How long the first lockout lasts, in seconds. See [Login hardening](#login-hardening).
|
|
281
|
-
| `trustProxy` | `false` | `GEEKITY_TRUST_PROXY` | Believe `X-Forwarded-For` when deciding which address a sign-in came from.
|
|
282
|
-
| `accessLog` | `false`; `true` under `geekity serve` | `GEEKITY_ACCESS_LOG` | One line per request on stdout: method, path with query, status, duration. See [The access log](#the-access-log).
|
|
283
|
-
| `accessLogAddress` | `false` | `GEEKITY_ACCESS_LOG_ADDRESS` | Put the client address on the end of each access-log line. `trustProxy` decides which address that is.
|
|
284
|
-
| `accessLogWriter` | stdout | — | Where the lines go instead. See [The access log](#the-access-log).
|
|
285
|
-
| `maintenance` | `false` | `GEEKITY_MAINTENANCE` | Keep the site in maintenance mode, answering 503, until a restart without it.
|
|
286
|
-
| `compression` | `true` | `GEEKITY_COMPRESSION` | Compress text responses with brotli or gzip. Turn it off behind a proxy that compresses. See [Compression](#compression).
|
|
287
|
-
| `securityHeaders` | [see below](#security-headers) | — | Headers every response carries. A string replaces a default or adds a header, `false` removes one.
|
|
288
|
-
| `onDocumentChange` | none | — | Hook run for every change to the index. See [Hooks](#hooks).
|
|
289
|
-
| `onPublish` | none | — | Hook run when a document becomes visible. See [Hooks](#hooks).
|
|
290
|
-
| `federation` | `{}` | — | Federation stores and guards. See [Federation](#federation).
|
|
291
|
-
| `commentChecker` | Akismet | — | A spam checker of the site's own, which wins over the key in `data/akismet.json`. See [Akismet](#akismet).
|
|
292
|
-
| `mail` | `{}` | — | Mail provider, retries, backoff and logger. See [Email](#email).
|
|
271
|
+
| Field | Default | Environment override | Meaning |
|
|
272
|
+
| ------------------ | ------------------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
273
|
+
| `port` | `3000` | `GEEKITY_PORT`, then `PORT` | Port the HTTP server listens on. `0` picks a free one. |
|
|
274
|
+
| `contentDir` | `<cwd>/content` | `GEEKITY_CONTENT_DIR` | Markdown content. |
|
|
275
|
+
| `dataDir` | `<cwd>/data` | `GEEKITY_DATA_DIR` | Derived state — the SQLite index, the image variants — and the files that are not derived and must be backed up, such as `users.json`, the actor key pairs under `keys/` and `locations.json`. [Two directories](#two-directories-content-and-data) lists them. |
|
|
276
|
+
| `themesDir` | `<cwd>/themes` | `GEEKITY_THEMES_DIR` | The site's themes, one directory per theme, each with a `theme.json`. Which one is in use is the `theme` setting in `site.json`, not a path. Need not exist. |
|
|
277
|
+
| `baseUrl` | `http://localhost:<port>` | `GEEKITY_BASE_URL` | Public origin for canonical URLs, feeds and ActivityPub ids. A trailing slash is stripped. |
|
|
278
|
+
| `watch` | `true` | `GEEKITY_WATCH` | Watch `contentDir` while serving and keep the index in step. |
|
|
279
|
+
| `sessionLifetime` | `1209600` (14 days) | `GEEKITY_SESSION_LIFETIME` | How long an admin login lasts, in seconds. |
|
|
280
|
+
| `loginAttempts` | `5` | `GEEKITY_LOGIN_ATTEMPTS` | Failed sign-ins a username or an address may make before it is locked out. |
|
|
281
|
+
| `loginLockout` | `900` (15 minutes) | `GEEKITY_LOGIN_LOCKOUT` | How long the first lockout lasts, in seconds. See [Login hardening](#login-hardening). |
|
|
282
|
+
| `trustProxy` | `false` | `GEEKITY_TRUST_PROXY` | Believe `X-Forwarded-For` when deciding which address a sign-in came from. |
|
|
283
|
+
| `accessLog` | `false`; `true` under `geekity serve` | `GEEKITY_ACCESS_LOG` | One line per request on stdout: method, path with query, status, duration. See [The access log](#the-access-log). |
|
|
284
|
+
| `accessLogAddress` | `false` | `GEEKITY_ACCESS_LOG_ADDRESS` | Put the client address on the end of each access-log line. `trustProxy` decides which address that is. |
|
|
285
|
+
| `accessLogWriter` | stdout | — | Where the lines go instead. See [The access log](#the-access-log). |
|
|
286
|
+
| `maintenance` | `false` | `GEEKITY_MAINTENANCE` | Keep the site in maintenance mode, answering 503, until a restart without it. |
|
|
287
|
+
| `compression` | `true` | `GEEKITY_COMPRESSION` | Compress text responses with brotli or gzip. Turn it off behind a proxy that compresses. See [Compression](#compression). |
|
|
288
|
+
| `securityHeaders` | [see below](#security-headers) | — | Headers every response carries. A string replaces a default or adds a header, `false` removes one. |
|
|
289
|
+
| `onDocumentChange` | none | — | Hook run for every change to the index. See [Hooks](#hooks). |
|
|
290
|
+
| `onPublish` | none | — | Hook run when a document becomes visible. See [Hooks](#hooks). |
|
|
291
|
+
| `federation` | `{}` | — | Federation stores and guards. See [Federation](#federation). |
|
|
292
|
+
| `commentChecker` | Akismet | — | A spam checker of the site's own, which wins over the key in `data/akismet.json`. See [Akismet](#akismet). |
|
|
293
|
+
| `mail` | `{}` | — | Mail provider, retries, backoff and logger. See [Email](#email). |
|
|
293
294
|
|
|
294
295
|
Precedence is environment variable, then config file, then default, so a host
|
|
295
296
|
can override anything without editing the site. A boolean environment variable
|
|
@@ -352,7 +353,7 @@ the same directory reads all of it, and everything in it is meant to be public:
|
|
|
352
353
|
| Path | What it holds |
|
|
353
354
|
| -------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
354
355
|
| `content/posts/`, `content/pages/` | The Markdown documents, `_trash/` included. |
|
|
355
|
-
| `content/uploads/` | Uploaded files
|
|
356
|
+
| `content/uploads/` | Uploaded files, with their location and camera metadata removed. |
|
|
356
357
|
| `content/_data/site.json` | Every site setting. |
|
|
357
358
|
| `content/_data/federation/followers.json` | Who follows the site. |
|
|
358
359
|
| `content/_data/federation/inbox/{yyyy}-{mm}.jsonl` | Every activity the inbox was handed, one per line. |
|
|
@@ -364,6 +365,7 @@ the same directory reads all of it, and everything in it is meant to be public:
|
|
|
364
365
|
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
365
366
|
| `data/users.json` | Usernames and argon2id password hashes. Mode `0600`. |
|
|
366
367
|
| `data/keys/` | Each user's actor key pairs as JWK files. Mode `0600`. **Losing these breaks federation.** |
|
|
368
|
+
| `data/locations.json` | Where each post was written, keyed by permalink (decision-29). Mode `0600`. |
|
|
367
369
|
| `data/comment-salt` | What hides commenters' addresses in the published comment files. Mode `0600`. |
|
|
368
370
|
| `data/comments/{slug}.json` | The emails of that post's commenters, and whether each asked to hear about replies, keyed by comment id. Mode `0600`. |
|
|
369
371
|
| `data/akismet.json` | The Akismet key, and what `verify-key` last said about it. Mode `0600`. |
|
|
@@ -1517,25 +1519,28 @@ This is every piece of personal data the CMS stores, where it is, and how long
|
|
|
1517
1519
|
it stays. "Kept" means until somebody deletes it, unless a retention period
|
|
1518
1520
|
says otherwise.
|
|
1519
1521
|
|
|
1520
|
-
| What
|
|
1521
|
-
|
|
|
1522
|
-
| A commenter's name, website and words
|
|
1523
|
-
| A commenter's email, and whether they asked to be told about replies
|
|
1524
|
-
| A salted hash of the address a comment, webmention or contact message came from (the address itself is never stored)
|
|
1525
|
-
| A webmention's author name, website, avatar URL and the source page's words
|
|
1526
|
-
| A contact message: the sender's name, email, subject and message
|
|
1527
|
-
| The addresses that unsubscribed from reply notices
|
|
1528
|
-
| Followers: actor id, handle, display name, avatar URL, profile URL
|
|
1529
|
-
| Inbound likes, boosts, replies and quotes, with the actor who sent them
|
|
1530
|
-
| What a reply shows of the post it answers: its title, words and author
|
|
1531
|
-
| Other actors who liked, boosted, answered or quoted: handle, display name, avatar URL, profile URL
|
|
1532
|
-
| Remote avatars, shrunk
|
|
1533
|
-
| Users: username, email, argon2id password hash, profile
|
|
1534
|
-
| The apps a user signed in to with IndieAuth: app, scopes, hashes of its tokens, when they expire
|
|
1535
|
-
| Recent IndieAuth and Micropub requests: app, username, what it sent (no secrets, values cut short), the answer
|
|
1536
|
-
| An index of all of the above, and sessions, reset tokens and spent link tokens
|
|
1537
|
-
| Client addresses in the rate limits
|
|
1538
|
-
|
|
|
1522
|
+
| What | Where | How long |
|
|
1523
|
+
| ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
1524
|
+
| A commenter's name, website and words | `content/_data/comments/{slug}.json`, public and in git | Kept. Erasing on request replaces the name and drops the website. |
|
|
1525
|
+
| A commenter's email, and whether they asked to be told about replies | `data/comments/{slug}.json`, mode `0600`, keyed by comment id | `commentEmailRetentionDays`: forever unless set, 180 on a new site. |
|
|
1526
|
+
| A salted hash of the address a comment, webmention or contact message came from (the address itself is never stored) | The comment file, or the contact message file | `addressHashRetentionDays`: forever unless set, 30 on a new site. |
|
|
1527
|
+
| A webmention's author name, website, avatar URL and the source page's words | `content/_data/comments/{slug}.json` | Kept, as a copy of a page that is public already. |
|
|
1528
|
+
| A contact message: the sender's name, email, subject and message | `data/contact/{id}.json`, mode `0600` | `contactMessageRetentionDays`: forever unless set, 365 on a new site. |
|
|
1529
|
+
| The addresses that unsubscribed from reply notices | `data/comment-optouts.json`, mode `0600` | Kept, so the site goes on not writing to them. Erasing on request removes one. |
|
|
1530
|
+
| Followers: actor id, handle, display name, avatar URL, profile URL | `content/_data/federation/{username}/followers.json`, in git | Until they unfollow. |
|
|
1531
|
+
| Inbound likes, boosts, replies and quotes, with the actor who sent them | `content/_data/federation/inbox/{yyyy}-{mm}.jsonl`, in git | Kept. |
|
|
1532
|
+
| What a reply shows of the post it answers: its title, words and author | `content/_data/replyContexts.json`, in git | Kept. |
|
|
1533
|
+
| Other actors who liked, boosted, answered or quoted: handle, display name, avatar URL, profile URL | `data/geekity.db`, fetched from their actor document | A cache. Refetched weekly while the inbox log names them. |
|
|
1534
|
+
| Remote avatars, shrunk | `data/avatars/` | Deleted by the avatar sweep once nothing shown names them. |
|
|
1535
|
+
| Users: username, email, argon2id password hash, profile | `data/users.json`, mode `0600` | Until the user is deleted. |
|
|
1536
|
+
| The apps a user signed in to with IndieAuth: app, scopes, hashes of its tokens, when they expire | `data/indieauth-tokens.json`, mode `0600` | Until the user is deleted, or 60 days after the app last refreshed. |
|
|
1537
|
+
| Recent IndieAuth and Micropub requests: app, username, what it sent (no secrets, values cut short), the answer | `data/indieauth-activity.json`, mode `0600` | The last 100 requests, none older than 14 days. |
|
|
1538
|
+
| An index of all of the above, and sessions, reset tokens and spent link tokens | `data/geekity.db` | A cache of the files. Sessions and tokens are pruned when they expire. |
|
|
1539
|
+
| Client addresses in the rate limits | Memory | Until the window passes or the site restarts. |
|
|
1540
|
+
| Where and when a photo or video was taken, and the camera or phone (EXIF, XMP, IPTC, a video's `©xyz`) | Removed from `content/uploads/` on upload | Never stored. Older uploads keep it until `geekity strip-metadata`; git history keeps the old bytes until rewritten. |
|
|
1541
|
+
| Where the author wrote a post or checked in: coordinates, accuracy, and the place's name, locality, region and country | `data/locations.json`, mode `0600`, keyed by permalink | Kept until the author clears it. Published only as far as **Settings > Privacy** allows, nothing by default. |
|
|
1542
|
+
| Micropub properties a post was sent that the site does not understand, such as an RSVP | `data/kept-properties.json`, mode `0600`, keyed by permalink | Kept until an update deletes them. Never published. |
|
|
1543
|
+
| Client addresses in the access log | stdout, and whatever collects it | Only with `accessLogAddress` on. The collector keeps them. |
|
|
1539
1544
|
|
|
1540
1545
|
Two services outside the site see personal data when a site turns them on.
|
|
1541
1546
|
Akismet is sent a commenter's or sender's address, user agent, referrer, name,
|
|
@@ -1704,6 +1709,48 @@ cacheable, and a URL that answered differently for one viewer would be cached
|
|
|
1704
1709
|
and served to the rest. Use the editor's Preview button, which renders the post
|
|
1705
1710
|
through the theme's own layout at an admin URL.
|
|
1706
1711
|
|
|
1712
|
+
## Unlisted posts
|
|
1713
|
+
|
|
1714
|
+
An unlisted post is published at its URL and left off every list. Choose
|
|
1715
|
+
Unlisted in the editor's Visibility field, send `visibility=unlisted` from a
|
|
1716
|
+
Micropub app, or write it into the front matter:
|
|
1717
|
+
|
|
1718
|
+
```yaml
|
|
1719
|
+
visibility: unlisted
|
|
1720
|
+
```
|
|
1721
|
+
|
|
1722
|
+
Public is the key's absence, and the editor removes the key when you choose
|
|
1723
|
+
Public again. The site has no private posts. A value other than `public` or
|
|
1724
|
+
`unlisted`, such as a hand-typed `visibility: private`, hides the post the way
|
|
1725
|
+
`draft: true` does: its URL answers 404 to anybody not signed in, it is on no
|
|
1726
|
+
list, and a post the followers already hold is withdrawn with a `Delete`. The
|
|
1727
|
+
editor shows the value as it is stored, marks the post Hidden in the list, and
|
|
1728
|
+
keeps the value through a save until you choose Public or Unlisted.
|
|
1729
|
+
|
|
1730
|
+
The rule works for pages too.
|
|
1731
|
+
|
|
1732
|
+
| Where | An unlisted post |
|
|
1733
|
+
| -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1734
|
+
| Its permalink, in every representation | 200, with `X-Robots-Tag: noindex`. The default theme also prints `<meta name="robots" content="noindex">`. |
|
|
1735
|
+
| The home page, tag, category and author archives, the `archive: true` page | Absent, and not counted in a pager or a tag count. |
|
|
1736
|
+
| Previous and next links under other posts, the front page's recent posts | Absent. |
|
|
1737
|
+
| Every RSS, Atom and JSON feed, and the site-wide comments feed | Absent. Saving one pings no notify server. |
|
|
1738
|
+
| The sitemap, search (HTML and JSON) and `llms.txt` | Absent. |
|
|
1739
|
+
| IndexNow | Not submitted. A public post that becomes unlisted is submitted once, so a search engine reads the `noindex`. |
|
|
1740
|
+
| The ActivityPub outbox and featured collection | Absent. |
|
|
1741
|
+
| Followers | Get the `Create` and every `Update`, addressed `to` the followers with Public in `cc`, which Mastodon shows as unlisted. Relays get nothing. |
|
|
1742
|
+
| Webmentions | Sent as for any post: the page is public. |
|
|
1743
|
+
|
|
1744
|
+
Changing a published post between public and unlisted sends its followers an
|
|
1745
|
+
`Update` with the new addressing.
|
|
1746
|
+
|
|
1747
|
+
In code, `isServed(document)` says whether the site serves a document at its
|
|
1748
|
+
URL and `isListed(document)` whether it also lists it. The index answers the
|
|
1749
|
+
same two rules in SQL. An Eleventy build with the example config reads the key
|
|
1750
|
+
too: an unlisted post gets its page, `noindex`, and no place in any collection,
|
|
1751
|
+
and an unrecognized value builds no page. See
|
|
1752
|
+
[Building the same content with Eleventy](#building-the-same-content-with-eleventy).
|
|
1753
|
+
|
|
1707
1754
|
## Hooks
|
|
1708
1755
|
|
|
1709
1756
|
Two hooks let a site do something of its own when content changes. Both are
|
|
@@ -1868,8 +1915,8 @@ email address, notification preferences, a public profile and the
|
|
|
1868
1915
|
[stored actor id](#a-users-stored-actor-id) they were published under
|
|
1869
1916
|
elsewhere. Written atomically with `0600` permissions and serialised against
|
|
1870
1917
|
itself, so two admins adding the same name at once cannot both succeed. It is in `data/` rather than `content/` because
|
|
1871
|
-
`content/` is published with the site, and it is one of the
|
|
1872
|
-
`dataDir` that must be backed up
|
|
1918
|
+
`content/` is published with the site, and it is one of the files under
|
|
1919
|
+
`dataDir` that must be backed up.
|
|
1873
1920
|
|
|
1874
1921
|
Sessions stay in SQLite, where the rest of the cache lives. They name a user by
|
|
1875
1922
|
id and are joined against the file on every admin request, so a session whose
|
|
@@ -2088,6 +2135,60 @@ shows up without a restart. `readAltTexts(contentDir)` and
|
|
|
2088
2135
|
`undescribedImages(html, library)` in `src/images/alt-text.ts` are what the
|
|
2089
2136
|
editor's publish check and the federated `Image` attachments read.
|
|
2090
2137
|
|
|
2138
|
+
#### Location and camera metadata
|
|
2139
|
+
|
|
2140
|
+
A phone photo carries where it was taken, when, and on what camera, and the
|
|
2141
|
+
original under `content/uploads` is what the site serves at `/uploads/…`, puts
|
|
2142
|
+
in every `<picture>` as the fallback, and federates as a photo post's
|
|
2143
|
+
attachment. So `storeUpload` removes that metadata before the file is written,
|
|
2144
|
+
for every upload: the editor's control, the media library, the Micropub media
|
|
2145
|
+
endpoint and Micropub photos. It is not a setting.
|
|
2146
|
+
|
|
2147
|
+
| Format | What goes | What stays |
|
|
2148
|
+
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
2149
|
+
| JPEG | EXIF (GPS, camera, lens, serial, time), XMP, IPTC, comments, other APPn segments, data after the image | JFIF, the ICC profile, Adobe's colour flag, the orientation |
|
|
2150
|
+
| PNG | `eXIf`, `tEXt`, `zTXt`, `iTXt` (XMP), `tIME` and private chunks | Image and colour chunks, APNG animation, the orientation |
|
|
2151
|
+
| WebP | `EXIF`, `XMP ` and unknown chunks | The bitstream, alpha, animation, ICC profile, the orientation |
|
|
2152
|
+
| AVIF | The contents of the Exif and XMP items, overwritten with an empty EXIF block and an empty XMP packet | The picture, and its `irot`/`imir` orientation |
|
|
2153
|
+
| GIF | Comment extensions and application extensions other than looping and ICC (XMP lives in one) | Frames, timing, looping |
|
|
2154
|
+
| MP4, M4V | `udta` (the `©xyz` location, camera), `meta` (the QuickTime location key) and `uuid` (XMP) boxes, in the movie, its tracks and at the top level | Every other box |
|
|
2155
|
+
|
|
2156
|
+
Nothing is re-encoded. Segments, chunks and blocks are cut out and the pixel
|
|
2157
|
+
data is copied byte for byte, so a stored JPEG or PNG decodes to the same
|
|
2158
|
+
pixels as the upload. A picture taken sideways keeps a minimal EXIF block
|
|
2159
|
+
holding its orientation and nothing else, so it still shows the right way up.
|
|
2160
|
+
AVIF and MP4 keep their layout exactly: the metadata is overwritten in place
|
|
2161
|
+
and a removed box becomes a zero-filled `free` box of the same size, so no
|
|
2162
|
+
offset inside the file moves. A file whose structure cannot be followed far
|
|
2163
|
+
enough to find its metadata is refused with a 415 rather than stored as it is.
|
|
2164
|
+
|
|
2165
|
+
Audio (MP3, M4A, Ogg), WebM, PDF and the text formats are stored as they
|
|
2166
|
+
arrive. An episode's tags are its title and artwork, not where it was
|
|
2167
|
+
recorded.
|
|
2168
|
+
|
|
2169
|
+
Files uploaded before this version still carry their metadata. Strip them
|
|
2170
|
+
with
|
|
2171
|
+
|
|
2172
|
+
```sh
|
|
2173
|
+
geekity strip-metadata
|
|
2174
|
+
```
|
|
2175
|
+
|
|
2176
|
+
which rewrites each file under `content/uploads` that has something to remove,
|
|
2177
|
+
prints what it removed, keeps the file's modification time (the library sorts
|
|
2178
|
+
by it), and leaves alone, and names, a file it cannot read, exiting `1`. It is
|
|
2179
|
+
safe to run again: a clean file is left as it is, and a second run reports
|
|
2180
|
+
every file already clean. The derived variants under `data/images` never
|
|
2181
|
+
carried metadata.
|
|
2182
|
+
|
|
2183
|
+
A site that keeps `content/` in git still has the old bytes in its history,
|
|
2184
|
+
and so does every clone and fork of it. Removing them means rewriting that
|
|
2185
|
+
history. One way: run `geekity strip-metadata`, copy `content/uploads`
|
|
2186
|
+
somewhere outside the repository, remove it from every commit with
|
|
2187
|
+
[`git filter-repo`](https://github.com/newren/git-filter-repo)
|
|
2188
|
+
`--path content/uploads --invert-paths`, copy the stripped files back, commit
|
|
2189
|
+
them, and force-push. That changes every commit hash, so anybody else with a
|
|
2190
|
+
clone has to clone again.
|
|
2191
|
+
|
|
2091
2192
|
### Image variants
|
|
2092
2193
|
|
|
2093
2194
|
`generateImageVariants(config, uploadPath)` derives one upload's copies with
|
|
@@ -2956,6 +3057,16 @@ its own item: RSS as `dc:language`, Atom as `xml:lang` on the `entry` and JSON
|
|
|
2956
3057
|
Feed as the item's `language`. A post in the site's language, or whose `lang`
|
|
2957
3058
|
is not a language tag, adds nothing.
|
|
2958
3059
|
|
|
3060
|
+
**Photos.** A post's `photo` front matter prints in every format's content,
|
|
3061
|
+
before the body, which is where the page prints it too. Each photo is a plain
|
|
3062
|
+
`<figure><img src alt></figure>` of the original upload, never the responsive
|
|
3063
|
+
variants, which a reader cannot resolve (decision-10). Its `src` is absolute on
|
|
3064
|
+
the site's base URL. Its `alt` is the post's own text, else the media library's,
|
|
3065
|
+
else empty. So a photo-only post reads in a feed reader as its photos. JSON Feed
|
|
3066
|
+
also names the item's main image as `image`: the post's `image` front matter,
|
|
3067
|
+
else its first photo. A photo is never an RSS `enclosure`, an Atom
|
|
3068
|
+
`rel="enclosure"` link or a JSON Feed attachment. Those carry a recording only.
|
|
3069
|
+
|
|
2959
3070
|
### RSS 2.0
|
|
2960
3071
|
|
|
2961
3072
|
The channel carries `title`, `link`, `description` (the tagline), `language`
|
|
@@ -3058,7 +3169,7 @@ Feed has no field for a license and says nothing about one.
|
|
|
3058
3169
|
[rfc4946]: https://www.rfc-editor.org/rfc/rfc4946
|
|
3059
3170
|
|
|
3060
3171
|
A JSON Feed item carries `id` (the object id), `url` (the permalink), `title`,
|
|
3061
|
-
`content_html`, `summary`, `date_published`, `date_modified`, `tags` (the
|
|
3172
|
+
`content_html`, `image` (see Photos above), `summary`, `date_published`, `date_modified`, `tags` (the
|
|
3062
3173
|
terms) and `authors`; the feed carries `version`, `title`, `home_page_url`,
|
|
3063
3174
|
`feed_url`, `description`, `authors` and `hubs`. Keys with nothing behind them
|
|
3064
3175
|
are left out rather than sent empty.
|
|
@@ -3349,9 +3460,10 @@ dates — a page with no date in its front matter — carries no `<lastmod>`
|
|
|
3349
3460
|
rather than an invented one.
|
|
3350
3461
|
|
|
3351
3462
|
Nothing hidden reaches it. The sitemap is drawn from the same queries the
|
|
3352
|
-
listings are and checked against the same `
|
|
3353
|
-
|
|
3354
|
-
|
|
3463
|
+
listings are and checked against the same `isListed`, so drafts, the trash and
|
|
3464
|
+
posts whose date has not arrived are absent for the same reason their
|
|
3465
|
+
permalinks 404, and an [unlisted post](#unlisted-posts) is absent for the same
|
|
3466
|
+
reason it is off the home page.
|
|
3355
3467
|
|
|
3356
3468
|
The protocol caps one file at 50,000 URLs. Past that, `/sitemap.xml` becomes a
|
|
3357
3469
|
`<sitemapindex>` naming `/sitemap-1.xml`, `/sitemap-2.xml` and so on, each
|
|
@@ -3684,6 +3796,7 @@ the rules the CMS follows that Eleventy does not know about on its own:
|
|
|
3684
3796
|
| Rule | How the config does it |
|
|
3685
3797
|
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
3686
3798
|
| `draft: true` hides a document | An `addPreprocessor` that returns `false` for it. `BUILD_DRAFTS=1` builds drafts anyway, for a local preview. |
|
|
3799
|
+
| `visibility: unlisted` is listed nowhere | An `addPreprocessor` that sets `eleventyExcludeFromCollections` on the document, so a feed, sitemap or archive drawn from collections leaves it out, and sets `noindex` for the layout to print as `<meta name="robots" content="noindex">`. Any value other than `public` or `unlisted` returns `false`, as a draft does. |
|
|
3687
3800
|
| A file with no `permalink` gets the CMS default | An `addPreprocessor` that fills in `/{yyyy}/{mm}/{slug}/` for a post and `/{slug}/` for a page, slugifying the title exactly as the CMS does. Front matter always wins; the CMS writes `permalink` into every file it saves, so this only matters for hand-authored files. |
|
|
3688
3801
|
| `content/uploads/` is served at `/uploads/` | `addPassthroughCopy({ 'content/uploads': 'uploads' })`, plus an `ignores` entry for the same path. Without the ignore, an upload that happens to be Markdown would be copied _and_ rendered as a page; the CMS only ever indexes `posts/` and `pages/`. |
|
|
3689
3802
|
| `content/_data/federation/` is data | `followers.json` is an ordinary data file in a namespaced `_data` subdirectory, so Eleventy hands it over as `federation.followers` without being told. The monthly inbox logs are JSON Lines, which Eleventy has no reader for, so the config registers one with `addDataExtension('jsonl', …)`: each month becomes an entry of `federation.inbox`, keyed by its `{yyyy}-{mm}` name. |
|
|
@@ -38,4 +38,6 @@
|
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
})();
|
|
41
|
-
</script></template></geekity-admin-bar>
|
|
41
|
+
</script></template></geekity-admin-bar>{% if notice %}
|
|
42
|
+
<p class="geekity-unpublished-notice" style="all: initial; display: block; box-sizing: border-box; margin: 0; padding: 8px 16px; background: #fcf9e8; color: #1d2327; border-bottom: 1px solid #dba617; font: 14px/1.5 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif">{{ notice }}</p>
|
|
43
|
+
{%- endif %}
|