@geekity/cms 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/README.md +188 -9
  2. package/admin/pages/account/login.njk +3 -0
  3. package/admin/pages/documents/editor.njk +20 -0
  4. package/admin/pages/indieauth/consent.njk +51 -0
  5. package/admin/pages/indieauth/refused.njk +11 -0
  6. package/admin/pages/settings/general.njk +12 -2
  7. package/admin/pages/settings/reading.njk +93 -0
  8. package/admin/pages/users/apps.njk +74 -0
  9. package/admin/pages/users/edit.njk +12 -0
  10. package/admin/static/admin.css +27 -0
  11. package/dist/admin/accounts.d.ts +3 -0
  12. package/dist/admin/accounts.d.ts.map +1 -1
  13. package/dist/admin/accounts.js +5 -0
  14. package/dist/admin/accounts.js.map +1 -1
  15. package/dist/admin/documents.d.ts +4 -0
  16. package/dist/admin/documents.d.ts.map +1 -1
  17. package/dist/admin/documents.js +45 -5
  18. package/dist/admin/documents.js.map +1 -1
  19. package/dist/admin/federation.js +2 -2
  20. package/dist/admin/federation.js.map +1 -1
  21. package/dist/admin/headers.d.ts +9 -2
  22. package/dist/admin/headers.d.ts.map +1 -1
  23. package/dist/admin/headers.js +16 -7
  24. package/dist/admin/headers.js.map +1 -1
  25. package/dist/admin/menu.d.ts.map +1 -1
  26. package/dist/admin/menu.js +2 -1
  27. package/dist/admin/menu.js.map +1 -1
  28. package/dist/admin/routes.d.ts.map +1 -1
  29. package/dist/admin/routes.js +48 -5
  30. package/dist/admin/routes.js.map +1 -1
  31. package/dist/admin/settings-general.d.ts.map +1 -1
  32. package/dist/admin/settings-general.js +28 -3
  33. package/dist/admin/settings-general.js.map +1 -1
  34. package/dist/admin/settings-reading.d.ts.map +1 -1
  35. package/dist/admin/settings-reading.js +15 -1
  36. package/dist/admin/settings-reading.js.map +1 -1
  37. package/dist/admin/settings.d.ts +83 -4
  38. package/dist/admin/settings.d.ts.map +1 -1
  39. package/dist/admin/settings.js +166 -4
  40. package/dist/admin/settings.js.map +1 -1
  41. package/dist/admin/templates.d.ts +3 -0
  42. package/dist/admin/templates.d.ts.map +1 -1
  43. package/dist/admin/templates.js +3 -0
  44. package/dist/admin/templates.js.map +1 -1
  45. package/dist/admin/users.d.ts +8 -0
  46. package/dist/admin/users.d.ts.map +1 -1
  47. package/dist/admin/users.js +9 -0
  48. package/dist/admin/users.js.map +1 -1
  49. package/dist/config.d.ts +34 -0
  50. package/dist/config.d.ts.map +1 -1
  51. package/dist/config.js +1 -0
  52. package/dist/config.js.map +1 -1
  53. package/dist/content/pinned.d.ts +26 -0
  54. package/dist/content/pinned.d.ts.map +1 -0
  55. package/dist/content/pinned.js +42 -0
  56. package/dist/content/pinned.js.map +1 -0
  57. package/dist/content/store.d.ts +7 -0
  58. package/dist/content/store.d.ts.map +1 -1
  59. package/dist/content/store.js +20 -0
  60. package/dist/content/store.js.map +1 -1
  61. package/dist/env.d.ts +21 -0
  62. package/dist/env.d.ts.map +1 -1
  63. package/dist/federation/actor.d.ts +15 -0
  64. package/dist/federation/actor.d.ts.map +1 -1
  65. package/dist/federation/actor.js +94 -3
  66. package/dist/federation/actor.js.map +1 -1
  67. package/dist/federation/article.d.ts +13 -1
  68. package/dist/federation/article.d.ts.map +1 -1
  69. package/dist/federation/article.js +45 -6
  70. package/dist/federation/article.js.map +1 -1
  71. package/dist/federation/delivery.d.ts.map +1 -1
  72. package/dist/federation/delivery.js +36 -4
  73. package/dist/federation/delivery.js.map +1 -1
  74. package/dist/federation/federation.d.ts.map +1 -1
  75. package/dist/federation/federation.js +24 -2
  76. package/dist/federation/federation.js.map +1 -1
  77. package/dist/federation/mount.js +2 -2
  78. package/dist/federation/mount.js.map +1 -1
  79. package/dist/federation/paths.d.ts +30 -0
  80. package/dist/federation/paths.d.ts.map +1 -1
  81. package/dist/federation/paths.js +36 -0
  82. package/dist/federation/paths.js.map +1 -1
  83. package/dist/images/icons.d.ts +44 -25
  84. package/dist/images/icons.d.ts.map +1 -1
  85. package/dist/images/icons.js +205 -60
  86. package/dist/images/icons.js.map +1 -1
  87. package/dist/images/index.d.ts +2 -2
  88. package/dist/images/index.d.ts.map +1 -1
  89. package/dist/images/index.js +1 -1
  90. package/dist/images/index.js.map +1 -1
  91. package/dist/images/markup.d.ts +14 -0
  92. package/dist/images/markup.d.ts.map +1 -1
  93. package/dist/images/markup.js +16 -11
  94. package/dist/images/markup.js.map +1 -1
  95. package/dist/images/variants.d.ts +11 -0
  96. package/dist/images/variants.d.ts.map +1 -1
  97. package/dist/images/variants.js +24 -4
  98. package/dist/images/variants.js.map +1 -1
  99. package/dist/index.d.ts +15 -5
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +33 -2
  102. package/dist/index.js.map +1 -1
  103. package/dist/indexnow.d.ts +34 -0
  104. package/dist/indexnow.d.ts.map +1 -0
  105. package/dist/indexnow.js +141 -0
  106. package/dist/indexnow.js.map +1 -0
  107. package/dist/indieauth/bearer.d.ts +39 -0
  108. package/dist/indieauth/bearer.d.ts.map +1 -0
  109. package/dist/indieauth/bearer.js +63 -0
  110. package/dist/indieauth/bearer.js.map +1 -0
  111. package/dist/indieauth/client.d.ts +61 -0
  112. package/dist/indieauth/client.d.ts.map +1 -0
  113. package/dist/indieauth/client.js +139 -0
  114. package/dist/indieauth/client.js.map +1 -0
  115. package/dist/indieauth/connected-apps.d.ts +23 -0
  116. package/dist/indieauth/connected-apps.d.ts.map +1 -0
  117. package/dist/indieauth/connected-apps.js +73 -0
  118. package/dist/indieauth/connected-apps.js.map +1 -0
  119. package/dist/indieauth/consent.d.ts +28 -0
  120. package/dist/indieauth/consent.d.ts.map +1 -0
  121. package/dist/indieauth/consent.js +185 -0
  122. package/dist/indieauth/consent.js.map +1 -0
  123. package/dist/indieauth/discovery.d.ts +87 -0
  124. package/dist/indieauth/discovery.d.ts.map +1 -0
  125. package/dist/indieauth/discovery.js +127 -0
  126. package/dist/indieauth/discovery.js.map +1 -0
  127. package/dist/indieauth/grants.d.ts +57 -0
  128. package/dist/indieauth/grants.d.ts.map +1 -0
  129. package/dist/indieauth/grants.js +35 -0
  130. package/dist/indieauth/grants.js.map +1 -0
  131. package/dist/indieauth/identity.d.ts +36 -0
  132. package/dist/indieauth/identity.d.ts.map +1 -0
  133. package/dist/indieauth/identity.js +77 -0
  134. package/dist/indieauth/identity.js.map +1 -0
  135. package/dist/indieauth/redeem.d.ts +47 -0
  136. package/dist/indieauth/redeem.d.ts.map +1 -0
  137. package/dist/indieauth/redeem.js +69 -0
  138. package/dist/indieauth/redeem.js.map +1 -0
  139. package/dist/indieauth/request.d.ts +47 -0
  140. package/dist/indieauth/request.d.ts.map +1 -0
  141. package/dist/indieauth/request.js +104 -0
  142. package/dist/indieauth/request.js.map +1 -0
  143. package/dist/indieauth/token.d.ts +19 -0
  144. package/dist/indieauth/token.d.ts.map +1 -0
  145. package/dist/indieauth/token.js +110 -0
  146. package/dist/indieauth/token.js.map +1 -0
  147. package/dist/indieauth/tokens.d.ts +131 -0
  148. package/dist/indieauth/tokens.d.ts.map +1 -0
  149. package/dist/indieauth/tokens.js +205 -0
  150. package/dist/indieauth/tokens.js.map +1 -0
  151. package/dist/web/admin-bar.d.ts +3 -1
  152. package/dist/web/admin-bar.d.ts.map +1 -1
  153. package/dist/web/admin-bar.js +5 -1
  154. package/dist/web/admin-bar.js.map +1 -1
  155. package/dist/web/archive.d.ts +1 -1
  156. package/dist/web/archive.d.ts.map +1 -1
  157. package/dist/web/archive.js +3 -2
  158. package/dist/web/archive.js.map +1 -1
  159. package/dist/web/authors.d.ts +19 -0
  160. package/dist/web/authors.d.ts.map +1 -1
  161. package/dist/web/authors.js +25 -0
  162. package/dist/web/authors.js.map +1 -1
  163. package/dist/web/context.d.ts +25 -0
  164. package/dist/web/context.d.ts.map +1 -1
  165. package/dist/web/context.js +18 -0
  166. package/dist/web/context.js.map +1 -1
  167. package/dist/web/feed-atom.d.ts.map +1 -1
  168. package/dist/web/feed-atom.js +5 -2
  169. package/dist/web/feed-atom.js.map +1 -1
  170. package/dist/web/feed-item.d.ts +24 -6
  171. package/dist/web/feed-item.d.ts.map +1 -1
  172. package/dist/web/feed-item.js +16 -8
  173. package/dist/web/feed-item.js.map +1 -1
  174. package/dist/web/feed-json.d.ts +6 -2
  175. package/dist/web/feed-json.d.ts.map +1 -1
  176. package/dist/web/feed-json.js +6 -2
  177. package/dist/web/feed-json.js.map +1 -1
  178. package/dist/web/feed-rss.d.ts.map +1 -1
  179. package/dist/web/feed-rss.js +17 -4
  180. package/dist/web/feed-rss.js.map +1 -1
  181. package/dist/web/feed-source.d.ts +31 -0
  182. package/dist/web/feed-source.d.ts.map +1 -1
  183. package/dist/web/feed-source.js +31 -0
  184. package/dist/web/feed-source.js.map +1 -1
  185. package/dist/web/feed-xml.d.ts +2 -0
  186. package/dist/web/feed-xml.d.ts.map +1 -1
  187. package/dist/web/feed-xml.js +2 -0
  188. package/dist/web/feed-xml.js.map +1 -1
  189. package/dist/web/feeds.d.ts.map +1 -1
  190. package/dist/web/feeds.js +15 -3
  191. package/dist/web/feeds.js.map +1 -1
  192. package/dist/web/index.d.ts +4 -2
  193. package/dist/web/index.d.ts.map +1 -1
  194. package/dist/web/index.js +3 -2
  195. package/dist/web/index.js.map +1 -1
  196. package/dist/web/indexnow.d.ts +9 -0
  197. package/dist/web/indexnow.d.ts.map +1 -0
  198. package/dist/web/indexnow.js +27 -0
  199. package/dist/web/indexnow.js.map +1 -0
  200. package/dist/web/llms.d.ts +58 -0
  201. package/dist/web/llms.d.ts.map +1 -0
  202. package/dist/web/llms.js +91 -0
  203. package/dist/web/llms.js.map +1 -0
  204. package/dist/web/locale.d.ts +41 -0
  205. package/dist/web/locale.d.ts.map +1 -0
  206. package/dist/web/locale.js +56 -0
  207. package/dist/web/locale.js.map +1 -0
  208. package/dist/web/manifest.d.ts +50 -0
  209. package/dist/web/manifest.d.ts.map +1 -0
  210. package/dist/web/manifest.js +56 -0
  211. package/dist/web/manifest.js.map +1 -0
  212. package/dist/web/negotiate.d.ts.map +1 -1
  213. package/dist/web/negotiate.js +6 -0
  214. package/dist/web/negotiate.js.map +1 -1
  215. package/dist/web/oembed.d.ts +104 -0
  216. package/dist/web/oembed.d.ts.map +1 -0
  217. package/dist/web/oembed.js +290 -0
  218. package/dist/web/oembed.js.map +1 -0
  219. package/dist/web/opensearch.d.ts +35 -0
  220. package/dist/web/opensearch.d.ts.map +1 -0
  221. package/dist/web/opensearch.js +65 -0
  222. package/dist/web/opensearch.js.map +1 -0
  223. package/dist/web/render.d.ts +6 -1
  224. package/dist/web/render.d.ts.map +1 -1
  225. package/dist/web/render.js +40 -10
  226. package/dist/web/render.js.map +1 -1
  227. package/dist/web/robots.d.ts +89 -0
  228. package/dist/web/robots.d.ts.map +1 -0
  229. package/dist/web/robots.js +259 -0
  230. package/dist/web/robots.js.map +1 -0
  231. package/dist/web/routes.d.ts.map +1 -1
  232. package/dist/web/routes.js +179 -8
  233. package/dist/web/routes.js.map +1 -1
  234. package/dist/web/share-image.d.ts +51 -0
  235. package/dist/web/share-image.d.ts.map +1 -0
  236. package/dist/web/share-image.js +43 -0
  237. package/dist/web/share-image.js.map +1 -0
  238. package/dist/web/sitemap.d.ts +0 -26
  239. package/dist/web/sitemap.d.ts.map +1 -1
  240. package/dist/web/sitemap.js +0 -44
  241. package/dist/web/sitemap.js.map +1 -1
  242. package/dist/web/templates.d.ts +16 -9
  243. package/dist/web/templates.d.ts.map +1 -1
  244. package/dist/web/templates.js +88 -55
  245. package/dist/web/templates.js.map +1 -1
  246. package/dist/web/themes.d.ts +33 -0
  247. package/dist/web/themes.d.ts.map +1 -1
  248. package/dist/web/themes.js +57 -0
  249. package/dist/web/themes.js.map +1 -1
  250. package/dist/webmention/discovery.d.ts +4 -2
  251. package/dist/webmention/discovery.d.ts.map +1 -1
  252. package/dist/webmention/discovery.js +14 -8
  253. package/dist/webmention/discovery.js.map +1 -1
  254. package/dist/webmention/fetch-public.d.ts +2 -0
  255. package/dist/webmention/fetch-public.d.ts.map +1 -1
  256. package/dist/webmention/fetch-public.js +1 -1
  257. package/dist/webmention/fetch-public.js.map +1 -1
  258. package/package.json +2 -1
  259. package/templates/site/content/_data/site.json +0 -1
  260. package/themes/default/README.md +174 -43
  261. package/themes/default/layouts/base.njk +116 -17
  262. package/themes/default/layouts/front-page.njk +7 -1
  263. package/themes/default/layouts/home.njk +11 -0
  264. package/themes/default/layouts/page.njk +4 -3
  265. package/themes/default/layouts/post.njk +5 -4
  266. package/themes/default/layouts/search.njk +4 -5
  267. package/themes/default/partials/archive.njk +3 -1
  268. package/themes/default/partials/bio.njk +16 -2
  269. package/themes/default/partials/breadcrumbs.njk +20 -0
  270. package/themes/default/partials/conversation.njk +4 -1
  271. package/themes/default/partials/jsonld.njk +49 -9
  272. package/themes/default/partials/kicker.njk +6 -4
  273. package/themes/default/partials/lang.njk +7 -0
  274. package/themes/default/partials/post-list.njk +5 -3
  275. package/themes/default/partials/reply-context.njk +4 -2
  276. package/themes/default/src/style.css +14 -0
  277. package/themes/default/static/style.css +57 -0
  278. package/themes/default/theme.json +2 -0
@@ -0,0 +1,104 @@
1
+ import type { Document } from '../content/document.ts';
2
+ import type { ImageConfig } from '../images/paths.ts';
3
+ import type { AuthorContext } from './authors.ts';
4
+ import type { SiteData } from './context.ts';
5
+ import type { ConditionalHeaders } from './negotiate.ts';
6
+ /**
7
+ * The oEmbed provider (TASK-205): what WordPress, Discourse and the rest ask
8
+ * to turn a pasted post URL into a card.
9
+ *
10
+ * Under `/_geekity/`, the CMS's own prefix, so no permalink can take it. Each
11
+ * post and page links it from its head, with its own URL in the query.
12
+ */
13
+ /** The endpoint's URL. */
14
+ export declare const OEMBED_PATH = "/_geekity/oembed";
15
+ /**
16
+ * The embed view's URL (TASK-208): the card alone as a page, with the
17
+ * document's absolute URL in `?url=`, and the one response on the site another
18
+ * origin may frame.
19
+ *
20
+ * WordPress keeps a rich embed from a provider it does not know only when its
21
+ * html holds an `<iframe>`, so the oEmbed html frames this page after the
22
+ * blockquote, the way WordPress's own provider does.
23
+ */
24
+ export declare const EMBED_PATH = "/_geekity/embed";
25
+ /** The formats the spec names. Anything else is a 501. */
26
+ export type OEmbedFormat = 'json' | 'xml';
27
+ /** One request, from its query. */
28
+ export interface OEmbedRequest {
29
+ /** The URL to embed, as given. */
30
+ url: string;
31
+ /** `undefined` for a format this provider does not serve. */
32
+ format: OEmbedFormat | undefined;
33
+ maxwidth?: number | undefined;
34
+ maxheight?: number | undefined;
35
+ }
36
+ /** A `type: rich` response. The thumbnail's three fields come together or not at all. */
37
+ export interface OEmbedRich {
38
+ version: '1.0';
39
+ type: 'rich';
40
+ title: string;
41
+ author_name?: string;
42
+ author_url?: string;
43
+ provider_name: string;
44
+ provider_url: string;
45
+ html: string;
46
+ width: number;
47
+ height: number;
48
+ thumbnail_url?: string;
49
+ thumbnail_width?: number;
50
+ thumbnail_height?: number;
51
+ }
52
+ /** A query as a request. A missing `format` is JSON, which every consumer reads. */
53
+ export declare function oEmbedRequest(query: (name: string) => string | undefined): OEmbedRequest;
54
+ /** One published document, served at `href`, and what its card names beside it. */
55
+ export interface EmbedSubject {
56
+ document: Document;
57
+ href: string;
58
+ author: AuthorContext | undefined;
59
+ config: {
60
+ baseUrl: string;
61
+ };
62
+ site: SiteData;
63
+ }
64
+ /**
65
+ * The embed of one published document, served at `href`.
66
+ *
67
+ * The title is the document's, else a note's first words. The html is the
68
+ * card, then a hidden sandboxed frame of {@link EMBED_PATH}: a consumer that
69
+ * keeps the html as given shows the blockquote, one that strips iframes still
70
+ * has it, and WordPress, which keeps only the frame, shows that once the page
71
+ * inside has told it how tall it is. The thumbnail is the
72
+ * document's own `image`, never the site's avatar, and only when its size is
73
+ * recorded: the spec requires the size with the URL, and a render never opens
74
+ * an image (decision-10). One wider or taller than the consumer allows is left
75
+ * out, because the spec says it must respect `maxwidth` and `maxheight` too.
76
+ */
77
+ export declare function oEmbedFor(input: EmbedSubject & {
78
+ config: ImageConfig & {
79
+ baseUrl: string;
80
+ };
81
+ request: OEmbedRequest;
82
+ }): OEmbedRich;
83
+ /** The embed as a response in `format`, or a 304 to a client that already holds it. */
84
+ export declare function oEmbedResponse(embed: OEmbedRich, format: OEmbedFormat, conditional: ConditionalHeaders | undefined): Response;
85
+ /**
86
+ * The embed view's page: the card, a style to read it by, and the script that
87
+ * speaks WordPress's side of the embed.
88
+ *
89
+ * Nothing in it depends on who asked. There is no theme, no admin bar and no
90
+ * session, so a reader of a framing site sees the same card a signed-in admin
91
+ * would, and nothing about either. `noindex` because the post is the page to
92
+ * find, not its card.
93
+ */
94
+ export declare function embedPage(subject: EmbedSubject): string;
95
+ /**
96
+ * The embed page as a response, or a 304 to a client that already holds it.
97
+ *
98
+ * Its policy is its own and complete: the one inline style and the one inline
99
+ * script by hash, nothing else loaded, and any origin may frame it. The
100
+ * caller marks the context frameable as well, so the baseline leaves off
101
+ * `X-Frame-Options`, which has no way to say "anyone".
102
+ */
103
+ export declare function embedResponse(page: string, conditional: ConditionalHeaders | undefined): Response;
104
+ //# sourceMappingURL=oembed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oembed.d.ts","sourceRoot":"","sources":["../../src/web/oembed.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAIzD;;;;;;GAMG;AAEH,0BAA0B;AAC1B,eAAO,MAAM,WAAW,qBAAqB,CAAC;AAE9C;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,oBAAoB,CAAC;AAE5C,0DAA0D;AAC1D,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC;AAe1C,mCAAmC;AACnC,MAAM,WAAW,aAAa;IAC5B,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,MAAM,EAAE,YAAY,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,yFAAyF;AACzF,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GAAG,aAAa,CAQxF;AAED,mFAAmF;AACnF,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC;IAClC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,YAAY,GAAG;IAAE,MAAM,EAAE,WAAW,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,GAC1F,UAAU,CA+CZ;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,kBAAkB,GAAG,SAAS,GAC1C,QAAQ,CAWV;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAkBvD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,GAAG,SAAS,GAAG,QAAQ,CAcjG"}
@@ -0,0 +1,290 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { postLabel } from '../content/post-type.js';
3
+ import { siteLocale, siteTimezone } from './context.js';
4
+ import { feedExcerpt } from './feed-item.js';
5
+ import { escapeXml } from './feed-xml.js';
6
+ import { absoluteUrl, contentEtag, isNotModified } from './negotiate.js';
7
+ import { shareImage } from './share-image.js';
8
+ import { formatDate } from './templates.js';
9
+ /**
10
+ * The oEmbed provider (TASK-205): what WordPress, Discourse and the rest ask
11
+ * to turn a pasted post URL into a card.
12
+ *
13
+ * Under `/_geekity/`, the CMS's own prefix, so no permalink can take it. Each
14
+ * post and page links it from its head, with its own URL in the query.
15
+ */
16
+ /** The endpoint's URL. */
17
+ export const OEMBED_PATH = '/_geekity/oembed';
18
+ /**
19
+ * The embed view's URL (TASK-208): the card alone as a page, with the
20
+ * document's absolute URL in `?url=`, and the one response on the site another
21
+ * origin may frame.
22
+ *
23
+ * WordPress keeps a rich embed from a provider it does not know only when its
24
+ * html holds an `<iframe>`, so the oEmbed html frames this page after the
25
+ * blockquote, the way WordPress's own provider does.
26
+ */
27
+ export const EMBED_PATH = '/_geekity/embed';
28
+ const CONTENT_TYPES = {
29
+ json: 'application/json; charset=utf-8',
30
+ xml: 'text/xml; charset=utf-8',
31
+ };
32
+ /**
33
+ * The size the card asks for. A rich embed must give both, and a blockquote
34
+ * of words reflows to whatever it is given, so these are what WordPress asks
35
+ * for its own cards rather than a measurement.
36
+ */
37
+ const DEFAULT_WIDTH = 600;
38
+ const DEFAULT_HEIGHT = 338;
39
+ /** A query as a request. A missing `format` is JSON, which every consumer reads. */
40
+ export function oEmbedRequest(query) {
41
+ const format = query('format') ?? 'json';
42
+ return {
43
+ url: query('url') ?? '',
44
+ format: format === 'json' || format === 'xml' ? format : undefined,
45
+ maxwidth: positiveInteger(query('maxwidth')),
46
+ maxheight: positiveInteger(query('maxheight')),
47
+ };
48
+ }
49
+ /**
50
+ * The embed of one published document, served at `href`.
51
+ *
52
+ * The title is the document's, else a note's first words. The html is the
53
+ * card, then a hidden sandboxed frame of {@link EMBED_PATH}: a consumer that
54
+ * keeps the html as given shows the blockquote, one that strips iframes still
55
+ * has it, and WordPress, which keeps only the frame, shows that once the page
56
+ * inside has told it how tall it is. The thumbnail is the
57
+ * document's own `image`, never the site's avatar, and only when its size is
58
+ * recorded: the spec requires the size with the URL, and a render never opens
59
+ * an image (decision-10). One wider or taller than the consumer allows is left
60
+ * out, because the spec says it must respect `maxwidth` and `maxheight` too.
61
+ */
62
+ export function oEmbedFor(input) {
63
+ const { document, author, config, site, request } = input;
64
+ const url = (pathname) => absoluteUrl(pathname, config.baseUrl);
65
+ const title = postLabel(document);
66
+ const authorUrl = author?.url === undefined ? undefined : url(author.url);
67
+ const width = Math.min(DEFAULT_WIDTH, request.maxwidth ?? DEFAULT_WIDTH);
68
+ const height = Math.min(DEFAULT_HEIGHT, request.maxheight ?? DEFAULT_HEIGHT);
69
+ const image = shareImage({
70
+ config,
71
+ image: document.extra['image'],
72
+ imageAlt: document.extra['imageAlt'],
73
+ title,
74
+ avatar: undefined,
75
+ owner: site.title,
76
+ });
77
+ const thumbnail = image?.size !== undefined &&
78
+ image.size.width <= (request.maxwidth ?? Infinity) &&
79
+ image.size.height <= (request.maxheight ?? Infinity)
80
+ ? { url: url(image.url), ...image.size }
81
+ : undefined;
82
+ return {
83
+ version: '1.0',
84
+ type: 'rich',
85
+ title,
86
+ ...(author === undefined ? {} : { author_name: author.name }),
87
+ ...(authorUrl === undefined ? {} : { author_url: authorUrl }),
88
+ provider_name: site.title,
89
+ provider_url: url('/'),
90
+ html: `${embedCard(input)}${embedFrame({
91
+ src: url(`${EMBED_PATH}?${new URLSearchParams({ url: url(input.href) }).toString()}`),
92
+ title,
93
+ width,
94
+ height,
95
+ })}`,
96
+ width,
97
+ height,
98
+ ...(thumbnail === undefined
99
+ ? {}
100
+ : {
101
+ thumbnail_url: thumbnail.url,
102
+ thumbnail_width: thumbnail.width,
103
+ thumbnail_height: thumbnail.height,
104
+ }),
105
+ };
106
+ }
107
+ /** The embed as a response in `format`, or a 304 to a client that already holds it. */
108
+ export function oEmbedResponse(embed, format, conditional) {
109
+ const body = format === 'json' ? JSON.stringify(embed) : oEmbedXml(embed);
110
+ const etag = contentEtag(`oembed-${format}`, body);
111
+ const headers = new Headers({ etag, 'cache-control': 'no-cache' });
112
+ if (isNotModified(conditional, etag, undefined)) {
113
+ return new Response(null, { status: 304, headers });
114
+ }
115
+ headers.set('content-type', CONTENT_TYPES[format]);
116
+ return new Response(body, { headers });
117
+ }
118
+ /**
119
+ * The embed view's page: the card, a style to read it by, and the script that
120
+ * speaks WordPress's side of the embed.
121
+ *
122
+ * Nothing in it depends on who asked. There is no theme, no admin bar and no
123
+ * session, so a reader of a framing site sees the same card a signed-in admin
124
+ * would, and nothing about either. `noindex` because the post is the page to
125
+ * find, not its card.
126
+ */
127
+ export function embedPage(subject) {
128
+ return [
129
+ '<!doctype html>',
130
+ `<html lang="${escapeXml(siteLocale(subject.site))}">`,
131
+ '<head>',
132
+ '<meta charset="utf-8">',
133
+ '<meta name="viewport" content="width=device-width, initial-scale=1">',
134
+ '<meta name="robots" content="noindex">',
135
+ `<title>${escapeXml(postLabel(subject.document))}</title>`,
136
+ `<style>${EMBED_STYLE}</style>`,
137
+ '</head>',
138
+ '<body>',
139
+ embedCard(subject),
140
+ `<script>${EMBED_SCRIPT}</script>`,
141
+ '</body>',
142
+ '</html>',
143
+ '',
144
+ ].join('\n');
145
+ }
146
+ /**
147
+ * The embed page as a response, or a 304 to a client that already holds it.
148
+ *
149
+ * Its policy is its own and complete: the one inline style and the one inline
150
+ * script by hash, nothing else loaded, and any origin may frame it. The
151
+ * caller marks the context frameable as well, so the baseline leaves off
152
+ * `X-Frame-Options`, which has no way to say "anyone".
153
+ */
154
+ export function embedResponse(page, conditional) {
155
+ const etag = contentEtag('embed', page);
156
+ const headers = new Headers({
157
+ etag,
158
+ 'cache-control': 'no-cache',
159
+ 'content-security-policy': EMBED_CONTENT_SECURITY_POLICY,
160
+ });
161
+ if (isNotModified(conditional, etag, undefined)) {
162
+ return new Response(null, { status: 304, headers });
163
+ }
164
+ headers.set('content-type', 'text/html; charset=utf-8');
165
+ return new Response(page, { headers });
166
+ }
167
+ /**
168
+ * The card's look inside the frame. Inline, like the script, because the page
169
+ * loads nothing: one request per embed is all a framing page should cost.
170
+ */
171
+ const EMBED_STYLE = [
172
+ 'html{color-scheme:light}',
173
+ 'body{margin:0;background:#fff;color:#1f1f1f;font:16px/1.5 system-ui,-apple-system,"Segoe UI",sans-serif}',
174
+ '.geekity-embed{margin:0;padding:16px 20px;border:1px solid #d6d6d6;border-radius:8px;overflow-wrap:anywhere}',
175
+ '.geekity-embed p{margin:0 0 8px}',
176
+ '.geekity-embed p:last-child{margin:0;font-size:14px;color:#595959}',
177
+ '.geekity-embed a{color:#0b57d0}',
178
+ ].join('');
179
+ /**
180
+ * WordPress's embed protocol, the framed side (wp-includes/js/wp-embed.js is
181
+ * the other).
182
+ *
183
+ * WordPress puts a secret in the frame's URL as `#?secret=` and keeps the
184
+ * frame hidden until a message with that secret says how tall the page is.
185
+ * The page says so when it loads, when it is resized, and whenever the host
186
+ * says it is ready. Its frame is sandboxed with scripts only, so a link cannot
187
+ * navigate by itself: a click is sent to the host as a `link` message, which
188
+ * WordPress follows when the link is on this site's host. Opened directly
189
+ * there is no secret, and the links are ordinary links.
190
+ */
191
+ const EMBED_SCRIPT = [
192
+ '(function(){',
193
+ 'var found=/[?&]secret=([A-Za-z0-9]+)/.exec(location.hash);',
194
+ 'if(!found||window.parent===window)return;',
195
+ 'var secret=found[1];',
196
+ "function send(message,value){window.parent.postMessage({message:message,value:value,secret:secret},'*');}",
197
+ "function height(){send('height',Math.ceil(document.documentElement.getBoundingClientRect().height));}",
198
+ "addEventListener('load',height);",
199
+ "addEventListener('resize',height);",
200
+ "addEventListener('message',function(event){var data=event.data;if(data&&data.message==='ready'&&data.secret===secret)height();});",
201
+ "document.addEventListener('click',function(event){var link=event.target instanceof Element?event.target.closest('a[href]'):null;if(!link)return;event.preventDefault();send('link',link.href);});",
202
+ '})();',
203
+ ].join('');
204
+ /** A CSP source naming one inline element's exact contents. */
205
+ function inlineHash(contents) {
206
+ return `'sha256-${createHash('sha256').update(contents, 'utf8').digest('base64')}'`;
207
+ }
208
+ const EMBED_CONTENT_SECURITY_POLICY = [
209
+ "default-src 'none'",
210
+ `style-src ${inlineHash(EMBED_STYLE)}`,
211
+ `script-src ${inlineHash(EMBED_SCRIPT)}`,
212
+ "base-uri 'none'",
213
+ "form-action 'none'",
214
+ 'frame-ancestors *',
215
+ ].join('; ');
216
+ /**
217
+ * The frame of the embed view, in the shape WordPress's own provider sends:
218
+ * sandboxed, borderless, and hidden until the page inside reports its height.
219
+ */
220
+ function embedFrame(input) {
221
+ return [
222
+ '<iframe sandbox="allow-scripts" security="restricted"',
223
+ ` src="${escapeXml(input.src)}"`,
224
+ ` width="${String(input.width)}" height="${String(input.height)}"`,
225
+ ` title="${escapeXml(input.title)}"`,
226
+ ' frameborder="0" marginwidth="0" marginheight="0" scrolling="no"',
227
+ ' style="position: absolute; visibility: hidden;"></iframe>',
228
+ ].join('');
229
+ }
230
+ /** The XML spelling: one element per field, under `<oembed>`. */
231
+ function oEmbedXml(embed) {
232
+ const fields = Object.entries(embed).map(([name, value]) => ` <${name}>${escapeXml(String(value))}</${name}>`);
233
+ return [
234
+ '<?xml version="1.0" encoding="utf-8" standalone="yes"?>',
235
+ '<oembed>',
236
+ ...fields,
237
+ '</oembed>',
238
+ '',
239
+ ].join('\n');
240
+ }
241
+ /**
242
+ * The card of one document, as both the oEmbed html and the embed page carry
243
+ * it. A blockquote of escaped text and links, so it needs nothing from this
244
+ * site to draw and can carry nothing a consumer would run.
245
+ */
246
+ function embedCard(subject) {
247
+ const { document, author, site, config } = subject;
248
+ const url = (pathname) => absoluteUrl(pathname, config.baseUrl);
249
+ return card({
250
+ href: url(subject.href),
251
+ title: postLabel(document),
252
+ excerpt: document.title === '' ? '' : feedExcerpt(document),
253
+ author: author === undefined
254
+ ? undefined
255
+ : { name: author.name, url: author.url === undefined ? undefined : url(author.url) },
256
+ date: {
257
+ iso: formatDate(document.date, 'iso'),
258
+ readable: formatDate(document.date, 'readable', siteTimezone(site), siteLocale(site)),
259
+ },
260
+ site: { name: site.title, url: url('/') },
261
+ });
262
+ }
263
+ /** The card: a linked title, the excerpt, who and when, and the site it is from. */
264
+ function card(input) {
265
+ const link = (href, text) => `<a href="${escapeXml(href)}">${escapeXml(text)}</a>`;
266
+ const { author, date } = input;
267
+ const byline = [
268
+ ...(author === undefined
269
+ ? []
270
+ : [author.url === undefined ? escapeXml(author.name) : link(author.url, author.name)]),
271
+ ...(date.iso === ''
272
+ ? []
273
+ : [`<time datetime="${escapeXml(date.iso)}">${escapeXml(date.readable)}</time>`]),
274
+ ];
275
+ return [
276
+ `<blockquote class="geekity-embed" cite="${escapeXml(input.href)}">`,
277
+ `<p><strong>${link(input.href, input.title)}</strong></p>`,
278
+ ...(input.excerpt === '' ? [] : [`<p>${escapeXml(input.excerpt)}</p>`]),
279
+ ...(byline.length === 0 ? [] : [`<p>${byline.join(', ')}</p>`]),
280
+ `<p>${link(input.site.url, input.site.name)}</p>`,
281
+ '</blockquote>',
282
+ ].join('');
283
+ }
284
+ function positiveInteger(value) {
285
+ if (value === undefined || !/^[0-9]+$/.test(value))
286
+ return undefined;
287
+ const parsed = Number(value);
288
+ return parsed > 0 ? parsed : undefined;
289
+ }
290
+ //# sourceMappingURL=oembed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oembed.js","sourceRoot":"","sources":["../../src/web/oembed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { ImageConfig } from '../images/paths.ts';
2
+ import type { ConditionalHeaders } from './negotiate.ts';
3
+ /**
4
+ * The OpenSearch description (TASK-204): what a browser reads to offer the
5
+ * site's own search from its address bar.
6
+ *
7
+ * A fixed route at the root for the reason the manifest is one, so no
8
+ * permalink can take it, and linked from the head of every page.
9
+ */
10
+ /** The description's URL. */
11
+ export declare const OPENSEARCH_PATH = "/opensearch.xml";
12
+ /**
13
+ * The description of one site, as XML.
14
+ *
15
+ * The short name is the title cut to 16 characters, and the description is
16
+ * the tagline, else the title, since the spec requires one. The image is
17
+ * `/favicon.ico`, whose 16 pixel frame is the size the spec suggests, and is
18
+ * left out on a site with no icon, where that URL answers 404. Every URL is
19
+ * absolute, because a browser keeps the template and runs it from its address
20
+ * bar, with no page to resolve a relative one against.
21
+ */
22
+ export declare function openSearchDescription(input: {
23
+ config: ImageConfig & {
24
+ baseUrl: string;
25
+ };
26
+ site: {
27
+ title: string;
28
+ tagline?: string | undefined;
29
+ icon?: unknown;
30
+ avatar?: unknown;
31
+ };
32
+ }): string;
33
+ /** The description as a response, or a 304 to a client that already holds it. */
34
+ export declare function openSearchResponse(body: string, conditional: ConditionalHeaders | undefined): Response;
35
+ //# sourceMappingURL=opensearch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opensearch.d.ts","sourceRoot":"","sources":["../../src/web/opensearch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGzD;;;;;;GAMG;AAEH,6BAA6B;AAC7B,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAQjD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,WAAW,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACzF,GAAG,MAAM,CAsBT;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,kBAAkB,GAAG,SAAS,GAC1C,QAAQ,CAUV"}
@@ -0,0 +1,65 @@
1
+ import { iconSetting, siteIconSource } from '../images/icons.js';
2
+ import { FAVICON_PATH } from './manifest.js';
3
+ import { escapeXml } from './feed-xml.js';
4
+ import { absoluteUrl, contentEtag, isNotModified } from './negotiate.js';
5
+ import { SEARCH_PATH } from './search.js';
6
+ /**
7
+ * The OpenSearch description (TASK-204): what a browser reads to offer the
8
+ * site's own search from its address bar.
9
+ *
10
+ * A fixed route at the root for the reason the manifest is one, so no
11
+ * permalink can take it, and linked from the head of every page.
12
+ */
13
+ /** The description's URL. */
14
+ export const OPENSEARCH_PATH = '/opensearch.xml';
15
+ const OPENSEARCH_CONTENT_TYPE = 'application/opensearchdescription+xml; charset=utf-8';
16
+ /** OpenSearch 1.1 caps these two, and a browser may refuse a longer one. */
17
+ const SHORT_NAME_MAX = 16;
18
+ const DESCRIPTION_MAX = 1024;
19
+ /**
20
+ * The description of one site, as XML.
21
+ *
22
+ * The short name is the title cut to 16 characters, and the description is
23
+ * the tagline, else the title, since the spec requires one. The image is
24
+ * `/favicon.ico`, whose 16 pixel frame is the size the spec suggests, and is
25
+ * left out on a site with no icon, where that URL answers 404. Every URL is
26
+ * absolute, because a browser keeps the template and runs it from its address
27
+ * bar, with no page to resolve a relative one against.
28
+ */
29
+ export function openSearchDescription(input) {
30
+ const { config, site } = input;
31
+ const url = (pathname) => absoluteUrl(pathname, config.baseUrl);
32
+ const tagline = site.tagline?.trim() ?? '';
33
+ const hasIcon = siteIconSource(config, iconSetting(site)) !== undefined;
34
+ const lines = [
35
+ '<?xml version="1.0" encoding="UTF-8"?>',
36
+ '<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">',
37
+ ` <ShortName>${escapeXml(cut(site.title, SHORT_NAME_MAX))}</ShortName>`,
38
+ ` <Description>${escapeXml(cut(tagline || site.title, DESCRIPTION_MAX))}</Description>`,
39
+ ' <InputEncoding>UTF-8</InputEncoding>',
40
+ ...(hasIcon
41
+ ? [
42
+ ` <Image width="16" height="16" type="image/x-icon">${escapeXml(url(FAVICON_PATH))}</Image>`,
43
+ ]
44
+ : []),
45
+ ` <Url type="text/html" method="get" template="${escapeXml(url(SEARCH_PATH))}?q={searchTerms}"/>`,
46
+ ` <Url type="application/opensearchdescription+xml" rel="self" template="${escapeXml(url(OPENSEARCH_PATH))}"/>`,
47
+ '</OpenSearchDescription>',
48
+ ];
49
+ return `${lines.join('\n')}\n`;
50
+ }
51
+ /** The description as a response, or a 304 to a client that already holds it. */
52
+ export function openSearchResponse(body, conditional) {
53
+ const etag = contentEtag('opensearch', body);
54
+ const headers = new Headers({ etag, 'cache-control': 'no-cache' });
55
+ if (isNotModified(conditional, etag, undefined)) {
56
+ return new Response(null, { status: 304, headers });
57
+ }
58
+ headers.set('content-type', OPENSEARCH_CONTENT_TYPE);
59
+ return new Response(body, { headers });
60
+ }
61
+ /** `text` cut to at most `max` characters, never inside a surrogate pair. */
62
+ function cut(text, max) {
63
+ return [...text].slice(0, max).join('').trimEnd();
64
+ }
65
+ //# sourceMappingURL=opensearch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opensearch.js","sourceRoot":"","sources":["../../src/web/opensearch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;GAMG;AAEH,6BAA6B;AAC7B,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAEjD,MAAM,uBAAuB,GAAG,sDAAsD,CAAC;AAEvF,4EAA4E;AAC5E,MAAM,cAAc,GAAG,EAAE,CAAC;AAC1B,MAAM,eAAe,GAAG,IAAI,CAAC;AAE7B;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAGrC;IACC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAC/B,MAAM,GAAG,GAAG,CAAC,QAAgB,EAAU,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,SAAS,CAAC;IAExE,MAAM,KAAK,GAAG;QACZ,wCAAwC;QACxC,sEAAsE;QACtE,gBAAgB,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,cAAc;QACxE,kBAAkB,SAAS,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,gBAAgB;QACxF,wCAAwC;QACxC,GAAG,CAAC,OAAO;YACT,CAAC,CAAC;gBACE,uDAAuD,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,UAAU;aAC9F;YACH,CAAC,CAAC,EAAE,CAAC;QACP,kDAAkD,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,qBAAqB;QAClG,4EAA4E,SAAS,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,KAAK;QAChH,0BAA0B;KAC3B,CAAC;IACF,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,WAA2C;IAE3C,MAAM,IAAI,GAAG,WAAW,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAC;IAEnE,IAAI,aAAa,CAAC,WAAW,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;QAChD,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,uBAAuB,CAAC,CAAC;IACrD,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,6EAA6E;AAC7E,SAAS,GAAG,CAAC,IAAY,EAAE,GAAW;IACpC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;AACpD,CAAC"}
@@ -10,7 +10,7 @@ import type { Conversation } from './conversation.ts';
10
10
  import type { FrontPageSlugs, SiteData } from './context.ts';
11
11
  import type { Pagination } from './pagination.ts';
12
12
  import type { TaxonomyBases, TaxonomyRedirect } from './taxonomy.ts';
13
- import type { ThemeSource } from './themes.ts';
13
+ import type { ThemeColors, ThemeSource } from './themes.ts';
14
14
  import type { ReplyContext } from '../webmention/reply-context.ts';
15
15
  /** Templates the default theme ships and the public routes ask for by name. */
16
16
  export declare const TEMPLATES: {
@@ -168,6 +168,11 @@ export interface Renderer {
168
168
  * the page that links to it can never come from two different themes.
169
169
  */
170
170
  themeDirs(): readonly string[];
171
+ /**
172
+ * The colours of the theme a render wears right now, gap-filled from the
173
+ * packaged theme: what the head declares and the web manifest repeats.
174
+ */
175
+ themeColors(): ThemeColors;
171
176
  /** The Nunjucks environment, for a site that wants to add its own filters. */
172
177
  readonly environment: Environment;
173
178
  }
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/web/render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/web/render.ts"],"names":[],"mappings":"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"}