@geekity/cms 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (660) hide show
  1. package/README.md +2217 -214
  2. package/admin/components/fields.njk +165 -0
  3. package/admin/layouts/base.njk +1 -1
  4. package/admin/layouts/settings-page.njk +26 -0
  5. package/admin/layouts/shell.njk +17 -3
  6. package/admin/pages/account/forgot.njk +47 -0
  7. package/admin/pages/account/login.njk +26 -0
  8. package/admin/pages/account/reset.njk +38 -0
  9. package/admin/pages/account/setup.njk +28 -0
  10. package/admin/pages/appearance/themes.njk +69 -0
  11. package/admin/pages/comments/all.njk +133 -0
  12. package/admin/{layouts/dashboard.njk → pages/dashboard/home.njk} +8 -15
  13. package/admin/{layouts/document-conflict.njk → pages/documents/conflict.njk} +1 -0
  14. package/admin/{layouts/document-editor.njk → pages/documents/editor.njk} +75 -59
  15. package/admin/{layouts/document-list.njk → pages/documents/list.njk} +19 -2
  16. package/admin/pages/documents/taxonomy.njk +95 -0
  17. package/admin/pages/federation/followers.njk +238 -0
  18. package/admin/pages/federation/settings.njk +77 -0
  19. package/admin/pages/media/library.njk +160 -0
  20. package/admin/pages/messages/all.njk +110 -0
  21. package/admin/pages/navigation/menus.njk +129 -0
  22. package/admin/{layouts → pages}/placeholder.njk +5 -1
  23. package/admin/pages/settings/discussion.njk +99 -0
  24. package/admin/pages/settings/email.njk +203 -0
  25. package/admin/pages/settings/general.njk +29 -0
  26. package/admin/pages/settings/permalinks.njk +50 -0
  27. package/admin/pages/settings/reading.njk +64 -0
  28. package/admin/pages/tools/content-index.njk +89 -0
  29. package/admin/pages/users/edit.njk +239 -0
  30. package/admin/pages/users/list.njk +51 -0
  31. package/admin/pages/users/new.njk +41 -0
  32. package/admin/static/admin.css +558 -3
  33. package/admin/static/copy.js +52 -0
  34. package/admin/static/editor.js +16 -16
  35. package/admin/static/slug.js +61 -0
  36. package/dist/access-log.d.ts +44 -0
  37. package/dist/access-log.d.ts.map +1 -0
  38. package/dist/access-log.js +71 -0
  39. package/dist/access-log.js.map +1 -0
  40. package/dist/admin/accounts.d.ts +413 -0
  41. package/dist/admin/accounts.d.ts.map +1 -0
  42. package/dist/admin/accounts.js +680 -0
  43. package/dist/admin/accounts.js.map +1 -0
  44. package/dist/admin/appearance.d.ts +80 -0
  45. package/dist/admin/appearance.d.ts.map +1 -0
  46. package/dist/admin/appearance.js +136 -0
  47. package/dist/admin/appearance.js.map +1 -0
  48. package/dist/admin/comments.d.ts +90 -0
  49. package/dist/admin/comments.d.ts.map +1 -0
  50. package/dist/admin/comments.js +244 -0
  51. package/dist/admin/comments.js.map +1 -0
  52. package/dist/admin/credentials.d.ts +26 -2
  53. package/dist/admin/credentials.d.ts.map +1 -1
  54. package/dist/admin/credentials.js +35 -2
  55. package/dist/admin/credentials.js.map +1 -1
  56. package/dist/admin/documents.d.ts +117 -10
  57. package/dist/admin/documents.d.ts.map +1 -1
  58. package/dist/admin/documents.js +328 -41
  59. package/dist/admin/documents.js.map +1 -1
  60. package/dist/admin/federation.d.ts +161 -50
  61. package/dist/admin/federation.d.ts.map +1 -1
  62. package/dist/admin/federation.js +235 -93
  63. package/dist/admin/federation.js.map +1 -1
  64. package/dist/admin/formatting.d.ts +20 -0
  65. package/dist/admin/formatting.d.ts.map +1 -0
  66. package/dist/admin/formatting.js +72 -0
  67. package/dist/admin/formatting.js.map +1 -0
  68. package/dist/admin/headers.d.ts +65 -0
  69. package/dist/admin/headers.d.ts.map +1 -0
  70. package/dist/admin/headers.js +104 -0
  71. package/dist/admin/headers.js.map +1 -0
  72. package/dist/admin/index.d.ts +38 -12
  73. package/dist/admin/index.d.ts.map +1 -1
  74. package/dist/admin/index.js +25 -7
  75. package/dist/admin/index.js.map +1 -1
  76. package/dist/admin/media.d.ts +168 -0
  77. package/dist/admin/media.d.ts.map +1 -0
  78. package/dist/admin/media.js +295 -0
  79. package/dist/admin/media.js.map +1 -0
  80. package/dist/admin/menu.d.ts +79 -0
  81. package/dist/admin/menu.d.ts.map +1 -0
  82. package/dist/admin/menu.js +143 -0
  83. package/dist/admin/menu.js.map +1 -0
  84. package/dist/admin/messages.d.ts +80 -0
  85. package/dist/admin/messages.d.ts.map +1 -0
  86. package/dist/admin/messages.js +152 -0
  87. package/dist/admin/messages.js.map +1 -0
  88. package/dist/admin/navigation.d.ts +155 -0
  89. package/dist/admin/navigation.d.ts.map +1 -0
  90. package/dist/admin/navigation.js +292 -0
  91. package/dist/admin/navigation.js.map +1 -0
  92. package/dist/admin/preview.d.ts.map +1 -1
  93. package/dist/admin/preview.js +31 -7
  94. package/dist/admin/preview.js.map +1 -1
  95. package/dist/admin/recovery.d.ts +92 -0
  96. package/dist/admin/recovery.d.ts.map +1 -0
  97. package/dist/admin/recovery.js +229 -0
  98. package/dist/admin/recovery.js.map +1 -0
  99. package/dist/admin/routes.d.ts +0 -20
  100. package/dist/admin/routes.d.ts.map +1 -1
  101. package/dist/admin/routes.js +164 -105
  102. package/dist/admin/routes.js.map +1 -1
  103. package/dist/admin/session.d.ts +17 -3
  104. package/dist/admin/session.d.ts.map +1 -1
  105. package/dist/admin/session.js +19 -5
  106. package/dist/admin/session.js.map +1 -1
  107. package/dist/admin/settings-discussion.d.ts +37 -0
  108. package/dist/admin/settings-discussion.d.ts.map +1 -0
  109. package/dist/admin/settings-discussion.js +117 -0
  110. package/dist/admin/settings-discussion.js.map +1 -0
  111. package/dist/admin/settings-email.d.ts +54 -0
  112. package/dist/admin/settings-email.d.ts.map +1 -0
  113. package/dist/admin/settings-email.js +189 -0
  114. package/dist/admin/settings-email.js.map +1 -0
  115. package/dist/admin/settings-federation.d.ts +48 -0
  116. package/dist/admin/settings-federation.d.ts.map +1 -0
  117. package/dist/admin/settings-federation.js +123 -0
  118. package/dist/admin/settings-federation.js.map +1 -0
  119. package/dist/admin/settings-general.d.ts +12 -0
  120. package/dist/admin/settings-general.d.ts.map +1 -0
  121. package/dist/admin/settings-general.js +48 -0
  122. package/dist/admin/settings-general.js.map +1 -0
  123. package/dist/admin/settings-page.d.ts +119 -0
  124. package/dist/admin/settings-page.d.ts.map +1 -0
  125. package/dist/admin/settings-page.js +132 -0
  126. package/dist/admin/settings-page.js.map +1 -0
  127. package/dist/admin/settings-pages.d.ts +30 -0
  128. package/dist/admin/settings-pages.d.ts.map +1 -0
  129. package/dist/admin/settings-pages.js +43 -0
  130. package/dist/admin/settings-pages.js.map +1 -0
  131. package/dist/admin/settings-permalinks.d.ts +16 -0
  132. package/dist/admin/settings-permalinks.d.ts.map +1 -0
  133. package/dist/admin/settings-permalinks.js +32 -0
  134. package/dist/admin/settings-permalinks.js.map +1 -0
  135. package/dist/admin/settings-reading.d.ts +34 -0
  136. package/dist/admin/settings-reading.d.ts.map +1 -0
  137. package/dist/admin/settings-reading.js +49 -0
  138. package/dist/admin/settings-reading.js.map +1 -0
  139. package/dist/admin/settings.d.ts +339 -96
  140. package/dist/admin/settings.d.ts.map +1 -1
  141. package/dist/admin/settings.js +600 -308
  142. package/dist/admin/settings.js.map +1 -1
  143. package/dist/admin/store.d.ts +606 -152
  144. package/dist/admin/store.d.ts.map +1 -1
  145. package/dist/admin/store.js +863 -268
  146. package/dist/admin/store.js.map +1 -1
  147. package/dist/admin/taxonomy.d.ts +114 -0
  148. package/dist/admin/taxonomy.d.ts.map +1 -0
  149. package/dist/admin/taxonomy.js +289 -0
  150. package/dist/admin/taxonomy.js.map +1 -0
  151. package/dist/admin/templates.d.ts +46 -14
  152. package/dist/admin/templates.d.ts.map +1 -1
  153. package/dist/admin/templates.js +46 -14
  154. package/dist/admin/templates.js.map +1 -1
  155. package/dist/admin/throttle.d.ts +84 -0
  156. package/dist/admin/throttle.d.ts.map +1 -0
  157. package/dist/admin/throttle.js +143 -0
  158. package/dist/admin/throttle.js.map +1 -0
  159. package/dist/admin/tools.d.ts +111 -0
  160. package/dist/admin/tools.d.ts.map +1 -0
  161. package/dist/admin/tools.js +182 -0
  162. package/dist/admin/tools.js.map +1 -0
  163. package/dist/admin/uploads.d.ts +28 -2
  164. package/dist/admin/uploads.d.ts.map +1 -1
  165. package/dist/admin/uploads.js +43 -4
  166. package/dist/admin/uploads.js.map +1 -1
  167. package/dist/admin/users.d.ts +100 -13
  168. package/dist/admin/users.d.ts.map +1 -1
  169. package/dist/admin/users.js +412 -39
  170. package/dist/admin/users.js.map +1 -1
  171. package/dist/cache.d.ts +141 -0
  172. package/dist/cache.d.ts.map +1 -0
  173. package/dist/cache.js +207 -0
  174. package/dist/cache.js.map +1 -0
  175. package/dist/cli.d.ts +14 -2
  176. package/dist/cli.d.ts.map +1 -1
  177. package/dist/cli.js +429 -21
  178. package/dist/cli.js.map +1 -1
  179. package/dist/comments/akismet.d.ts +130 -0
  180. package/dist/comments/akismet.d.ts.map +1 -0
  181. package/dist/comments/akismet.js +274 -0
  182. package/dist/comments/akismet.js.map +1 -0
  183. package/dist/comments/conversation.d.ts +29 -0
  184. package/dist/comments/conversation.d.ts.map +1 -0
  185. package/dist/comments/conversation.js +60 -0
  186. package/dist/comments/conversation.js.map +1 -0
  187. package/dist/comments/form.d.ts +123 -0
  188. package/dist/comments/form.d.ts.map +1 -0
  189. package/dist/comments/form.js +79 -0
  190. package/dist/comments/form.js.map +1 -0
  191. package/dist/comments/index.d.ts +16 -0
  192. package/dist/comments/index.d.ts.map +1 -0
  193. package/dist/comments/index.js +10 -0
  194. package/dist/comments/index.js.map +1 -0
  195. package/dist/comments/markdown.d.ts +8 -0
  196. package/dist/comments/markdown.d.ts.map +1 -0
  197. package/dist/comments/markdown.js +85 -0
  198. package/dist/comments/markdown.js.map +1 -0
  199. package/dist/comments/moderate.d.ts +71 -0
  200. package/dist/comments/moderate.d.ts.map +1 -0
  201. package/dist/comments/moderate.js +88 -0
  202. package/dist/comments/moderate.js.map +1 -0
  203. package/dist/comments/policy.d.ts +57 -0
  204. package/dist/comments/policy.d.ts.map +1 -0
  205. package/dist/comments/policy.js +80 -0
  206. package/dist/comments/policy.js.map +1 -0
  207. package/dist/comments/records.d.ts +266 -0
  208. package/dist/comments/records.d.ts.map +1 -0
  209. package/dist/comments/records.js +487 -0
  210. package/dist/comments/records.js.map +1 -0
  211. package/dist/comments/routes.d.ts +60 -0
  212. package/dist/comments/routes.d.ts.map +1 -0
  213. package/dist/comments/routes.js +212 -0
  214. package/dist/comments/routes.js.map +1 -0
  215. package/dist/comments/submission.d.ts +297 -0
  216. package/dist/comments/submission.d.ts.map +1 -0
  217. package/dist/comments/submission.js +280 -0
  218. package/dist/comments/submission.js.map +1 -0
  219. package/dist/comments/viewer.d.ts +21 -0
  220. package/dist/comments/viewer.d.ts.map +1 -0
  221. package/dist/comments/viewer.js +45 -0
  222. package/dist/comments/viewer.js.map +1 -0
  223. package/dist/config.d.ts +225 -5
  224. package/dist/config.d.ts.map +1 -1
  225. package/dist/config.js +121 -6
  226. package/dist/config.js.map +1 -1
  227. package/dist/contact/delivery.d.ts +60 -0
  228. package/dist/contact/delivery.d.ts.map +1 -0
  229. package/dist/contact/delivery.js +87 -0
  230. package/dist/contact/delivery.js.map +1 -0
  231. package/dist/contact/form.d.ts +130 -0
  232. package/dist/contact/form.d.ts.map +1 -0
  233. package/dist/contact/form.js +163 -0
  234. package/dist/contact/form.js.map +1 -0
  235. package/dist/contact/index.d.ts +17 -0
  236. package/dist/contact/index.d.ts.map +1 -0
  237. package/dist/contact/index.js +13 -0
  238. package/dist/contact/index.js.map +1 -0
  239. package/dist/contact/records.d.ts +124 -0
  240. package/dist/contact/records.d.ts.map +1 -0
  241. package/dist/contact/records.js +218 -0
  242. package/dist/contact/records.js.map +1 -0
  243. package/dist/contact/routes.d.ts +17 -0
  244. package/dist/contact/routes.d.ts.map +1 -0
  245. package/dist/contact/routes.js +127 -0
  246. package/dist/contact/routes.js.map +1 -0
  247. package/dist/contact/submission.d.ts +103 -0
  248. package/dist/contact/submission.d.ts.map +1 -0
  249. package/dist/contact/submission.js +166 -0
  250. package/dist/contact/submission.js.map +1 -0
  251. package/dist/content/document.d.ts +7 -2
  252. package/dist/content/document.d.ts.map +1 -1
  253. package/dist/content/document.js +1 -0
  254. package/dist/content/document.js.map +1 -1
  255. package/dist/content/index.d.ts +7 -2
  256. package/dist/content/index.d.ts.map +1 -1
  257. package/dist/content/index.js +4 -1
  258. package/dist/content/index.js.map +1 -1
  259. package/dist/content/markdown.d.ts.map +1 -1
  260. package/dist/content/markdown.js +24 -2
  261. package/dist/content/markdown.js.map +1 -1
  262. package/dist/content/parser.d.ts.map +1 -1
  263. package/dist/content/parser.js +11 -4
  264. package/dist/content/parser.js.map +1 -1
  265. package/dist/content/save.d.ts +5 -0
  266. package/dist/content/save.d.ts.map +1 -1
  267. package/dist/content/save.js +44 -1
  268. package/dist/content/save.js.map +1 -1
  269. package/dist/content/schedule.d.ts +125 -0
  270. package/dist/content/schedule.d.ts.map +1 -0
  271. package/dist/content/schedule.js +207 -0
  272. package/dist/content/schedule.js.map +1 -0
  273. package/dist/content/search.d.ts +64 -0
  274. package/dist/content/search.d.ts.map +1 -0
  275. package/dist/content/search.js +136 -0
  276. package/dist/content/search.js.map +1 -0
  277. package/dist/content/store.d.ts +220 -7
  278. package/dist/content/store.d.ts.map +1 -1
  279. package/dist/content/store.js +392 -67
  280. package/dist/content/store.js.map +1 -1
  281. package/dist/content/sync.d.ts +7 -1
  282. package/dist/content/sync.d.ts.map +1 -1
  283. package/dist/content/sync.js +18 -10
  284. package/dist/content/sync.js.map +1 -1
  285. package/dist/content/time.d.ts +56 -0
  286. package/dist/content/time.d.ts.map +1 -0
  287. package/dist/content/time.js +141 -0
  288. package/dist/content/time.js.map +1 -0
  289. package/dist/content/writer.d.ts.map +1 -1
  290. package/dist/content/writer.js +3 -0
  291. package/dist/content/writer.js.map +1 -1
  292. package/dist/env.d.ts +70 -5
  293. package/dist/env.d.ts.map +1 -1
  294. package/dist/federation/actor.d.ts +95 -41
  295. package/dist/federation/actor.d.ts.map +1 -1
  296. package/dist/federation/actor.js +180 -53
  297. package/dist/federation/actor.js.map +1 -1
  298. package/dist/federation/article.d.ts +44 -17
  299. package/dist/federation/article.d.ts.map +1 -1
  300. package/dist/federation/article.js +98 -46
  301. package/dist/federation/article.js.map +1 -1
  302. package/dist/federation/delivery.d.ts +63 -15
  303. package/dist/federation/delivery.d.ts.map +1 -1
  304. package/dist/federation/delivery.js +154 -80
  305. package/dist/federation/delivery.js.map +1 -1
  306. package/dist/federation/federation.d.ts +22 -17
  307. package/dist/federation/federation.d.ts.map +1 -1
  308. package/dist/federation/federation.js +98 -77
  309. package/dist/federation/federation.js.map +1 -1
  310. package/dist/federation/followers.d.ts +3 -2
  311. package/dist/federation/followers.d.ts.map +1 -1
  312. package/dist/federation/followers.js +6 -5
  313. package/dist/federation/followers.js.map +1 -1
  314. package/dist/federation/import-wordpress.d.ts +128 -0
  315. package/dist/federation/import-wordpress.d.ts.map +1 -0
  316. package/dist/federation/import-wordpress.js +426 -0
  317. package/dist/federation/import-wordpress.js.map +1 -0
  318. package/dist/federation/inbox.d.ts +36 -13
  319. package/dist/federation/inbox.d.ts.map +1 -1
  320. package/dist/federation/inbox.js +120 -49
  321. package/dist/federation/inbox.js.map +1 -1
  322. package/dist/federation/index.d.ts +22 -10
  323. package/dist/federation/index.d.ts.map +1 -1
  324. package/dist/federation/index.js +13 -8
  325. package/dist/federation/index.js.map +1 -1
  326. package/dist/federation/keys.d.ts +98 -20
  327. package/dist/federation/keys.d.ts.map +1 -1
  328. package/dist/federation/keys.js +269 -39
  329. package/dist/federation/keys.js.map +1 -1
  330. package/dist/federation/mount.d.ts +46 -10
  331. package/dist/federation/mount.d.ts.map +1 -1
  332. package/dist/federation/mount.js +300 -28
  333. package/dist/federation/mount.js.map +1 -1
  334. package/dist/federation/paths.d.ts +23 -35
  335. package/dist/federation/paths.d.ts.map +1 -1
  336. package/dist/federation/paths.js +26 -39
  337. package/dist/federation/paths.js.map +1 -1
  338. package/dist/federation/records.d.ts +223 -0
  339. package/dist/federation/records.d.ts.map +1 -0
  340. package/dist/federation/records.js +506 -0
  341. package/dist/federation/records.js.map +1 -0
  342. package/dist/federation/relays.d.ts +114 -0
  343. package/dist/federation/relays.d.ts.map +1 -0
  344. package/dist/federation/relays.js +290 -0
  345. package/dist/federation/relays.js.map +1 -0
  346. package/dist/federation/replies.d.ts +80 -0
  347. package/dist/federation/replies.d.ts.map +1 -0
  348. package/dist/federation/replies.js +166 -0
  349. package/dist/federation/replies.js.map +1 -0
  350. package/dist/federation/wordpress.d.ts +131 -0
  351. package/dist/federation/wordpress.d.ts.map +1 -0
  352. package/dist/federation/wordpress.js +341 -0
  353. package/dist/federation/wordpress.js.map +1 -0
  354. package/dist/files/atomic.d.ts +103 -0
  355. package/dist/files/atomic.d.ts.map +1 -0
  356. package/dist/files/atomic.js +150 -0
  357. package/dist/files/atomic.js.map +1 -0
  358. package/dist/files/index.d.ts +3 -0
  359. package/dist/files/index.d.ts.map +1 -0
  360. package/dist/files/index.js +2 -0
  361. package/dist/files/index.js.map +1 -0
  362. package/dist/forms/protection.d.ts +85 -0
  363. package/dist/forms/protection.d.ts.map +1 -0
  364. package/dist/forms/protection.js +116 -0
  365. package/dist/forms/protection.js.map +1 -0
  366. package/dist/images/icons.d.ts +59 -0
  367. package/dist/images/icons.d.ts.map +1 -0
  368. package/dist/images/icons.js +131 -0
  369. package/dist/images/icons.js.map +1 -0
  370. package/dist/images/index.d.ts +7 -0
  371. package/dist/images/index.d.ts.map +1 -0
  372. package/dist/images/index.js +4 -0
  373. package/dist/images/index.js.map +1 -0
  374. package/dist/images/markup.d.ts +47 -0
  375. package/dist/images/markup.d.ts.map +1 -0
  376. package/dist/images/markup.js +175 -0
  377. package/dist/images/markup.js.map +1 -0
  378. package/dist/images/paths.d.ts +34 -0
  379. package/dist/images/paths.d.ts.map +1 -0
  380. package/dist/images/paths.js +41 -0
  381. package/dist/images/paths.js.map +1 -0
  382. package/dist/images/variants.d.ts +104 -0
  383. package/dist/images/variants.d.ts.map +1 -0
  384. package/dist/images/variants.js +320 -0
  385. package/dist/images/variants.js.map +1 -0
  386. package/dist/index.d.ts +123 -19
  387. package/dist/index.d.ts.map +1 -1
  388. package/dist/index.js +344 -25
  389. package/dist/index.js.map +1 -1
  390. package/dist/init.d.ts +18 -0
  391. package/dist/init.d.ts.map +1 -1
  392. package/dist/init.js +34 -3
  393. package/dist/init.js.map +1 -1
  394. package/dist/mail/brevo.d.ts +35 -0
  395. package/dist/mail/brevo.d.ts.map +1 -0
  396. package/dist/mail/brevo.js +85 -0
  397. package/dist/mail/brevo.js.map +1 -0
  398. package/dist/mail/credentials.d.ts +62 -0
  399. package/dist/mail/credentials.d.ts.map +1 -0
  400. package/dist/mail/credentials.js +86 -0
  401. package/dist/mail/credentials.js.map +1 -0
  402. package/dist/mail/index.d.ts +15 -0
  403. package/dist/mail/index.d.ts.map +1 -0
  404. package/dist/mail/index.js +8 -0
  405. package/dist/mail/index.js.map +1 -0
  406. package/dist/mail/memory.d.ts +35 -0
  407. package/dist/mail/memory.d.ts.map +1 -0
  408. package/dist/mail/memory.js +29 -0
  409. package/dist/mail/memory.js.map +1 -0
  410. package/dist/mail/provider.d.ts +80 -0
  411. package/dist/mail/provider.d.ts.map +1 -0
  412. package/dist/mail/provider.js +23 -0
  413. package/dist/mail/provider.js.map +1 -0
  414. package/dist/mail/service.d.ts +156 -0
  415. package/dist/mail/service.d.ts.map +1 -0
  416. package/dist/mail/service.js +265 -0
  417. package/dist/mail/service.js.map +1 -0
  418. package/dist/mail/smtp.d.ts +39 -0
  419. package/dist/mail/smtp.d.ts.map +1 -0
  420. package/dist/mail/smtp.js +58 -0
  421. package/dist/mail/smtp.js.map +1 -0
  422. package/dist/mail/templates.d.ts +91 -0
  423. package/dist/mail/templates.d.ts.map +1 -0
  424. package/dist/mail/templates.js +69 -0
  425. package/dist/mail/templates.js.map +1 -0
  426. package/dist/notifications/comments.d.ts +66 -0
  427. package/dist/notifications/comments.d.ts.map +1 -0
  428. package/dist/notifications/comments.js +151 -0
  429. package/dist/notifications/comments.js.map +1 -0
  430. package/dist/notifications/digest.d.ts +135 -0
  431. package/dist/notifications/digest.d.ts.map +1 -0
  432. package/dist/notifications/digest.js +287 -0
  433. package/dist/notifications/digest.js.map +1 -0
  434. package/dist/notifications/index.d.ts +13 -0
  435. package/dist/notifications/index.d.ts.map +1 -0
  436. package/dist/notifications/index.js +8 -0
  437. package/dist/notifications/index.js.map +1 -0
  438. package/dist/notifications/links.d.ts +60 -0
  439. package/dist/notifications/links.d.ts.map +1 -0
  440. package/dist/notifications/links.js +63 -0
  441. package/dist/notifications/links.js.map +1 -0
  442. package/dist/notifications/optouts.d.ts +48 -0
  443. package/dist/notifications/optouts.d.ts.map +1 -0
  444. package/dist/notifications/optouts.js +93 -0
  445. package/dist/notifications/optouts.js.map +1 -0
  446. package/dist/notifications/preferences.d.ts +158 -0
  447. package/dist/notifications/preferences.d.ts.map +1 -0
  448. package/dist/notifications/preferences.js +195 -0
  449. package/dist/notifications/preferences.js.map +1 -0
  450. package/dist/notifications/routes.d.ts +28 -0
  451. package/dist/notifications/routes.d.ts.map +1 -0
  452. package/dist/notifications/routes.js +184 -0
  453. package/dist/notifications/routes.js.map +1 -0
  454. package/dist/notifications/tokens.d.ts +60 -0
  455. package/dist/notifications/tokens.d.ts.map +1 -0
  456. package/dist/notifications/tokens.js +125 -0
  457. package/dist/notifications/tokens.js.map +1 -0
  458. package/dist/notify.d.ts +84 -0
  459. package/dist/notify.d.ts.map +1 -0
  460. package/dist/notify.js +149 -0
  461. package/dist/notify.js.map +1 -0
  462. package/dist/web/archive.d.ts +49 -0
  463. package/dist/web/archive.d.ts.map +1 -0
  464. package/dist/web/archive.js +59 -0
  465. package/dist/web/archive.js.map +1 -0
  466. package/dist/web/assets.d.ts +6 -5
  467. package/dist/web/assets.d.ts.map +1 -1
  468. package/dist/web/assets.js +5 -7
  469. package/dist/web/assets.js.map +1 -1
  470. package/dist/web/authors.d.ts +143 -0
  471. package/dist/web/authors.d.ts.map +1 -0
  472. package/dist/web/authors.js +178 -0
  473. package/dist/web/authors.js.map +1 -0
  474. package/dist/web/comments.d.ts +60 -0
  475. package/dist/web/comments.d.ts.map +1 -0
  476. package/dist/web/comments.js +207 -0
  477. package/dist/web/comments.js.map +1 -0
  478. package/dist/web/context.d.ts +162 -28
  479. package/dist/web/context.d.ts.map +1 -1
  480. package/dist/web/context.js +123 -26
  481. package/dist/web/context.js.map +1 -1
  482. package/dist/web/conversation.d.ts +209 -0
  483. package/dist/web/conversation.d.ts.map +1 -0
  484. package/dist/web/conversation.js +557 -0
  485. package/dist/web/conversation.js.map +1 -0
  486. package/dist/web/documents.d.ts +36 -6
  487. package/dist/web/documents.d.ts.map +1 -1
  488. package/dist/web/documents.js +52 -10
  489. package/dist/web/documents.js.map +1 -1
  490. package/dist/web/feed-atom.d.ts +22 -0
  491. package/dist/web/feed-atom.d.ts.map +1 -0
  492. package/dist/web/feed-atom.js +83 -0
  493. package/dist/web/feed-atom.js.map +1 -0
  494. package/dist/web/feed-item.d.ts +145 -0
  495. package/dist/web/feed-item.d.ts.map +1 -0
  496. package/dist/web/feed-item.js +120 -0
  497. package/dist/web/feed-item.js.map +1 -0
  498. package/dist/web/feed-json.d.ts +79 -0
  499. package/dist/web/feed-json.d.ts.map +1 -0
  500. package/dist/web/feed-json.js +53 -0
  501. package/dist/web/feed-json.js.map +1 -0
  502. package/dist/web/feed-rss.d.ts +26 -0
  503. package/dist/web/feed-rss.d.ts.map +1 -0
  504. package/dist/web/feed-rss.js +203 -0
  505. package/dist/web/feed-rss.js.map +1 -0
  506. package/dist/web/feed-source.d.ts +244 -0
  507. package/dist/web/feed-source.d.ts.map +1 -0
  508. package/dist/web/feed-source.js +201 -0
  509. package/dist/web/feed-source.js.map +1 -0
  510. package/dist/web/feed-xml.d.ts +63 -0
  511. package/dist/web/feed-xml.d.ts.map +1 -0
  512. package/dist/web/feed-xml.js +116 -0
  513. package/dist/web/feed-xml.js.map +1 -0
  514. package/dist/web/feeds.d.ts +31 -96
  515. package/dist/web/feeds.d.ts.map +1 -1
  516. package/dist/web/feeds.js +94 -198
  517. package/dist/web/feeds.js.map +1 -1
  518. package/dist/web/health.d.ts +31 -0
  519. package/dist/web/health.d.ts.map +1 -0
  520. package/dist/web/health.js +44 -0
  521. package/dist/web/health.js.map +1 -0
  522. package/dist/web/index.d.ts +30 -10
  523. package/dist/web/index.d.ts.map +1 -1
  524. package/dist/web/index.js +18 -7
  525. package/dist/web/index.js.map +1 -1
  526. package/dist/web/navigation.d.ts +195 -0
  527. package/dist/web/navigation.d.ts.map +1 -0
  528. package/dist/web/navigation.js +300 -0
  529. package/dist/web/navigation.js.map +1 -0
  530. package/dist/web/negotiate.d.ts +31 -0
  531. package/dist/web/negotiate.d.ts.map +1 -1
  532. package/dist/web/negotiate.js +31 -11
  533. package/dist/web/negotiate.js.map +1 -1
  534. package/dist/web/recent.d.ts +43 -0
  535. package/dist/web/recent.d.ts.map +1 -0
  536. package/dist/web/recent.js +37 -0
  537. package/dist/web/recent.js.map +1 -0
  538. package/dist/web/render.d.ts +203 -9
  539. package/dist/web/render.d.ts.map +1 -1
  540. package/dist/web/render.js +341 -17
  541. package/dist/web/render.js.map +1 -1
  542. package/dist/web/routes.d.ts +25 -8
  543. package/dist/web/routes.d.ts.map +1 -1
  544. package/dist/web/routes.js +854 -93
  545. package/dist/web/routes.js.map +1 -1
  546. package/dist/web/sanitize.d.ts +19 -0
  547. package/dist/web/sanitize.d.ts.map +1 -0
  548. package/dist/web/sanitize.js +272 -0
  549. package/dist/web/sanitize.js.map +1 -0
  550. package/dist/web/search.d.ts +79 -0
  551. package/dist/web/search.d.ts.map +1 -0
  552. package/dist/web/search.js +94 -0
  553. package/dist/web/search.js.map +1 -0
  554. package/dist/web/sitemap.d.ts +120 -0
  555. package/dist/web/sitemap.d.ts.map +1 -0
  556. package/dist/web/sitemap.js +199 -0
  557. package/dist/web/sitemap.js.map +1 -0
  558. package/dist/web/taxonomy.d.ts +152 -0
  559. package/dist/web/taxonomy.d.ts.map +1 -0
  560. package/dist/web/taxonomy.js +237 -0
  561. package/dist/web/taxonomy.js.map +1 -0
  562. package/dist/web/templates.d.ts +54 -16
  563. package/dist/web/templates.d.ts.map +1 -1
  564. package/dist/web/templates.js +109 -28
  565. package/dist/web/templates.js.map +1 -1
  566. package/dist/web/themes.d.ts +226 -0
  567. package/dist/web/themes.d.ts.map +1 -0
  568. package/dist/web/themes.js +314 -0
  569. package/dist/web/themes.js.map +1 -0
  570. package/dist/webmention/discovery.d.ts +51 -0
  571. package/dist/webmention/discovery.d.ts.map +1 -0
  572. package/dist/webmention/discovery.js +176 -0
  573. package/dist/webmention/discovery.js.map +1 -0
  574. package/dist/webmention/html.d.ts +71 -0
  575. package/dist/webmention/html.d.ts.map +1 -0
  576. package/dist/webmention/html.js +285 -0
  577. package/dist/webmention/html.js.map +1 -0
  578. package/dist/webmention/index.d.ts +12 -0
  579. package/dist/webmention/index.d.ts.map +1 -0
  580. package/dist/webmention/index.js +8 -0
  581. package/dist/webmention/index.js.map +1 -0
  582. package/dist/webmention/links.d.ts +18 -0
  583. package/dist/webmention/links.d.ts.map +1 -0
  584. package/dist/webmention/links.js +64 -0
  585. package/dist/webmention/links.js.map +1 -0
  586. package/dist/webmention/microformats.d.ts +93 -0
  587. package/dist/webmention/microformats.d.ts.map +1 -0
  588. package/dist/webmention/microformats.js +376 -0
  589. package/dist/webmention/microformats.js.map +1 -0
  590. package/dist/webmention/receive.d.ts +141 -0
  591. package/dist/webmention/receive.d.ts.map +1 -0
  592. package/dist/webmention/receive.js +264 -0
  593. package/dist/webmention/receive.js.map +1 -0
  594. package/dist/webmention/routes.d.ts +37 -0
  595. package/dist/webmention/routes.d.ts.map +1 -0
  596. package/dist/webmention/routes.js +75 -0
  597. package/dist/webmention/routes.js.map +1 -0
  598. package/dist/webmention/service.d.ts +94 -0
  599. package/dist/webmention/service.d.ts.map +1 -0
  600. package/dist/webmention/service.js +207 -0
  601. package/dist/webmention/service.js.map +1 -0
  602. package/package.json +11 -6
  603. package/templates/site/content/_data/site.json +8 -0
  604. package/templates/site/content/pages/about.md +7 -0
  605. package/templates/site/content/posts/2026-01-01-hello-world.md +5 -3
  606. package/templates/site/geekity.config.ts +11 -1
  607. package/templates/site/tsconfig.json +1 -1
  608. package/themes/default/README.md +1216 -50
  609. package/themes/default/layouts/404.njk +2 -3
  610. package/themes/default/layouts/author.njk +36 -0
  611. package/themes/default/layouts/base.njk +161 -31
  612. package/themes/default/layouts/category.njk +27 -0
  613. package/themes/default/layouts/front-page.njk +56 -0
  614. package/themes/default/layouts/home.njk +17 -1
  615. package/themes/default/layouts/page.njk +57 -5
  616. package/themes/default/layouts/post.njk +78 -19
  617. package/themes/default/layouts/search.njk +57 -0
  618. package/themes/default/layouts/tag.njk +3 -6
  619. package/themes/default/mail/comment-digest.html.njk +37 -0
  620. package/themes/default/mail/comment-digest.subject.njk +3 -0
  621. package/themes/default/mail/comment-digest.txt.njk +40 -0
  622. package/themes/default/mail/comment-pending.html.njk +27 -0
  623. package/themes/default/mail/comment-pending.subject.njk +2 -0
  624. package/themes/default/mail/comment-pending.txt.njk +24 -0
  625. package/themes/default/mail/comment-reply.html.njk +21 -0
  626. package/themes/default/mail/comment-reply.subject.njk +2 -0
  627. package/themes/default/mail/comment-reply.txt.njk +22 -0
  628. package/themes/default/mail/contact-message.html.njk +24 -0
  629. package/themes/default/mail/contact-message.subject.njk +5 -0
  630. package/themes/default/mail/contact-message.txt.njk +20 -0
  631. package/themes/default/mail/password-changed.html.njk +18 -0
  632. package/themes/default/mail/password-changed.subject.njk +2 -0
  633. package/themes/default/mail/password-changed.txt.njk +17 -0
  634. package/themes/default/mail/password-reset.html.njk +22 -0
  635. package/themes/default/mail/password-reset.subject.njk +2 -0
  636. package/themes/default/mail/password-reset.txt.njk +18 -0
  637. package/themes/default/mail/test.html.njk +14 -0
  638. package/themes/default/mail/test.subject.njk +2 -0
  639. package/themes/default/mail/test.txt.njk +12 -0
  640. package/themes/default/partials/archive.njk +27 -0
  641. package/themes/default/partials/bio.njk +71 -0
  642. package/themes/default/partials/comment-form.njk +137 -0
  643. package/themes/default/partials/contact-form.njk +88 -0
  644. package/themes/default/partials/conversation.njk +139 -0
  645. package/themes/default/partials/feeds.njk +26 -0
  646. package/themes/default/partials/jsonld.njk +120 -0
  647. package/themes/default/partials/menu.njk +32 -0
  648. package/themes/default/partials/pagination.njk +12 -6
  649. package/themes/default/partials/post-list.njk +51 -18
  650. package/themes/default/partials/search-form.njk +22 -0
  651. package/themes/default/partials/tags.njk +26 -5
  652. package/themes/default/static/highlight.js +4 -0
  653. package/themes/default/static/style.css +1142 -194
  654. package/themes/default/theme.json +9 -0
  655. package/admin/layouts/federation.njk +0 -145
  656. package/admin/layouts/login.njk +0 -23
  657. package/admin/layouts/settings.njk +0 -116
  658. package/admin/layouts/setup.njk +0 -27
  659. package/admin/layouts/users.njk +0 -91
  660. /package/admin/{layouts/_flash.njk → components/flash.njk} +0 -0
@@ -1,14 +1,21 @@
1
+ import { isScheduled } from '../content/schedule.js';
1
2
  import { isTrashedPath } from '../content/store.js';
2
- import { postObjectId } from '../federation/paths.js';
3
+ import { absoluteUrl } from './negotiate.js';
3
4
  /**
4
5
  * Whether the public site may show a document.
5
6
  *
6
- * Two things hide one: `draft: true` in the front matter, and living under
7
- * `_trash/`. Both stay indexed so the admin can find them; neither is ever
8
- * served, listed, or fed.
7
+ * Three things hide one: `draft: true` in the front matter, living under
8
+ * `_trash/`, and a date that has not arrived yet. All three stay indexed so
9
+ * the admin can find them; none is ever served, listed, or fed.
10
+ *
11
+ * This is the predicate the index answers in SQL, so anything that has to
12
+ * decide about a single document in hand — a permalink, a View link, the
13
+ * sitemap — asks it here rather than deriving the rule again. The clock
14
+ * defaults to the system one; a caller with a store should pass
15
+ * {@link ContentStore.now} so the answer matches the listings it came from.
9
16
  */
10
- export function isPublicDocument(document) {
11
- return !document.draft && !isTrashedPath(document.path);
17
+ export function isPublicDocument(document, now = new Date()) {
18
+ return !document.draft && !isTrashedPath(document.path) && !isScheduled(document, now);
12
19
  }
13
20
  /**
14
21
  * The document a public URL resolves to, or `undefined`.
@@ -19,21 +26,56 @@ export function isPublicDocument(document) {
19
26
  */
20
27
  export function publicDocumentAt(store, permalink) {
21
28
  const document = store.getByPermalink(permalink);
22
- if (document === undefined || !isPublicDocument(document))
29
+ if (document === undefined || !isPublicDocument(document, store.now()))
23
30
  return undefined;
24
31
  return document;
25
32
  }
33
+ /**
34
+ * A post's ActivityStreams object id: its permalink, absolute on the site's
35
+ * base URL, or the id its file already names.
36
+ *
37
+ * decision-13. A permalink is by name permanent, and the fediverse id is the
38
+ * same promise made to a different audience, so one URL answers both: a
39
+ * browser gets the page and a peer gets the `Article`, by content negotiation.
40
+ * There is no second URL to mint and none to keep in step.
41
+ *
42
+ * A stored `activitypub.id` wins, for the life of the post. That is not a
43
+ * cache: it is what lets a post migrated from WordPress keep the
44
+ * `https://example.com/?p=813` id its followers, its replies and its RSS
45
+ * subscribers already hold (decision-14), so the CMS serves the object there
46
+ * too and names it in every `Update` and `Delete`. A hand-written
47
+ * `activitypub.id` that is not a URL is not an id, and the permalink is used
48
+ * instead.
49
+ *
50
+ * Unlike {@link activityStreamsId} this answers for any post, published or
51
+ * not: a draft that was announced before it was withdrawn still has the name
52
+ * its followers filed it under, and a `Delete` has to say it.
53
+ */
54
+ export function postObjectId(document, baseUrl) {
55
+ const stored = document.activitypub?.id;
56
+ if (stored !== undefined && stored !== '') {
57
+ try {
58
+ return new URL(stored).href;
59
+ }
60
+ catch {
61
+ // Not a URL, so not an id. Fall through to the permalink.
62
+ }
63
+ }
64
+ return absoluteUrl(document.permalink, baseUrl);
65
+ }
26
66
  /**
27
67
  * The ActivityStreams id of a document, or `undefined` when it has none.
28
68
  *
29
69
  * Only a published post federates (doc-4), so only a published post has an id
30
70
  * to advertise. This is what the theme's `<link rel="alternate">` points at,
31
- * and it is deliberately the same string the object dispatcher answers under:
32
- * the page and the object agree about the post's name in the fediverse.
71
+ * what every feed keys the post by (decision-12) and what the permalink
72
+ * answers an ActivityStreams request with: the page, the feed item and the
73
+ * object all agree about the post's name in the fediverse, because after
74
+ * decision-13 they are the same URL.
33
75
  */
34
76
  export function activityStreamsId(document, baseUrl) {
35
77
  if (document.type !== 'post' || !isPublicDocument(document))
36
78
  return undefined;
37
- return postObjectId(document.slug, baseUrl);
79
+ return postObjectId(document, baseUrl);
38
80
  }
39
81
  //# sourceMappingURL=documents.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"documents.js","sourceRoot":"","sources":["../../src/web/documents.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAkB;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAmB,EAAE,SAAiB;IACrE,MAAM,QAAQ,GAAG,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IACjD,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5E,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAkB,EAAE,OAAe;IACnE,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9E,OAAO,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC"}
1
+ {"version":3,"file":"documents.js","sourceRoot":"","sources":["../../src/web/documents.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAkB,EAAE,GAAG,GAAS,IAAI,IAAI,EAAE;IACzE,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AACzF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAmB,EAAE,SAAiB;IACrE,MAAM,QAAQ,GAAG,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IACjD,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;QAAE,OAAO,SAAS,CAAC;IACzF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,YAAY,CAAC,QAAkB,EAAE,OAAe;IAC9D,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;IACxC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,0DAA0D;QAC5D,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAkB,EAAE,OAAe;IACnE,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9E,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { FeedItem } from './feed-item.ts';
2
+ import type { FeedSource } from './feed-source.ts';
3
+ /**
4
+ * Atom 1.0: the feed and its entries, rendered from {@link FeedItem}s.
5
+ *
6
+ * An entry names the post by its object id and lists every term it carries,
7
+ * which is what RSS and JSON Feed do with the same item: decision-12 leaves
8
+ * the three formats nothing to disagree about.
9
+ */
10
+ /** One feed as an Atom 1.0 document. */
11
+ export declare function atomFeed(source: FeedSource): string;
12
+ /**
13
+ * One item as an Atom entry.
14
+ *
15
+ * `<id>` is the object id and the `rel="alternate"` link is the permalink,
16
+ * which are the same URL for every post born on this CMS and differ only for
17
+ * one carrying a stored id. A summary is written whenever there is one, which
18
+ * after decision-12 is every post with a body: Atom's `<summary>` is optional,
19
+ * and an empty one says less than none.
20
+ */
21
+ export declare function atomEntry(item: FeedItem): string[];
22
+ //# sourceMappingURL=feed-atom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed-atom.d.ts","sourceRoot":"","sources":["../../src/web/feed-atom.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAS/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD;;;;;;GAMG;AAEH,wCAAwC;AACxC,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA8BnD;AAeD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CAoBlD"}
@@ -0,0 +1,83 @@
1
+ import { feedItems } from './feed-item.js';
2
+ import { contentTypeOf, EMPTY_FEED_UPDATED, FEED_GENERATOR, FEED_GENERATOR_URI, feedLanguage, notifyServerOf, } from './feed-source.js';
3
+ import { author, element, escapeXml, link, optionalElement, SOURCE_NAMESPACE } from './feed-xml.js';
4
+ import { absoluteUrl, latestModified } from './negotiate.js';
5
+ /**
6
+ * Atom 1.0: the feed and its entries, rendered from {@link FeedItem}s.
7
+ *
8
+ * An entry names the post by its object id and lists every term it carries,
9
+ * which is what RSS and JSON Feed do with the same item: decision-12 leaves
10
+ * the three formats nothing to disagree about.
11
+ */
12
+ /** One feed as an Atom 1.0 document. */
13
+ export function atomFeed(source) {
14
+ const { site, documents, baseUrl } = source;
15
+ const updated = latestModified(documents) ?? EMPTY_FEED_UPDATED;
16
+ const lines = [
17
+ '<?xml version="1.0" encoding="utf-8"?>',
18
+ `<feed xmlns="http://www.w3.org/2005/Atom"`,
19
+ ` xmlns:source="${SOURCE_NAMESPACE}"`,
20
+ ` xml:lang="${escapeXml(feedLanguage(site))}">`,
21
+ element('id', absoluteUrl(source.href, baseUrl)),
22
+ element('title', source.title),
23
+ ...optionalElement('subtitle', site.tagline),
24
+ element('updated', updated.toISOString()),
25
+ link({
26
+ rel: 'self',
27
+ type: contentTypeOf('atom'),
28
+ href: absoluteUrl(source.feedHref, baseUrl),
29
+ }),
30
+ link({ rel: 'alternate', type: 'text/html', href: absoluteUrl(source.href, baseUrl) }),
31
+ ...atomCloud(site),
32
+ ` <generator uri="${escapeXml(FEED_GENERATOR_URI)}">${escapeXml(FEED_GENERATOR)}</generator>`,
33
+ ...author(site.author, 1),
34
+ ];
35
+ for (const item of feedItems(documents, source)) {
36
+ lines.push(...atomEntry(item));
37
+ }
38
+ lines.push('</feed>', '');
39
+ return lines.join('\n');
40
+ }
41
+ /**
42
+ * The notify server as an Atom feed can say it: the `rel="hub"` link WebSub
43
+ * defines, and `<source:cloud>`, which is namespaced and so belongs here as
44
+ * much as in RSS. The legacy `<cloud>` is not: it is an RSS 2.0 element with
45
+ * no namespace, and Atom has nowhere to put it.
46
+ */
47
+ function atomCloud(site) {
48
+ const notify = notifyServerOf(site);
49
+ if (notify === undefined)
50
+ return [];
51
+ return [element('source:cloud', notify.pleaseNotify), link({ rel: 'hub', href: notify.hub })];
52
+ }
53
+ /**
54
+ * One item as an Atom entry.
55
+ *
56
+ * `<id>` is the object id and the `rel="alternate"` link is the permalink,
57
+ * which are the same URL for every post born on this CMS and differ only for
58
+ * one carrying a stored id. A summary is written whenever there is one, which
59
+ * after decision-12 is every post with a body: Atom's `<summary>` is optional,
60
+ * and an empty one says less than none.
61
+ */
62
+ export function atomEntry(item) {
63
+ return [
64
+ ' <entry>',
65
+ element('id', item.id, 2),
66
+ element('title', item.title, 2),
67
+ element('updated', (item.updated ?? EMPTY_FEED_UPDATED).toISOString(), 2),
68
+ ...(item.published === undefined
69
+ ? []
70
+ : [element('published', item.published.toISOString(), 2)]),
71
+ link({ rel: 'alternate', type: 'text/html', href: item.link }, 2),
72
+ ...author(item.author, 2),
73
+ ...item.terms.map((term) => ` <category term="${escapeXml(term)}"/>`),
74
+ ...(item.summary === ''
75
+ ? []
76
+ : [` <summary type="text">${escapeXml(item.summary)}</summary>`]),
77
+ // `type="html"` means the markup is escaped rather than inlined, so a
78
+ // reader that does not parse XHTML still gets the whole post.
79
+ ` <content type="html">${escapeXml(item.html)}</content>`,
80
+ ' </entry>',
81
+ ];
82
+ }
83
+ //# sourceMappingURL=feed-atom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed-atom.js","sourceRoot":"","sources":["../../src/web/feed-atom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ import type { Document } from '../content/document.ts';
2
+ import type { SiteData } from './context.ts';
3
+ /**
4
+ * One post as a feed shows it, in one shape whatever format the feed is.
5
+ *
6
+ * This is the model the three serialisers render. It exists because they used
7
+ * to read the {@link Document} themselves, three times, and disagreed about
8
+ * what they found: RSS keyed an item by the post's ActivityStreams object id
9
+ * where Atom and JSON Feed used the permalink, RSS listed both taxonomies
10
+ * where the others listed tags only, and RSS fell back to an excerpt where the
11
+ * others printed nothing. One derivation, done once per post and site, means
12
+ * there is one answer to each of those questions and one place to change it.
13
+ *
14
+ * decision-12 is what each of those answers is, and the shape here is what
15
+ * makes it unavoidable: there is one {@link FeedItem.id}, one
16
+ * {@link FeedItem.terms} list and one {@link FeedItem.summary}, so a format
17
+ * cannot print a second-best version of any of them. The one pair left,
18
+ * {@link FeedItem.id} beside {@link FeedItem.link}, is two real things: what
19
+ * the post is called and where it is read, which differ only for a post
20
+ * carrying a stored id.
21
+ */
22
+ export interface FeedItem {
23
+ /**
24
+ * The post's name: its ActivityStreams object id, which after decision-13 is
25
+ * the permalink, or the stored id a migrated post carries. decision-12 makes
26
+ * this every feed's key for the post, so all three formats print it: RSS as
27
+ * `guid`, Atom as `<id>` and JSON Feed as `id`.
28
+ */
29
+ id: string;
30
+ /**
31
+ * Where the post is read: its permalink, absolute on the site's base URL.
32
+ * The same in every format — RSS's `link`, Atom's `rel="alternate"` and JSON
33
+ * Feed's `url` — and equal to {@link FeedItem.id} unless the post carries a
34
+ * stored one.
35
+ */
36
+ link: string;
37
+ /** Display title. */
38
+ title: string;
39
+ /** When it was published, if it carries a date that parses. */
40
+ published?: Date | undefined;
41
+ /** When it last changed: its `updated`, else its date. */
42
+ updated?: Date | undefined;
43
+ /** The post's own author, when it names one. Atom and JSON Feed print this. */
44
+ author?: string | undefined;
45
+ /**
46
+ * Who a feed credits: the post's own author, else the site's. RSS's
47
+ * `dc:creator` prints it, because an RSS item has nowhere else to say it.
48
+ */
49
+ creator?: string | undefined;
50
+ /**
51
+ * What the post is filed under and tagged with, categories first and each in
52
+ * file order, as one list.
53
+ *
54
+ * One list rather than two because no feed format distinguishes them: RSS has
55
+ * a single `<category>`, Atom a single `<category term>` and JSON Feed a
56
+ * single `tags`, which is exactly how WordPress publishes both taxonomies
57
+ * too. decision-12 says every format lists every term, and a model that
58
+ * cannot say which vocabulary a term came from is a model no format can
59
+ * quietly list half of.
60
+ */
61
+ terms: readonly string[];
62
+ /**
63
+ * What every format prints as the summary: the description the author wrote,
64
+ * else an excerpt of the rendered body. Never the whole post — the content is
65
+ * where that goes — and empty only for a post with nothing to summarise,
66
+ * which is the one case a format leaves the element out.
67
+ */
68
+ summary: string;
69
+ /** The rendered body. */
70
+ html: string;
71
+ /** The Markdown the body was written from, for `source:markdown`. */
72
+ markdown: string;
73
+ /**
74
+ * Where this item's comments are, and how many there are, or `undefined`
75
+ * when the feed did not resolve the counts. A feed whose builder did not
76
+ * would otherwise publish "0 comments" about a post with plenty.
77
+ */
78
+ comments?: FeedItemComments | undefined;
79
+ }
80
+ /**
81
+ * Which revision of the item's serialisation a feed's validator is keyed by.
82
+ *
83
+ * A feed's ETag is a hash of the documents and the site's metadata, because
84
+ * those are what usually move it. The rules for turning a document into an item
85
+ * are not in that hash, so a release that changes them — this one, which
86
+ * changes every RSS `guid`, both the other formats' ids, the terms they list
87
+ * and their summaries — would leave the validator where it was, and a reader
88
+ * polling with `If-None-Match` would be handed a 304 that hides the new bytes.
89
+ *
90
+ * Bumping this moves every post feed's ETag exactly once, at the upgrade, and
91
+ * never again until the next such change. The comments feeds do not carry it:
92
+ * a comment is not a {@link FeedItem} and its bytes are untouched.
93
+ */
94
+ export declare const FEED_ITEM_REVISION = 2;
95
+ /** Where one item's comments are, counted. */
96
+ export interface FeedItemComments {
97
+ /** The page a person reads them on. */
98
+ page: string;
99
+ /** The feed a reader polls for them. */
100
+ feed: string;
101
+ /** How many there are. */
102
+ count: number;
103
+ }
104
+ /** What an item needs to know about the feed it is part of. */
105
+ export interface FeedItemContext {
106
+ /** Site-wide data, for the author a post does not name. */
107
+ site: SiteData;
108
+ /** The site's public origin, for absolute ids and links. */
109
+ baseUrl: string;
110
+ /** How many replies each document has, by permalink. See {@link FeedItem.comments}. */
111
+ commentCounts?: ReadonlyMap<string, number> | undefined;
112
+ }
113
+ /**
114
+ * One document as the item every format renders.
115
+ *
116
+ * The only reading of a {@link Document} a feed does: after this, a serialiser
117
+ * sees an item and nothing else, so two formats cannot quietly disagree about
118
+ * what a post's summary or its name is.
119
+ */
120
+ export declare function feedItem(document: Document, context: FeedItemContext): FeedItem;
121
+ /** One item per document, in the order the feed was given them. */
122
+ export declare function feedItems(documents: readonly Document[], context: FeedItemContext): readonly FeedItem[];
123
+ /**
124
+ * How many words of the rendered text an excerpt keeps when a post carries no
125
+ * `description`. WordPress's own excerpt length, so a migrated site's feed
126
+ * reads the same.
127
+ */
128
+ export declare const EXCERPT_WORDS = 55;
129
+ /**
130
+ * The plain-text summary a feed carries for a post.
131
+ *
132
+ * The `description` front matter when the post has one — it is what the author
133
+ * wrote for exactly this — and otherwise the first paragraph of the rendered
134
+ * body, stripped to text and cut where WordPress cuts an excerpt. Never the
135
+ * whole post: the content element is where the whole post goes, and a reader
136
+ * that shows both should have something to choose between.
137
+ */
138
+ export declare function feedExcerpt(document: Document): string;
139
+ /**
140
+ * The first paragraph of some HTML as plain text, cut where WordPress cuts an
141
+ * excerpt. What a post falls back to when it carries no `description`, and
142
+ * what a comment — which never carries one — always uses.
143
+ */
144
+ export declare function excerptFromHtml(html: string): string;
145
+ //# sourceMappingURL=feed-item.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed-item.d.ts","sourceRoot":"","sources":["../../src/web/feed-item.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAK7C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;OAKG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IAC7B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IAC3B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;;;;;;;;OAUG;IACH,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACzC;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,IAAI,EAAE,QAAQ,CAAC;IACf,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CACzD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,GAAG,QAAQ,CAsC/E;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CACvB,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,EAAE,eAAe,GACvB,SAAS,QAAQ,EAAE,CAErB;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAGtD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAapD"}
@@ -0,0 +1,120 @@
1
+ import { activityStreamsId } from './documents.js';
2
+ import { feedPathUnder } from './feed-source.js';
3
+ import { absoluteUrl, lastModifiedOf } from './negotiate.js';
4
+ /**
5
+ * Which revision of the item's serialisation a feed's validator is keyed by.
6
+ *
7
+ * A feed's ETag is a hash of the documents and the site's metadata, because
8
+ * those are what usually move it. The rules for turning a document into an item
9
+ * are not in that hash, so a release that changes them — this one, which
10
+ * changes every RSS `guid`, both the other formats' ids, the terms they list
11
+ * and their summaries — would leave the validator where it was, and a reader
12
+ * polling with `If-None-Match` would be handed a 304 that hides the new bytes.
13
+ *
14
+ * Bumping this moves every post feed's ETag exactly once, at the upgrade, and
15
+ * never again until the next such change. The comments feeds do not carry it:
16
+ * a comment is not a {@link FeedItem} and its bytes are untouched.
17
+ */
18
+ export const FEED_ITEM_REVISION = 2;
19
+ /**
20
+ * One document as the item every format renders.
21
+ *
22
+ * The only reading of a {@link Document} a feed does: after this, a serialiser
23
+ * sees an item and nothing else, so two formats cannot quietly disagree about
24
+ * what a post's summary or its name is.
25
+ */
26
+ export function feedItem(document, context) {
27
+ const { baseUrl } = context;
28
+ const link = absoluteUrl(document.permalink, baseUrl);
29
+ const published = document.date === undefined ? undefined : new Date(document.date);
30
+ const item = {
31
+ // A page or a draft has no ActivityStreams id to advertise, and falls back
32
+ // to its address. A feed only ever carries published posts, so in practice
33
+ // this is the object id; the fallback is what keeps the shape total.
34
+ id: activityStreamsId(document, baseUrl) ?? link,
35
+ link,
36
+ title: document.title,
37
+ terms: [...document.categories, ...document.tags],
38
+ summary: feedExcerpt(document),
39
+ html: document.html,
40
+ markdown: document.body,
41
+ };
42
+ if (published !== undefined && !Number.isNaN(published.getTime()))
43
+ item.published = published;
44
+ const updated = lastModifiedOf(document);
45
+ if (updated !== undefined)
46
+ item.updated = updated;
47
+ if (document.author !== undefined)
48
+ item.author = document.author;
49
+ const creator = document.author ?? context.site.author;
50
+ if (creator !== undefined && creator !== '')
51
+ item.creator = creator;
52
+ const counts = context.commentCounts;
53
+ if (counts !== undefined) {
54
+ item.comments = {
55
+ page: `${link}#comments`,
56
+ feed: absoluteUrl(feedPathUnder(document.permalink, 'rss'), baseUrl),
57
+ count: counts.get(document.permalink) ?? 0,
58
+ };
59
+ }
60
+ return item;
61
+ }
62
+ /** One item per document, in the order the feed was given them. */
63
+ export function feedItems(documents, context) {
64
+ return documents.map((document) => feedItem(document, context));
65
+ }
66
+ /**
67
+ * How many words of the rendered text an excerpt keeps when a post carries no
68
+ * `description`. WordPress's own excerpt length, so a migrated site's feed
69
+ * reads the same.
70
+ */
71
+ export const EXCERPT_WORDS = 55;
72
+ /**
73
+ * The plain-text summary a feed carries for a post.
74
+ *
75
+ * The `description` front matter when the post has one — it is what the author
76
+ * wrote for exactly this — and otherwise the first paragraph of the rendered
77
+ * body, stripped to text and cut where WordPress cuts an excerpt. Never the
78
+ * whole post: the content element is where the whole post goes, and a reader
79
+ * that shows both should have something to choose between.
80
+ */
81
+ export function feedExcerpt(document) {
82
+ if (document.description !== undefined)
83
+ return document.description;
84
+ return excerptFromHtml(document.html);
85
+ }
86
+ /**
87
+ * The first paragraph of some HTML as plain text, cut where WordPress cuts an
88
+ * excerpt. What a post falls back to when it carries no `description`, and
89
+ * what a comment — which never carries one — always uses.
90
+ */
91
+ export function excerptFromHtml(html) {
92
+ // Tags are dropped rather than replaced by a space: the markup inside a
93
+ // paragraph is inline, and "now</span>," is one word followed by a comma.
94
+ // What separates the words is the whitespace the renderer already put
95
+ // between its block tags, which the collapse below turns into single spaces.
96
+ const paragraph = /<p[^>]*>([\s\S]*?)<\/p>/i.exec(html)?.[1] ?? html;
97
+ const text = decodeHtmlText(paragraph.replace(/<[^>]*>/g, ''))
98
+ .replace(/\s+/g, ' ')
99
+ .trim();
100
+ if (text === '')
101
+ return '';
102
+ const words = text.split(' ');
103
+ return words.length <= EXCERPT_WORDS ? text : `${words.slice(0, EXCERPT_WORDS).join(' ')} …`;
104
+ }
105
+ /**
106
+ * The five named entities the Markdown renderer emits, resolved.
107
+ *
108
+ * An excerpt is text rather than markup, so `&amp;` in the rendered HTML has
109
+ * to become `&` here before the XML escaping puts it back: leaving it would
110
+ * publish a summary reading "Fish &amp;amp; chips".
111
+ */
112
+ function decodeHtmlText(value) {
113
+ return value
114
+ .replace(/&lt;/g, '<')
115
+ .replace(/&gt;/g, '>')
116
+ .replace(/&quot;/g, '"')
117
+ .replace(/&#(?:39|x27);/g, "'")
118
+ .replace(/&amp;/g, '&');
119
+ }
120
+ //# sourceMappingURL=feed-item.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed-item.js","sourceRoot":"","sources":["../../src/web/feed-item.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import type { FeedItem } from './feed-item.ts';
2
+ import type { FeedSource } from './feed-source.ts';
3
+ /**
4
+ * JSON Feed 1.1: the document, its items, and the vocabulary they are spelled
5
+ * in.
6
+ *
7
+ * An item is keyed by the post's object id and lists every term it carries,
8
+ * which is what the two XML formats do with the same item: decision-12 leaves
9
+ * the three formats nothing to disagree about.
10
+ */
11
+ /** The `version` every JSON Feed this CMS writes declares. */
12
+ export declare const JSON_FEED_VERSION = "https://jsonfeed.org/version/1.1";
13
+ /** What JSON Feed 1.1 calls the protocol the notify server's hub speaks. */
14
+ export declare const JSON_FEED_HUB_TYPE = "WebSub";
15
+ /** A JSON Feed 1.1 document. */
16
+ export interface JsonFeed {
17
+ /** {@link JSON_FEED_VERSION}. */
18
+ version: string;
19
+ /** The feed's name. */
20
+ title: string;
21
+ /** The HTML page this feed syndicates. */
22
+ home_page_url: string;
23
+ /** Where this feed itself lives. */
24
+ feed_url: string;
25
+ /** The site's tagline, when it has one. */
26
+ description?: string;
27
+ /** Site-level authors, when the site names one. */
28
+ authors?: JsonFeedAuthor[];
29
+ /**
30
+ * Where a subscriber can be told the feed changed rather than polling it.
31
+ * One entry, the site's notify server, when it names one.
32
+ */
33
+ hubs?: JsonFeedHub[];
34
+ /** The entries, newest first. */
35
+ items: JsonFeedItem[];
36
+ }
37
+ /**
38
+ * A real-time endpoint, as JSON Feed 1.1 models one. `type` names the protocol
39
+ * rather than a media type, and `WebSub` is the one this CMS's server speaks.
40
+ */
41
+ export interface JsonFeedHub {
42
+ /** The protocol: `WebSub`. */
43
+ type: string;
44
+ /** The hub's URL. */
45
+ url: string;
46
+ }
47
+ /** An author, as JSON Feed 1.1 models one. */
48
+ export interface JsonFeedAuthor {
49
+ name: string;
50
+ }
51
+ /** One entry of a {@link JsonFeed}. */
52
+ export interface JsonFeedItem {
53
+ /**
54
+ * Permanent identifier: the post's ActivityStreams object id, which is its
55
+ * permalink unless the post carries a stored one.
56
+ */
57
+ id: string;
58
+ /** Where the entry can be read: the permalink. */
59
+ url: string;
60
+ /** Display title. */
61
+ title: string;
62
+ /** The rendered body. */
63
+ content_html: string;
64
+ /** The post's summary, unless there is nothing to summarise. */
65
+ summary?: string;
66
+ /** Publish date, RFC 3339. */
67
+ date_published?: string;
68
+ /** Last modification date, RFC 3339. */
69
+ date_modified?: string;
70
+ /** The post's terms — its categories and then its tags, in file order. */
71
+ tags?: string[];
72
+ /** The post's own author, when it names one. */
73
+ authors?: JsonFeedAuthor[];
74
+ }
75
+ /** One feed as a JSON Feed 1.1 document. */
76
+ export declare function jsonFeed(source: FeedSource): JsonFeed;
77
+ /** One item as a JSON Feed item. */
78
+ export declare function jsonFeedItem(item: FeedItem): JsonFeedItem;
79
+ //# sourceMappingURL=feed-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed-json.d.ts","sourceRoot":"","sources":["../../src/web/feed-json.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD;;;;;;;GAOG;AAEH,8DAA8D;AAC9D,eAAO,MAAM,iBAAiB,qCAAqC,CAAC;AAEpE,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAE3C,gCAAgC;AAChC,MAAM,WAAW,QAAQ;IACvB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;IACrB,iCAAiC;IACjC,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,8CAA8C;AAC9C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,uCAAuC;AACvC,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,gDAAgD;IAChD,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED,4CAA4C;AAC5C,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,QAAQ,CAcrD;AAED,oCAAoC;AACpC,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,YAAY,CAiBzD"}
@@ -0,0 +1,53 @@
1
+ import { feedItems } from './feed-item.js';
2
+ import { notifyServerOf } from './feed-source.js';
3
+ import { absoluteUrl } from './negotiate.js';
4
+ /**
5
+ * JSON Feed 1.1: the document, its items, and the vocabulary they are spelled
6
+ * in.
7
+ *
8
+ * An item is keyed by the post's object id and lists every term it carries,
9
+ * which is what the two XML formats do with the same item: decision-12 leaves
10
+ * the three formats nothing to disagree about.
11
+ */
12
+ /** The `version` every JSON Feed this CMS writes declares. */
13
+ export const JSON_FEED_VERSION = 'https://jsonfeed.org/version/1.1';
14
+ /** What JSON Feed 1.1 calls the protocol the notify server's hub speaks. */
15
+ export const JSON_FEED_HUB_TYPE = 'WebSub';
16
+ /** One feed as a JSON Feed 1.1 document. */
17
+ export function jsonFeed(source) {
18
+ const { site, baseUrl } = source;
19
+ const notify = notifyServerOf(site);
20
+ return {
21
+ version: JSON_FEED_VERSION,
22
+ title: source.title,
23
+ home_page_url: absoluteUrl(source.href, baseUrl),
24
+ feed_url: absoluteUrl(source.feedHref, baseUrl),
25
+ ...(site.tagline === undefined ? {} : { description: site.tagline }),
26
+ ...(site.author === undefined ? {} : { authors: [{ name: site.author }] }),
27
+ ...(notify === undefined ? {} : { hubs: [{ type: JSON_FEED_HUB_TYPE, url: notify.hub }] }),
28
+ items: feedItems(source.documents, source).map(jsonFeedItem),
29
+ };
30
+ }
31
+ /** One item as a JSON Feed item. */
32
+ export function jsonFeedItem(item) {
33
+ const entry = {
34
+ id: item.id,
35
+ url: item.link,
36
+ title: item.title,
37
+ content_html: item.html,
38
+ };
39
+ // A key with nothing behind it is left out rather than sent empty: a JSON
40
+ // Feed reader treats absent and empty differently.
41
+ if (item.summary !== '')
42
+ entry.summary = item.summary;
43
+ if (item.published !== undefined)
44
+ entry.date_published = item.published.toISOString();
45
+ if (item.updated !== undefined)
46
+ entry.date_modified = item.updated.toISOString();
47
+ if (item.terms.length > 0)
48
+ entry.tags = [...item.terms];
49
+ if (item.author !== undefined)
50
+ entry.authors = [{ name: item.author }];
51
+ return entry;
52
+ }
53
+ //# sourceMappingURL=feed-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed-json.js","sourceRoot":"","sources":["../../src/web/feed-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;;;;GAOG;AAEH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,iBAAiB,GAAG,kCAAkC,CAAC;AAEpE,4EAA4E;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAkE3C,4CAA4C;AAC5C,MAAM,UAAU,QAAQ,CAAC,MAAkB;IACzC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IACjC,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAEpC,OAAO;QACL,OAAO,EAAE,iBAAiB;QAC1B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC;QAChD,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC;QAC/C,GAAG,CAAC,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QACpE,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;QAC1F,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;KAC7D,CAAC;AACJ,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,MAAM,KAAK,GAAiB;QAC1B,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,GAAG,EAAE,IAAI,CAAC,IAAI;QACd,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,YAAY,EAAE,IAAI,CAAC,IAAI;KACxB,CAAC;IAEF,0EAA0E;IAC1E,mDAAmD;IACnD,IAAI,IAAI,CAAC,OAAO,KAAK,EAAE;QAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IACtD,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;QAAE,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IACtF,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACjF,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IACxD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvE,OAAO,KAAK,CAAC;AACf,CAAC"}