@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
@@ -0,0 +1,506 @@
1
+ import { readdirSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { readFileIfPresentSync, withFileLock, writeFileAtomicallySync } from '../files/atomic.js';
4
+ import { uriOf } from './replies.js';
5
+ /**
6
+ * The two things an ActivityPub site cannot regenerate, as files it publishes.
7
+ *
8
+ * decision-9 makes the filesystem the source of truth for everything durable,
9
+ * and for federation that is the followers and the log of what the inbox was
10
+ * told. Both live under `content/_data/federation/`, which puts them in git
11
+ * beside the posts, hands them to an Eleventy build of the same directory as
12
+ * `federation.followers` and `federation.inbox`, and leaves SQLite holding
13
+ * nothing but an index of them — one that is rebuilt from these files on every
14
+ * boot and may be deleted at rest.
15
+ *
16
+ * Two rules make that safe, and both live here so no handler has to remember
17
+ * them:
18
+ *
19
+ * - **The file first, the index inside the same step.** Every writer takes
20
+ * {@link withFileLock} over the file it is about to change and writes the
21
+ * index before it lets go, so a follow and an unfollow arriving together
22
+ * cannot leave the index saying something the file does not. SQLite's
23
+ * transactions used to cover this and cover nothing here any more.
24
+ * - **The index is derived, never told.** A row is built from a line of the
25
+ * log by {@link inboxRowFrom} whether it is being written for the first time
26
+ * or rebuilt at boot, so a rebuilt index cannot differ from the live one.
27
+ */
28
+ /** Where the federation files live, relative to the content directory. */
29
+ export const FEDERATION_DATA_DIRECTORY = '_data/federation';
30
+ /** What a user's followers file is called, inside their own directory. */
31
+ export const FOLLOWERS_FILE = 'followers.json';
32
+ /** The directory of monthly inbox logs, relative to the content directory. */
33
+ export const INBOX_DIRECTORY = `${FEDERATION_DATA_DIRECTORY}/inbox`;
34
+ /**
35
+ * The directory one user's federation files live in, relative to the content
36
+ * directory: `_data/federation/{username}`.
37
+ *
38
+ * decision-14 makes every user an actor, and an actor's followers are its own
39
+ * — an actor that was followed and forgotten simply stops hearing from the
40
+ * site — so the one file doc-4 had becomes one per user. The name is the
41
+ * username verbatim, because it is also the name in the actor's id and in the
42
+ * key files, and a directory nobody can match to a person would be worse than
43
+ * one with an unusual name in it.
44
+ *
45
+ * `inbox` is not a username: it is where the shared log lives, and
46
+ * `web/authors.ts` reserves the path for exactly that reason. A name that
47
+ * could climb out of the directory is refused rather than sanitised, because
48
+ * sanitising two different usernames into one directory would merge two
49
+ * people's followers.
50
+ */
51
+ export function userDirectory(username) {
52
+ if (username === '' || username === '.' || username === '..' || /[/\\]/.test(username)) {
53
+ throw new Error(`"${username}" cannot name a federation directory.`);
54
+ }
55
+ return `${FEDERATION_DATA_DIRECTORY}/${username}`;
56
+ }
57
+ /** The absolute path of one user's `content/_data/federation/{username}/followers.json`. */
58
+ export function followersFile(contentDir, username) {
59
+ return path.join(contentDir, ...userDirectory(username).split('/'), FOLLOWERS_FILE);
60
+ }
61
+ /**
62
+ * Every user the content directory holds federation files for, sorted.
63
+ *
64
+ * Read from the directory rather than from `data/users.json`, because
65
+ * decision-9 makes the files the truth: a rebuilt database has to put back
66
+ * exactly what is on disk, including the followers of a user whose account was
67
+ * removed — deleting the account is not the same act as unfollowing everybody
68
+ * on their behalf, and only one of the two can be taken back.
69
+ */
70
+ export function federatedUsernames(contentDir) {
71
+ let entries;
72
+ try {
73
+ entries = readdirSync(path.join(contentDir, ...FEDERATION_DATA_DIRECTORY.split('/')), {
74
+ withFileTypes: true,
75
+ });
76
+ }
77
+ catch {
78
+ // No directory is a site nobody has federated with yet.
79
+ return [];
80
+ }
81
+ return entries
82
+ .filter((entry) => entry.isDirectory() && entry.name !== 'inbox')
83
+ .map((entry) => entry.name)
84
+ .sort();
85
+ }
86
+ /** The absolute path of one site's `content/_data/federation/inbox`. */
87
+ export function inboxDirectory(contentDir) {
88
+ return path.join(contentDir, ...INBOX_DIRECTORY.split('/'));
89
+ }
90
+ /**
91
+ * The month an instant falls in, `yyyy-mm`, in UTC.
92
+ *
93
+ * UTC rather than the site's zone because the log is a record of what a server
94
+ * was told, not of a site's day: the name of a file that has been written must
95
+ * not move when somebody changes the `timezone` setting.
96
+ */
97
+ export function inboxMonth(instant) {
98
+ const at = new Date(instant);
99
+ if (Number.isNaN(at.getTime()))
100
+ return instant.slice(0, 7);
101
+ return `${String(at.getUTCFullYear()).padStart(4, '0')}-${String(at.getUTCMonth() + 1).padStart(2, '0')}`;
102
+ }
103
+ /** The log file an activity that arrived at this instant belongs in. */
104
+ export function inboxFile(contentDir, instant) {
105
+ return path.join(inboxDirectory(contentDir), `${inboxMonth(instant)}.jsonl`);
106
+ }
107
+ /**
108
+ * One user's followers, as their `followers.json` says them, oldest follow
109
+ * first.
110
+ *
111
+ * A missing file is an empty list, which is what a site nobody has followed
112
+ * yet has. Anything else that is not a list of deliverable followers throws,
113
+ * naming the file: this is read at boot to build the index, and a damaged file
114
+ * read as "no followers" would quietly unfollow everybody — the one thing
115
+ * doc-4 says an ActivityPub site can never take back.
116
+ */
117
+ export function readFollowers(contentDir, username) {
118
+ const file = followersFile(contentDir, username);
119
+ const source = readFileIfPresentSync(file);
120
+ if (source === undefined)
121
+ return [];
122
+ return parseFollowers(source, file, username);
123
+ }
124
+ /**
125
+ * Record a follow of one user: append the follower to that user's file, or
126
+ * refresh the profile of one already there, and put the same thing in the
127
+ * index.
128
+ *
129
+ * Following twice is not two followers. The file is keyed by actor id exactly
130
+ * as the index is, and an actor already in it keeps its place and its original
131
+ * follow time — a repeated or redelivered `Follow` refreshes the name and the
132
+ * avatar and nothing else.
133
+ */
134
+ export async function addFollower(records, username, follower) {
135
+ const { admin, contentDir } = records;
136
+ const file = followersFile(contentDir, username);
137
+ return await withFileLock(file, () => {
138
+ const held = readFollowers(contentDir, username);
139
+ const existing = held.find((entry) => entry.actorId === follower.actorId);
140
+ const stored = {
141
+ username,
142
+ actorId: follower.actorId,
143
+ inboxId: follower.inboxId,
144
+ sharedInboxId: follower.sharedInboxId,
145
+ handle: follower.handle,
146
+ name: follower.name,
147
+ iconUrl: follower.iconUrl,
148
+ url: follower.url,
149
+ // The file remembers when the follow began, so a profile refresh cannot
150
+ // move an actor to the top of the list it has been on for a year.
151
+ followedAt: existing?.followedAt ?? follower.followedAt ?? new Date().toISOString(),
152
+ };
153
+ const next = existing === undefined
154
+ ? [...held, stored]
155
+ : held.map((entry) => (entry.actorId === stored.actorId ? stored : entry));
156
+ writeFileAtomicallySync(file, followersJson(next));
157
+ admin.putFollower(stored);
158
+ return stored;
159
+ });
160
+ }
161
+ /**
162
+ * Forget one of a user's followers: an `Undo(Follow)`, or an actor deleting
163
+ * itself.
164
+ *
165
+ * Returns whether anything was there to forget. The index is emptied of the
166
+ * actor whether or not the file held it, so a row left over from a file that
167
+ * was edited by hand cannot go on being delivered to.
168
+ */
169
+ export async function removeFollower(records, username, actorId) {
170
+ const { admin, contentDir } = records;
171
+ const file = followersFile(contentDir, username);
172
+ return await withFileLock(file, () => {
173
+ const held = readFollowers(contentDir, username);
174
+ const next = held.filter((entry) => entry.actorId !== actorId);
175
+ if (next.length !== held.length)
176
+ writeFileAtomicallySync(file, followersJson(next));
177
+ const indexed = admin.deleteFollower(username, actorId);
178
+ return next.length !== held.length || indexed;
179
+ });
180
+ }
181
+ /**
182
+ * The whole inbox log, oldest month first and, within a month, in the order
183
+ * the activities arrived.
184
+ *
185
+ * Every month file under `content/_data/federation/inbox` is read; a file or a
186
+ * line that will not parse throws, naming the file. Fedify answers a throwing
187
+ * dispatcher by swallowing the throw, so a log this cannot read has to stop
188
+ * the boot rather than wait to be noticed through a request.
189
+ */
190
+ export function readInboxLog(contentDir) {
191
+ const lines = [];
192
+ for (const file of inboxFiles(contentDir))
193
+ lines.push(...readInboxFile(file));
194
+ return lines;
195
+ }
196
+ /**
197
+ * Record one inbound activity: append it to the month's log and index it.
198
+ *
199
+ * `json` is the activity as compacted JSON-LD, which is what the handler has
200
+ * and what doc-4 says to keep whole — nothing is picked out of it here beyond
201
+ * the columns the index pages and counts by, because what a later phase will
202
+ * want out of an activity is not knowable from here.
203
+ *
204
+ * An activity with no actor is dropped and nothing is written: Fedify has
205
+ * already refused anything whose signature does not match its actor, so one
206
+ * without an actor is malformed rather than anonymous. A redelivery of an
207
+ * activity the month already holds replaces its line where it stands, which is
208
+ * what the index's unique key on the activity id does to the row.
209
+ */
210
+ export async function appendInboxActivity(records, json, options = {}) {
211
+ const { admin, contentDir } = records;
212
+ const receivedAt = options.receivedAt ?? new Date().toISOString();
213
+ const line = { receivedAt, recipient: options.recipient ?? null, json };
214
+ const row = inboxRowFrom(line);
215
+ if (row === undefined)
216
+ return undefined;
217
+ const file = inboxFile(contentDir, receivedAt);
218
+ return await withFileLock(file, () => {
219
+ const held = readInboxFile(file);
220
+ const at = row.activityId === null ? -1 : held.findIndex(sameActivity(row.activityId));
221
+ const next = at === -1 ? [...held, line] : held.with(at, line);
222
+ writeFileAtomicallySync(file, inboxJsonl(next));
223
+ return admin.logInboxActivity(row);
224
+ });
225
+ }
226
+ /**
227
+ * One line of the log as the index row it makes, or `undefined` when it is not
228
+ * an activity the log keeps.
229
+ *
230
+ * This is the only place a row is derived, and the live append and the boot
231
+ * rebuild both go through it, so a row rebuilt from the log cannot say
232
+ * something different from the row the activity made when it arrived. Every
233
+ * column is read out of the JSON, so the file really is the whole story;
234
+ * `inReplyTo` is the one the store derives for itself, from this same JSON and
235
+ * by the same rule.
236
+ */
237
+ export function inboxRowFrom(line) {
238
+ let parsed;
239
+ try {
240
+ parsed = JSON.parse(line.json);
241
+ }
242
+ catch {
243
+ return undefined;
244
+ }
245
+ if (!isRecord(parsed))
246
+ return undefined;
247
+ const actorId = uriOf(parsed['actor']);
248
+ if (actorId === null)
249
+ return undefined;
250
+ return {
251
+ activityId: uriOf(parsed['id']),
252
+ activityType: activityTypeOf(parsed['type']),
253
+ actorId,
254
+ objectId: uriOf(parsed['object']),
255
+ recipient: line.recipient,
256
+ receivedAt: line.receivedAt,
257
+ json: line.json,
258
+ };
259
+ }
260
+ /**
261
+ * Rebuild the followers and inbox indexes from the files.
262
+ *
263
+ * This is what makes `data/geekity.db` disposable for federation (decision-9):
264
+ * the two tables hold nothing but what these files say, so every boot throws
265
+ * away what they hold and reads them again. That is also what makes editing
266
+ * `followers.json` by hand and restarting a supported thing to do, and why a
267
+ * database deleted at rest costs a site nothing.
268
+ *
269
+ * Exported so `geekity rebuild` can call the very function boot calls. It is
270
+ * synchronous because both callers are, and it reads before it writes: a file
271
+ * that will not parse throws with the file named and leaves the index exactly
272
+ * as it was, rather than emptying it and then failing.
273
+ */
274
+ export function rebuildFederationIndexes(records) {
275
+ const { admin, contentDir } = records;
276
+ const followers = federatedUsernames(contentDir).flatMap((username) => readFollowers(contentDir, username));
277
+ const activities = [];
278
+ for (const line of readInboxLog(contentDir)) {
279
+ const row = inboxRowFrom(line);
280
+ if (row !== undefined)
281
+ activities.push(row);
282
+ }
283
+ admin.replaceFollowers(followers);
284
+ admin.replaceInboxActivities(activities);
285
+ return { followers: followers.length, activities: activities.length };
286
+ }
287
+ /**
288
+ * Write an older site's inbox rows out as files, once.
289
+ *
290
+ * Before decision-9 the table was the source rather than an index of one, so a
291
+ * site upgrading has rows that no file carries. The rule is the simple one the
292
+ * other decision-9 migrations use, and it is simple here because the log did
293
+ * not exist as a file at all before: a log that is already there wins outright
294
+ * and is not touched, and rows are written out only where there is none. The
295
+ * lines it writes name no recipient, because the site they came from had one
296
+ * actor and it is gone (decision-14).
297
+ *
298
+ * The site actor's followers are **not** migrated. decision-14 replaces one
299
+ * site actor with one actor per user, and there is no honest answer to which
300
+ * user inherited the followers of an account that no longer exists: a follow
301
+ * is an agreement with somebody, and handing it to whoever happens to have the
302
+ * lowest user id would be answering it for them. A site that federated as the
303
+ * site actor starts again as its users, and the old
304
+ * `content/_data/federation/followers.json` is left exactly where it is for an
305
+ * operator who wants to move rows into a user's file by hand.
306
+ *
307
+ * The table is not dropped, unlike `settings`, `actor_keys` and `users`: it
308
+ * stays as the index the rest of the CMS reads. {@link rebuildFederationIndexes}
309
+ * is what runs next and puts the files back into it.
310
+ */
311
+ export function migrateFederationToFiles(records) {
312
+ const { admin, contentDir } = records;
313
+ if (inboxFiles(contentDir).length === 0) {
314
+ const byMonth = new Map();
315
+ for (const activity of [...admin.listInboxActivities()].reverse()) {
316
+ const line = {
317
+ receivedAt: activity.receivedAt,
318
+ recipient: activity.recipient,
319
+ json: activity.json,
320
+ };
321
+ const month = inboxFile(contentDir, activity.receivedAt);
322
+ byMonth.set(month, [...(byMonth.get(month) ?? []), line]);
323
+ }
324
+ for (const [month, lines] of byMonth)
325
+ writeFileAtomicallySync(month, inboxJsonl(lines));
326
+ }
327
+ }
328
+ /**
329
+ * One user's followers as their file spells them: an array, indented, newline
330
+ * ended.
331
+ *
332
+ * The username is not written into the entries. It is the name of the
333
+ * directory the file is in, and saying it again once per follower would be a
334
+ * second place for it to be wrong.
335
+ */
336
+ function followersJson(followers) {
337
+ const entries = followers.map(({ username: _username, ...rest }) => rest);
338
+ return `${JSON.stringify(entries, null, 2)}\n`;
339
+ }
340
+ /**
341
+ * `followers.json` as the followers it names, or a thrown error naming it.
342
+ *
343
+ * An entry with no actor id or no inbox is refused rather than dropped. Those
344
+ * two are the whole of what a follower is for — something to deliver to, and a
345
+ * name to key it by — and skipping such an entry would leave the file and the
346
+ * index quietly disagreeing about who follows the site.
347
+ */
348
+ function parseFollowers(source, file, username) {
349
+ let parsed;
350
+ try {
351
+ parsed = JSON.parse(source);
352
+ }
353
+ catch (error) {
354
+ throw new Error(`${file} could not be read as JSON: ${messageOf(error)}`, { cause: error });
355
+ }
356
+ if (!Array.isArray(parsed)) {
357
+ throw new Error(`${file} should be a list of followers, one object per follower.`);
358
+ }
359
+ return parsed.map((entry, index) => {
360
+ if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {
361
+ throw new Error(`${file}: entry ${String(index + 1)} is not a follower object.`);
362
+ }
363
+ const follower = entry;
364
+ const actorId = follower['actorId'];
365
+ const inboxId = follower['inboxId'];
366
+ if (typeof actorId !== 'string' || actorId === '') {
367
+ throw new Error(`${file}: entry ${String(index + 1)} has no actorId.`);
368
+ }
369
+ if (typeof inboxId !== 'string' || inboxId === '') {
370
+ throw new Error(`${file}: the follower "${actorId}" has no inboxId to deliver to.`);
371
+ }
372
+ return {
373
+ username,
374
+ actorId,
375
+ inboxId,
376
+ sharedInboxId: optionalText(follower['sharedInboxId']),
377
+ handle: optionalText(follower['handle']),
378
+ name: optionalText(follower['name']),
379
+ iconUrl: optionalText(follower['iconUrl']),
380
+ url: optionalText(follower['url']),
381
+ followedAt: typeof follower['followedAt'] === 'string' ? follower['followedAt'] : '',
382
+ };
383
+ });
384
+ }
385
+ /** A value the file may have left out, as the text it holds or `null`. */
386
+ function optionalText(value) {
387
+ return typeof value === 'string' && value !== '' ? value : null;
388
+ }
389
+ /** Every month log a site has, oldest first. */
390
+ function inboxFiles(contentDir) {
391
+ const directory = inboxDirectory(contentDir);
392
+ let entries;
393
+ try {
394
+ entries = readdirSync(directory);
395
+ }
396
+ catch {
397
+ // No directory is no log, which is what a site nobody has interacted with
398
+ // has. Every other way this can fail fails again on the next boot.
399
+ return [];
400
+ }
401
+ // The names are `yyyy-mm`, so sorting them as text sorts them by month, and
402
+ // reading them in that order is what makes the row ids the arrival order.
403
+ return entries
404
+ .filter((name) => name.endsWith('.jsonl'))
405
+ .sort()
406
+ .map((name) => path.join(directory, name));
407
+ }
408
+ /** One month's log as its lines, or a thrown error naming the file. */
409
+ function readInboxFile(file) {
410
+ const source = readFileIfPresentSync(file);
411
+ if (source === undefined)
412
+ return [];
413
+ const lines = [];
414
+ const rows = source.split('\n');
415
+ for (const [index, row] of rows.entries()) {
416
+ if (row.trim() === '')
417
+ continue;
418
+ let parsed;
419
+ try {
420
+ parsed = JSON.parse(row);
421
+ }
422
+ catch (error) {
423
+ throw new Error(`${file}: line ${String(index + 1)} is not JSON: ${messageOf(error)}`, {
424
+ cause: error,
425
+ });
426
+ }
427
+ if (!isRecord(parsed)) {
428
+ throw new Error(`${file}: line ${String(index + 1)} is not an activity.`);
429
+ }
430
+ // `receivedAt` and `recipient` are the log's own words and everything else
431
+ // is the activity, so taking them off leaves exactly what the peer
432
+ // delivered.
433
+ const { receivedAt, recipient, ...activity } = parsed;
434
+ lines.push({
435
+ receivedAt: typeof receivedAt === 'string' ? receivedAt : '',
436
+ recipient: typeof recipient === 'string' && recipient !== '' ? recipient : null,
437
+ json: JSON.stringify(activity),
438
+ });
439
+ }
440
+ return lines;
441
+ }
442
+ /** The lines as the file spells them: one compact JSON object each. */
443
+ function inboxJsonl(lines) {
444
+ return lines
445
+ .map((line) => `${JSON.stringify({
446
+ receivedAt: line.receivedAt,
447
+ // Absent rather than null for a shared-inbox delivery that named
448
+ // nobody, so a log written before decision-14 and one written after
449
+ // it read the same.
450
+ ...(line.recipient === null ? {} : { recipient: line.recipient }),
451
+ ...JSON.parse(line.json),
452
+ })}\n`)
453
+ .join('');
454
+ }
455
+ /** Whether a line carries this activity id, for the redelivery that replaces it. */
456
+ function sameActivity(activityId) {
457
+ return (line) => {
458
+ const parsed = JSON.parse(line.json);
459
+ return isRecord(parsed) && uriOf(parsed['id']) === activityId;
460
+ };
461
+ }
462
+ /**
463
+ * The short ActivityStreams type name an activity carries: `Like`, `Announce`,
464
+ * `Create`.
465
+ *
466
+ * A compacted document usually spells it as that word, which is what the
467
+ * `INBOX_INTERACTIONS` table on the federation screen keys on. Anything else
468
+ * is reduced the way the type IRI is: the fragment, else the last path
469
+ * segment, so an activity outside the core vocabulary still has a name rather
470
+ * than a URL. An activity with several types is filed under the first, and one
471
+ * with none is `Activity`, which is what it is.
472
+ */
473
+ function activityTypeOf(value) {
474
+ if (Array.isArray(value)) {
475
+ for (const item of value) {
476
+ const found = activityTypeOf(item);
477
+ if (found !== 'Activity')
478
+ return found;
479
+ }
480
+ return 'Activity';
481
+ }
482
+ if (typeof value !== 'string' || value === '')
483
+ return 'Activity';
484
+ if (!value.includes(':'))
485
+ return value;
486
+ try {
487
+ const url = new URL(value);
488
+ if (url.hash !== '')
489
+ return url.hash.slice(1);
490
+ const last = url.pathname
491
+ .split('/')
492
+ .filter((segment) => segment !== '')
493
+ .pop();
494
+ return last ?? value;
495
+ }
496
+ catch {
497
+ return value;
498
+ }
499
+ }
500
+ function isRecord(value) {
501
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
502
+ }
503
+ function messageOf(error) {
504
+ return error instanceof Error ? error.message : String(error);
505
+ }
506
+ //# sourceMappingURL=records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"records.js","sourceRoot":"","sources":["../../src/federation/records.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ import { Accept, Reject } from '@fedify/vocab';
2
+ import type { Recipient } from '@fedify/vocab';
3
+ import type { AdminStore, Relay } from '../admin/store.ts';
4
+ import type { ResolvedConfig } from '../config.ts';
5
+ import type { ContentStore } from '../content/store.ts';
6
+ import type { SiteFederation } from './federation.ts';
7
+ /** Where a relay reports what it could not do. `console` will do. */
8
+ export interface RelayLogger {
9
+ warn(message: string): void;
10
+ }
11
+ /** What {@link createRelayService} needs. */
12
+ export interface CreateRelayServiceOptions {
13
+ /** The site's federation object, which mints the ids and signs the requests. */
14
+ federation: SiteFederation;
15
+ /** The settings, which hold the relay list, and the subscription records. */
16
+ admin: AdminStore;
17
+ /** The content index, which the dispatchers read through the context. */
18
+ store: ContentStore;
19
+ /** Config after defaults and environment overrides. */
20
+ config: ResolvedConfig;
21
+ /** Where failures are reported. Defaults to `console`. */
22
+ logger?: RelayLogger | undefined;
23
+ }
24
+ /** What one call to {@link RelayService.sync} did. */
25
+ export interface RelaySyncReport {
26
+ /** The relays newly followed, because the list named them and nothing knew them. */
27
+ readonly followed: readonly string[];
28
+ /** The relays unfollowed, because the list stopped naming them. */
29
+ readonly unfollowed: readonly string[];
30
+ }
31
+ /**
32
+ * The site's half of the Mastodon relay protocol (FEP-ae0c).
33
+ *
34
+ * A relay is not a follower and is not stored as one: it is followed rather
35
+ * than following, its subscription can be refused, and it has no profile worth
36
+ * showing. What it shares with a follower is the only thing that matters to
37
+ * the rest of the system — an inbox every public activity is delivered to —
38
+ * and {@link relayRecipient} is where that likeness is spelled out.
39
+ */
40
+ export interface RelayService {
41
+ /**
42
+ * Bring the subscriptions in line with the relay list in the settings: a
43
+ * listed relay with no record is followed, a record no longer listed is
44
+ * undone. Called at boot and after every save of the settings.
45
+ *
46
+ * A listed relay whose record was lost — a rebuilt database, a restored
47
+ * content directory — is followed again, which is what makes the file the
48
+ * source and the records derivable from it.
49
+ */
50
+ sync(): RelaySyncReport;
51
+ /**
52
+ * Send the `Follow` again for one relay, under a fresh id, and put its
53
+ * record back to pending. This is the Retry on the federation screen: a
54
+ * relay may have been down, or may have lost the subscription.
55
+ */
56
+ retry(inboxId: string): Promise<Relay | undefined>;
57
+ /** Resolve once every queued `Follow` and `Undo` has finished, however it finished. */
58
+ settled(): Promise<void>;
59
+ }
60
+ /**
61
+ * One relay as the {@link Recipient} Fedify delivers to.
62
+ *
63
+ * The inbox stands in for the id until the relay has answered, because the
64
+ * `Follow` goes out before the site knows what to call it: Fedify drops a
65
+ * recipient with no id, so `null` would silently send nothing. The id is only
66
+ * ever used to key the inbox and to build a collection synchronisation header
67
+ * for a shared inbox, and a relay publishes no shared inbox — a relay *is* one
68
+ * — so standing the inbox in for it costs the relay nothing.
69
+ */
70
+ export declare function relayRecipient(relay: Relay): Recipient;
71
+ /**
72
+ * The relays a public activity is delivered to: the accepted ones, and only
73
+ * those.
74
+ *
75
+ * A pending subscription has not been agreed to and a rejected one has been
76
+ * refused; delivering to either would be posting into an inbox that has not
77
+ * said it wants this, which is what the handshake exists to establish.
78
+ */
79
+ export declare function acceptedRelays(admin: AdminStore): Relay[];
80
+ /**
81
+ * Build the relay service for one site.
82
+ *
83
+ * FEP-ae0c is the whole of the protocol: a `Follow` whose object is the
84
+ * literal Public collection, sent to the relay's inbox and signed the way any
85
+ * other activity is; an `Accept` or a `Reject` back, which may take days
86
+ * because a relay is allowed to hold a subscription for a human to approve;
87
+ * and an `Undo` of that same `Follow` to leave.
88
+ */
89
+ export declare function createRelayService(options: CreateRelayServiceOptions): RelayService;
90
+ /**
91
+ * Mark the subscription an `Accept` answers as accepted, and record who the
92
+ * relay turned out to be. `undefined` when it answers no follow this site
93
+ * sent — the site follows nothing but relays (doc-4), so that is a stray.
94
+ *
95
+ * A free function over the store rather than a method on the service: nothing
96
+ * about it is queued or sent, and the inbox listener that calls it has the
97
+ * store on its context and no service.
98
+ */
99
+ export declare function acceptRelay(admin: AdminStore, activity: Accept): Relay | undefined;
100
+ /** The same for a `Reject`, which marks the relay rejected with its reason. */
101
+ export declare function rejectRelay(admin: AdminStore, activity: Reject): Relay | undefined;
102
+ /**
103
+ * Match an `Accept` or a `Reject` to the subscription it answers.
104
+ *
105
+ * The follow id is what FEP-ae0c says the answer names, so it is tried first.
106
+ * A relay that has answered before is then recognised by its actor id, which
107
+ * covers a re-follow whose answer echoes a stale id. Last, a single pending
108
+ * subscription on the answering relay's own origin is taken as the one meant:
109
+ * a relay answering from the host its inbox is on is answering about that
110
+ * inbox, and there is nothing else it could be about. Two pending
111
+ * subscriptions on one host are left alone rather than guessed between.
112
+ */
113
+ export declare function relayAnswering(admin: AdminStore, activity: Accept | Reject): Relay | undefined;
114
+ //# sourceMappingURL=relays.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relays.d.ts","sourceRoot":"","sources":["../../src/federation/relays.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAA6B,MAAM,EAAQ,MAAM,eAAe,CAAC;AAChF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAK/C,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAyB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE7E,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,6CAA6C;AAC7C,MAAM,WAAW,yBAAyB;IACxC,gFAAgF;IAChF,UAAU,EAAE,cAAc,CAAC;IAC3B,6EAA6E;IAC7E,KAAK,EAAE,UAAU,CAAC;IAClB,yEAAyE;IACzE,KAAK,EAAE,YAAY,CAAC;IACpB,uDAAuD;IACvD,MAAM,EAAE,cAAc,CAAC;IACvB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,sDAAsD;AACtD,MAAM,WAAW,eAAe;IAC9B,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,mEAAmE;IACnE,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;OAQG;IACH,IAAI,IAAI,eAAe,CAAC;IACxB;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IACnD,uFAAuF;IACvF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAKtD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK,EAAE,CAEzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CAyMnF;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CASlF;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CASlF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAoB9F"}