fedipod-server 0.29.0 → 0.31.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 (444) hide show
  1. package/README.md +16 -6
  2. package/dist/claims.d.ts +2 -0
  3. package/dist/claims.js +13 -4
  4. package/dist/door.d.ts +4 -0
  5. package/dist/door.js +31 -0
  6. package/dist/fedipod.d.ts +15 -0
  7. package/dist/fedipod.js +13 -0
  8. package/dist/front.d.ts +3 -0
  9. package/dist/front.js +92 -0
  10. package/dist/handler.d.ts +36 -101
  11. package/dist/handler.js +93 -644
  12. package/dist/handler.jsonld +2 -30
  13. package/dist/identities.d.ts +71 -0
  14. package/dist/identities.js +236 -0
  15. package/dist/mounts.d.ts +43 -0
  16. package/dist/mounts.js +123 -0
  17. package/dist/opt-in.d.ts +46 -0
  18. package/dist/opt-in.js +176 -0
  19. package/dist/private-read.d.ts +4 -0
  20. package/dist/private-read.js +34 -0
  21. package/package.json +12 -20
  22. package/lib/client/c2s.mjs +0 -636
  23. package/lib/client/localapi.mjs +0 -87
  24. package/lib/client/masto/accounts.mjs +0 -310
  25. package/lib/client/masto/body.mjs +0 -156
  26. package/lib/client/masto/index.mjs +0 -206
  27. package/lib/client/masto/instance.mjs +0 -112
  28. package/lib/client/masto/media.mjs +0 -79
  29. package/lib/client/masto/oauth.mjs +0 -656
  30. package/lib/client/masto/render.mjs +0 -518
  31. package/lib/client/masto/statuses.mjs +0 -372
  32. package/lib/client/masto/timelines.mjs +0 -438
  33. package/lib/client/oidc-auth.mjs +0 -62
  34. package/lib/client/streaming.mjs +0 -154
  35. package/lib/client/webpush.mjs +0 -98
  36. package/lib/connections/acctfeed.mjs +0 -257
  37. package/lib/connections/atproto.mjs +0 -309
  38. package/lib/connections/bskyfeed.mjs +0 -243
  39. package/lib/connections/bskygroup.mjs +0 -162
  40. package/lib/connections/fediacct.mjs +0 -253
  41. package/lib/connections/import.mjs +0 -357
  42. package/lib/connections/tagfeed.mjs +0 -212
  43. package/lib/connections/vault.mjs +0 -114
  44. package/lib/core/as2.mjs +0 -206
  45. package/lib/core/contexts/activitystreams.json +0 -379
  46. package/lib/core/contexts/anno.json +0 -126
  47. package/lib/core/contexts/did-v1.json +0 -57
  48. package/lib/core/contexts/fep-5711.json +0 -36
  49. package/lib/core/contexts/gotosocial.json +0 -86
  50. package/lib/core/contexts/identity-v1.json +0 -152
  51. package/lib/core/contexts/index.mjs +0 -63
  52. package/lib/core/contexts/join-lemmy.json +0 -33
  53. package/lib/core/contexts/joinmastodon.json +0 -28
  54. package/lib/core/contexts/litepub-0.1.json +0 -60
  55. package/lib/core/contexts/map.json +0 -19
  56. package/lib/core/contexts/miscellany.json +0 -19
  57. package/lib/core/contexts/quotes.json +0 -18
  58. package/lib/core/contexts/schemaorg.json +0 -8845
  59. package/lib/core/contexts/security-data-integrity-v1.json +0 -78
  60. package/lib/core/contexts/security-data-integrity-v2.json +0 -81
  61. package/lib/core/contexts/security-multikey-v1.json +0 -35
  62. package/lib/core/contexts/security-v1.json +0 -74
  63. package/lib/core/contexts/webfinger.json +0 -10
  64. package/lib/core/deliver.mjs +0 -387
  65. package/lib/core/graphview.mjs +0 -327
  66. package/lib/core/intake/activities.mjs +0 -649
  67. package/lib/core/intake/activity.mjs +0 -318
  68. package/lib/core/intake/channel.mjs +0 -144
  69. package/lib/core/intake/group.mjs +0 -258
  70. package/lib/core/intake/index.mjs +0 -732
  71. package/lib/core/intake/notes.mjs +0 -367
  72. package/lib/core/intake/verify.mjs +0 -142
  73. package/lib/core/keys.mjs +0 -153
  74. package/lib/core/lease.mjs +0 -206
  75. package/lib/core/place.mjs +0 -82
  76. package/lib/core/polls.mjs +0 -105
  77. package/lib/core/profile-page.mjs +0 -104
  78. package/lib/core/proof.mjs +0 -79
  79. package/lib/core/publisher/collections.mjs +0 -272
  80. package/lib/core/publisher/index.mjs +0 -522
  81. package/lib/core/publisher/notes.mjs +0 -519
  82. package/lib/core/publisher/own.mjs +0 -143
  83. package/lib/core/publisher/questions.mjs +0 -241
  84. package/lib/core/publisher/restore.mjs +0 -224
  85. package/lib/core/shapes/activitystreams.ttl +0 -157
  86. package/lib/core/shapes/index.mjs +0 -132
  87. package/lib/core/shapes/shapes-text.mjs +0 -13
  88. package/lib/core/social.mjs +0 -561
  89. package/lib/core/storage.mjs +0 -176
  90. package/lib/core/store.mjs +0 -578
  91. package/lib/core/wire-quotes.mjs +0 -71
  92. package/lib/core/wire.mjs +0 -925
  93. package/lib/device/account.mjs +0 -87
  94. package/lib/device/admin/index.mjs +0 -13
  95. package/lib/device/admin/origins.mjs +0 -35
  96. package/lib/device/admin/routes/connections.mjs +0 -144
  97. package/lib/device/admin/routes/gateway.mjs +0 -199
  98. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  99. package/lib/device/admin/routes/owner.mjs +0 -322
  100. package/lib/device/admin/routes/setup.mjs +0 -428
  101. package/lib/device/admin/routes/social.mjs +0 -188
  102. package/lib/device/admin/server.mjs +0 -95
  103. package/lib/device/admin/static.mjs +0 -247
  104. package/lib/device/admin/surface.mjs +0 -315
  105. package/lib/device/certs.mjs +0 -281
  106. package/lib/device/cli/commands/account.mjs +0 -586
  107. package/lib/device/cli/commands/run.mjs +0 -278
  108. package/lib/device/cli/commands/service.mjs +0 -221
  109. package/lib/device/cli/commands/setup.mjs +0 -489
  110. package/lib/device/cli/commands/state.mjs +0 -561
  111. package/lib/device/cli/context.mjs +0 -288
  112. package/lib/device/export-collections.mjs +0 -161
  113. package/lib/device/gateway-move.mjs +0 -58
  114. package/lib/device/home.mjs +0 -161
  115. package/lib/device/migrate.mjs +0 -115
  116. package/lib/device/ports.mjs +0 -27
  117. package/lib/device/remote.mjs +0 -54
  118. package/lib/device/setup.mjs +0 -496
  119. package/lib/device/update.mjs +0 -96
  120. package/lib/gateway/caches.mjs +0 -36
  121. package/lib/gateway/directory.mjs +0 -90
  122. package/lib/gateway/front-core.mjs +0 -966
  123. package/lib/gateway/gateway-core.mjs +0 -244
  124. package/lib/gateway/headers.mjs +0 -49
  125. package/lib/gateway/httpsig.mjs +0 -159
  126. package/lib/gateway/notices.mjs +0 -84
  127. package/lib/gateway/quiet.mjs +0 -189
  128. package/lib/gateway/relay-extras.mjs +0 -89
  129. package/lib/gateway/token-claims.mjs +0 -16
  130. package/lib/pod/README.md +0 -61
  131. package/lib/pod/actor.mjs +0 -96
  132. package/lib/pod/collection.mjs +0 -77
  133. package/lib/pod/containers.mjs +0 -140
  134. package/lib/pod/discovery.mjs +0 -46
  135. package/lib/pod/featured.mjs +0 -18
  136. package/lib/pod/followers.mjs +0 -24
  137. package/lib/pod/following.mjs +0 -10
  138. package/lib/pod/http.mjs +0 -74
  139. package/lib/pod/inbox.mjs +0 -166
  140. package/lib/pod/links.mjs +0 -35
  141. package/lib/pod/location.mjs +0 -52
  142. package/lib/pod/media.mjs +0 -27
  143. package/lib/pod/notes.mjs +0 -78
  144. package/lib/pod/notifications.mjs +0 -89
  145. package/lib/pod/outbox.mjs +0 -18
  146. package/lib/pod/package.json +0 -19
  147. package/lib/pod/policy.mjs +0 -58
  148. package/lib/pod/private.mjs +0 -19
  149. package/lib/pod/root.mjs +0 -104
  150. package/lib/pod/state.mjs +0 -40
  151. package/lib/pod/transport.mjs +0 -674
  152. package/lib/pod/type-index.mjs +0 -101
  153. package/lib/pod/urls.mjs +0 -91
  154. package/lib/server/embed.mjs +0 -424
  155. package/lib/session/README.md +0 -137
  156. package/lib/session/demo.html +0 -94
  157. package/lib/session/fedi-account.mjs +0 -417
  158. package/lib/session/fedi-login.mjs +0 -123
  159. package/lib/session/oidc-session.mjs +0 -233
  160. package/lib/session/package.json +0 -49
  161. package/lib/shared/guard.mjs +0 -213
  162. package/lib/shared/links.mjs +0 -9
  163. package/lib/shared/safefetch.mjs +0 -235
  164. package/lib/shared/ua.mjs +0 -29
  165. package/phanpy/dist/404.html +0 -40
  166. package/phanpy/dist/_headers +0 -2
  167. package/phanpy/dist/apple-touch-icon.png +0 -0
  168. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  169. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  170. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  171. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  172. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  173. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  174. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  175. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  176. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  177. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  178. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  179. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  180. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  181. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  182. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  183. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  184. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  185. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  186. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  187. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  188. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  189. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  190. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  191. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  192. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  193. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  195. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  196. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  197. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  198. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  199. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  200. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  201. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  202. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  203. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  204. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  205. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  206. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  207. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  208. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  209. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  210. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  211. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  212. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  213. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  214. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  215. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  216. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  217. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  218. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  219. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  220. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  221. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  222. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  223. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  224. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  225. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  226. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  227. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  228. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  229. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  230. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  231. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  232. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  233. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  234. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  235. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  236. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  237. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  238. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  239. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  240. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  241. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  242. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  243. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  244. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  245. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  246. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  247. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  248. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  249. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  250. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  251. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  252. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  253. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  254. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  255. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  256. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  257. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  258. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  259. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  260. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  261. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  262. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  263. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  264. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  265. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  266. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  267. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  268. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  269. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  270. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  271. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  272. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  273. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  274. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  275. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  276. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  277. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  278. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  279. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  280. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  281. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  282. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  283. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  284. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  285. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  286. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  287. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  288. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  289. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  290. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  291. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  292. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  293. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  294. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  295. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  296. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  297. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  298. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  299. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  300. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  301. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  302. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  303. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  304. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  305. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  306. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  307. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  308. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  309. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  310. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  311. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  312. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  313. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  314. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  315. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  316. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  317. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  318. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  319. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  320. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  321. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  322. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  323. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  324. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  325. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  326. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  327. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  328. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  329. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  330. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  331. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  332. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  333. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  334. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  335. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  336. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  337. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  338. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  339. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  340. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  341. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  342. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  343. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  344. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  345. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  346. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  347. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  348. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  349. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  350. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  351. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  352. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  353. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  354. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  355. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  356. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  357. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  358. package/phanpy/dist/compose/index.html +0 -20
  359. package/phanpy/dist/favicon.ico +0 -0
  360. package/phanpy/dist/index.html +0 -73
  361. package/phanpy/dist/logo-192.png +0 -0
  362. package/phanpy/dist/logo-512.png +0 -0
  363. package/phanpy/dist/logo-badge-72.png +0 -0
  364. package/phanpy/dist/logo-maskable-512.png +0 -0
  365. package/phanpy/dist/logo-monochrome-512.png +0 -0
  366. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  367. package/phanpy/dist/manifest.webmanifest +0 -1
  368. package/phanpy/dist/og-image-2.jpg +0 -0
  369. package/phanpy/dist/og-image.png +0 -0
  370. package/phanpy/dist/robots.txt +0 -2
  371. package/phanpy/dist/sw.js +0 -2
  372. package/phanpy/dist/sw.js.map +0 -1
  373. package/phanpy/dist/version.json +0 -1
  374. package/run-agent.mjs +0 -899
  375. package/vendor/gate.cjs +0 -138
  376. package/vendor/idp-grant.cjs +0 -394
  377. package/vendor/jfetch.cjs +0 -16
  378. package/web/admin/actors.js +0 -147
  379. package/web/admin/bar.css +0 -126
  380. package/web/admin/bar.js +0 -99
  381. package/web/admin/client/client.js +0 -66
  382. package/web/admin/client/index.html +0 -69
  383. package/web/admin/client-pick.js +0 -79
  384. package/web/admin/common.js +0 -23
  385. package/web/admin/connections.js +0 -112
  386. package/web/admin/gateway.js +0 -133
  387. package/web/admin/group.js +0 -258
  388. package/web/admin/index.html +0 -612
  389. package/web/admin/notices-bar.js +0 -90
  390. package/web/admin/oauth-signin.mjs +0 -37
  391. package/web/admin/record.js +0 -393
  392. package/web/admin/setup/index.html +0 -257
  393. package/web/admin/setup/setup.js +0 -339
  394. package/web/admin/tokens.css +0 -68
  395. package/web/admin/upkeep.js +0 -177
  396. package/web/admin/window.css +0 -55
  397. package/web/admin/window.js +0 -136
  398. package/web/app/README.md +0 -81
  399. package/web/app/admin-facade.mjs +0 -588
  400. package/web/app/agent.mjs +0 -672
  401. package/web/app/atproto-browser.mjs +0 -86
  402. package/web/app/authorize_interaction.html +0 -56
  403. package/web/app/authorize_interaction.js +0 -69
  404. package/web/app/boot.mjs +0 -616
  405. package/web/app/deliver-relay.mjs +0 -129
  406. package/web/app/dist/boot.js +0 -34562
  407. package/web/app/dist/boot.js.map +0 -7
  408. package/web/app/dist/sw.js +0 -73456
  409. package/web/app/dist/sw.js.map +0 -7
  410. package/web/app/fediacct-browser.mjs +0 -146
  411. package/web/app/gateway-move.mjs +0 -60
  412. package/web/app/idb-kv.mjs +0 -35
  413. package/web/app/index.html +0 -258
  414. package/web/app/keys-browser.mjs +0 -71
  415. package/web/app/keystore.mjs +0 -82
  416. package/web/app/oidc-session.mjs +0 -6
  417. package/web/app/pod-auth.mjs +0 -248
  418. package/web/app/pod-remote.mjs +0 -84
  419. package/web/app/shims/_globals.mjs +0 -2
  420. package/web/app/shims/fedify-sig.mjs +0 -77
  421. package/web/app/shims/node-crypto.mjs +0 -113
  422. package/web/app/shims/node-fs.mjs +0 -17
  423. package/web/app/shims/node-path.mjs +0 -19
  424. package/web/app/shims/node-url.mjs +0 -7
  425. package/web/app/shims/prelude.js +0 -58
  426. package/web/app/shims/safefetch.mjs +0 -58
  427. package/web/app/shims/shapes-text.mjs +0 -8
  428. package/web/app/shims/web-push.mjs +0 -14
  429. package/web/app/signup.mjs +0 -357
  430. package/web/app/sw-src.mjs +0 -220
  431. package/web/app/update.js +0 -70
  432. package/web/front/admin.html +0 -55
  433. package/web/front/admin.js +0 -89
  434. package/web/front/install.sh +0 -69
  435. package/web/front/new-account.html +0 -35
  436. package/web/front/new-account.js +0 -13
  437. package/web/front/notices.html +0 -69
  438. package/web/front/notices.js +0 -107
  439. package/web/front/run.html +0 -64
  440. package/web/front/run.js +0 -221
  441. package/web/front/solid-oidc-client.js +0 -6
  442. package/web/icons/forum.svg +0 -11
  443. package/web/icons/gateway.svg +0 -14
  444. package/web/icons/local.svg +0 -11
@@ -1,372 +0,0 @@
1
- // statuses.mjs — a status and what a client does to one: compose (a note, a
2
- // poll, a scheduled post, a reply through a connected account), source and
3
- // history, read, edit and delete, context, who reacted, pin, bookmarks and
4
- // favourites, scheduled posts, poll votes, favourite and boost.
5
-
6
- import crypto from 'node:crypto';
7
- import * as social from '../../core/social.mjs';
8
- import { readBody, pollParams, htmlToText } from './body.mjs';
9
- import {
10
- MAX_OPTIONS as POLL_MAX_OPTIONS, MAX_OPTION_CHARS as POLL_MAX_OPTION_CHARS,
11
- MIN_SECONDS as POLL_MIN_SECONDS, MAX_SECONDS as POLL_MAX_SECONDS,
12
- } from '../../core/polls.mjs';
13
-
14
- export async function handle(api, ctx) {
15
- const { req, res, pathname, url, send } = ctx; // eslint-disable-line no-unused-vars
16
-
17
- if (pathname === '/api/v1/statuses' && req.method === 'POST') {
18
- const body = await readBody(req);
19
- if (!body.status) return send(422, { error: 'status text required' });
20
- const visibility = body.visibility || 'public';
21
- if (!['public', 'unlisted', 'private', 'direct'].includes(visibility)) {
22
- return send(422, { error: `unknown visibility "${visibility}"` });
23
- }
24
- const inReplyTo = body.in_reply_to_id ? api.store.urlFor(body.in_reply_to_id) : undefined;
25
- // A reply to a mirrored Bluesky post goes out as a native Bluesky reply
26
- // — the parent is not an AP object, so there is no AP note to make.
27
- const bskyParent = inReplyTo && api.store.getStatuses().find(x => x.noteId === inReplyTo && x.kind === 'bsky');
28
- if (bskyParent) return api.bskyReply(send, body, bskyParent, visibility);
29
- // A reply to a post a connected account brought us goes out from that
30
- // account, where the conversation already is.
31
- const acctParent = inReplyTo && api.store.getStatuses().find(x => x.noteId === inReplyTo && x.kind === 'acct');
32
- if (acctParent) return api.acctReply(send, body, acctParent, visibility);
33
- // Private and direct posts live in an owner-only pod container — and
34
- // only on a pod that provably enforces it.
35
- if (visibility === 'private' || visibility === 'direct') {
36
- const ready = await api.agent.publisher.privateReady();
37
- if (ready !== true) return send(422, { error: ready });
38
- }
39
- const spoilerText = String(body.spoiler_text || '').trim() || null;
40
- const sensitive = body.sensitive === true || body.sensitive === 'true' || body.sensitive === '1';
41
- const mediaIds = [].concat(body.media_ids || body['media_ids[]'] || []).filter(Boolean);
42
- const media = api.store.getMedia();
43
- const attachments = mediaIds.map(id => media[id] && { id, ...media[id] }).filter(Boolean);
44
-
45
- // A quote: the post named is one this account holds, and its author has
46
- // said it may be quoted. The author's answer decides what the reader sees;
47
- // the reasons a quote cannot even be asked for are the client's to show.
48
- let quote = null;
49
- if (body.quoted_status_id) {
50
- const quotedUrl = api.store.urlFor(String(body.quoted_status_id));
51
- const quoted = quotedUrl && api.store.getStatuses().find(x => x.noteId === quotedUrl);
52
- if (!quoted) return send(404, { error: 'Record not found' });
53
- if (['bsky', 'acct'].includes(quoted.kind)) return send(422, { error: 'that post cannot be quoted from this account' });
54
- if (visibility === 'private' || visibility === 'direct') return send(422, { error: 'a quote post is public or unlisted' });
55
- const may = api.quoteApproval(quoted).current_user;
56
- if (may === 'denied') return send(422, { error: 'the author of that post does not allow quotes' });
57
- if (may === 'unknown') return send(422, { error: 'the author of that post has not said whether it may be quoted' });
58
- if (body.scheduled_at) return send(422, { error: 'a quote cannot be scheduled' });
59
- quote = { id: quoted.noteId, actor: quoted.actor };
60
- }
61
-
62
- const asking = pollParams(body);
63
- if (asking) {
64
- // Mastodon's own rules, stated here rather than discovered inside the
65
- // publisher, so a client gets the reason back on the request it made.
66
- if (quote) return send(422, { error: 'a poll cannot quote a post' });
67
- if (attachments.length) return send(422, { error: 'a poll cannot carry media' });
68
- if (body.scheduled_at) return send(422, { error: 'a poll cannot be scheduled' });
69
- if (asking.options.length < 2) return send(422, { error: 'a poll needs at least two options' });
70
- if (asking.options.length > POLL_MAX_OPTIONS) {
71
- return send(422, { error: `a poll takes at most ${POLL_MAX_OPTIONS} options` });
72
- }
73
- if (asking.options.some(o => o.length > POLL_MAX_OPTION_CHARS)) {
74
- return send(422, { error: `a poll option is at most ${POLL_MAX_OPTION_CHARS} characters` });
75
- }
76
- if (new Set(asking.options).size !== asking.options.length) {
77
- return send(422, { error: 'a poll\u2019s options must differ from one another' });
78
- }
79
- const seconds = asking.expiresIn ?? POLL_MAX_SECONDS;
80
- if (!Number.isFinite(seconds) || seconds < POLL_MIN_SECONDS || seconds > POLL_MAX_SECONDS) {
81
- return send(422, {
82
- error: `a poll runs between ${POLL_MIN_SECONDS} and ${POLL_MAX_SECONDS} seconds`,
83
- });
84
- }
85
- try {
86
- const q = await api.agent.publisher.publishQuestion(body.status, {
87
- options: asking.options, multiple: asking.multiple,
88
- expiresAt: new Date(Date.now() + seconds * 1000).toISOString(),
89
- inReplyTo, visibility, spoilerText, sensitive,
90
- });
91
- return send(200, api.status(api.store.getStatuses().find(x => x.noteId === q.id)));
92
- } catch (e) {
93
- return send(422, { error: e.message });
94
- }
95
- }
96
-
97
- if (body.scheduled_at) {
98
- // Nothing here publishes it when the time comes (see `scheduling` in the
99
- // constructor), so saying yes would be losing the post quietly.
100
- if (!api.scheduling) {
101
- return send(422, { error: 'this instance cannot schedule posts — it has no process '
102
- + 'running between now and then to publish one. Post it when you want it sent.' });
103
- }
104
- const at = Date.parse(body.scheduled_at);
105
- if (!Number.isFinite(at) || at < Date.now() + 60_000) {
106
- return send(422, { error: 'scheduled_at must be at least a minute from now' });
107
- }
108
- const sched = api.store.getScheduled();
109
- const entry = {
110
- id: crypto.randomBytes(8).toString('hex'), scheduledAt: new Date(at).toISOString(),
111
- params: { status: body.status, visibility, spoilerText, inReplyTo, attachments },
112
- };
113
- sched.push(entry);
114
- api.store.setScheduled(sched);
115
- return send(200, api.scheduledJson(entry));
116
- }
117
- let note;
118
- try {
119
- note = await api.agent.publisher.publishNote(body.status,
120
- { inReplyTo, attachments, visibility, spoilerText, sensitive, quote });
121
- } catch (e) {
122
- // A direct message nobody could be found for: the sender's mistake to
123
- // fix, said in the client, not a fault of the server.
124
- if (e.code === 'unaddressed') return send(422, { error: e.message });
125
- throw e;
126
- }
127
- const s = api.store.getStatuses().find(x => x.noteId === note.id);
128
- return send(200, api.status(s));
129
- }
130
-
131
- // Who may quote a post is the same for every post here — anyone, when the
132
- // world can read it — and is not set per post.
133
- if (/^\/api\/v1\/statuses\/[a-f0-9]+\/interaction_policy$/.test(pathname) && req.method === 'PUT') {
134
- return send(422, { error: 'the quote policy is the same for every post here: anyone may quote a public or unlisted post, nobody a followers-only or direct one' });
135
- }
136
-
137
- // The composer reads the raw text back before an edit.
138
- const mSource = /^\/api\/v1\/statuses\/([a-f0-9]+)\/source$/.exec(pathname);
139
- if (mSource && req.method === 'GET') {
140
- const noteUrl = api.store.urlFor(mSource[1]);
141
- const s = noteUrl && api.store.getStatuses().find(x => x.noteId === noteUrl);
142
- if (!s) return send(404, { error: 'Record not found' });
143
- return send(200, { id: mSource[1], text: s.text ?? htmlToText(s.content || ''), spoiler_text: s.spoiler || '' });
144
- }
145
-
146
- // One entry — the current version. Enough for the client's history view;
147
- // past versions are not kept.
148
- const mHistory = /^\/api\/v1\/statuses\/([a-f0-9]+)\/history$/.exec(pathname);
149
- if (mHistory && req.method === 'GET') {
150
- const noteUrl = api.store.urlFor(mHistory[1]);
151
- const s = noteUrl && api.store.getStatuses().find(x => x.noteId === noteUrl);
152
- if (!s) return send(404, { error: 'Record not found' });
153
- return send(200, [{
154
- content: s.content || '', spoiler_text: s.spoiler || '', sensitive: !!(s.spoiler || s.sensitive),
155
- created_at: s.editedAt || s.published, account: api.account(s.actor),
156
- media_attachments: (s.attachments || []).map(a => api.mediaJson(a)),
157
- emojis: [], poll: null,
158
- }]);
159
- }
160
-
161
- const mStatus = /^\/api\/v1\/statuses\/([a-f0-9]+)$/.exec(pathname);
162
- if (mStatus && req.method === 'GET') {
163
- const { s, wrapped } = api.lookup(mStatus[1]);
164
- if (!s) return send(404, { error: 'Record not found' });
165
- return send(200, wrapped ? api.statusOrBoost(s) : api.status(s));
166
- }
167
- if (mStatus && req.method === 'PUT') {
168
- const noteUrl = api.store.urlFor(mStatus[1]);
169
- const s = noteUrl && api.store.getStatuses().find(x => x.noteId === noteUrl);
170
- if (!s) return send(404, { error: 'Record not found' });
171
- if (s.actor !== api.urls.actor) return send(403, { error: 'not your status' });
172
- const body = await readBody(req);
173
- if (!body.status) return send(422, { error: 'status text required' });
174
- const mediaIds = [].concat(body.media_ids || body['media_ids[]'] || []).filter(Boolean);
175
- const media = api.store.getMedia();
176
- const attachments = mediaIds.length
177
- ? mediaIds.map(id => media[id] && { id, ...media[id] }).filter(Boolean)
178
- : null; // null: keep what the post has
179
- const spoilerText = String(body.spoiler_text || '').trim() || null;
180
- const sensitive = body.sensitive === undefined ? null
181
- : (body.sensitive === true || body.sensitive === 'true' || body.sensitive === '1');
182
- const patched = await api.agent.publisher.updateNote(s,
183
- { content: body.status, spoilerText, sensitive, attachments });
184
- return send(200, api.status(patched || s));
185
- }
186
- if (mStatus && req.method === 'DELETE') {
187
- const noteUrl = api.store.urlFor(mStatus[1]);
188
- const s = noteUrl && api.store.getStatuses().find(x => x.noteId === noteUrl);
189
- if (!s) return send(404, { error: 'Record not found' });
190
- // A post the owner wrote on a connected account is theirs to delete too.
191
- // It is deleted where it lives — an AP Delete of ours would address an
192
- // object that was never ours to speak for.
193
- const onAcct = s.actor !== api.urls.actor
194
- ? (api.agent.fediaccts?.list() || []).find(r => r.actorUrl && r.actorUrl === s.actor)
195
- : null;
196
- if (s.actor !== api.urls.actor && !onAcct) return send(403, { error: 'not your status' });
197
- const rendered = api.status(s);
198
- if (onAcct) {
199
- const held = (s.sourceAccts || []).find(v => v.acct === onAcct.id);
200
- if (!held?.remoteId) return send(422, { error: `we do not know where ${onAcct.handle} keeps that post` });
201
- try {
202
- await api.agent.fediaccts.api(onAcct.id,
203
- `/api/v1/statuses/${encodeURIComponent(held.remoteId)}`, { method: 'DELETE' });
204
- } catch (e) { return send(502, { error: e.message }); }
205
- api.store.removeStatus(s.noteId);
206
- return send(200, { ...rendered, text: s.content || '' });
207
- }
208
- // 502, because the refusal is the pod's: the client asked correctly and
209
- // the post is still up. Reporting 200 here is what let a deleted post
210
- // stay publicly readable with nothing to show for it.
211
- const gone = await social.deleteNote(api.agent, s);
212
- if (!gone.ok) return send(502, { error: gone.error });
213
- return send(200, { ...rendered, text: s.content || '' });
214
- }
215
-
216
- // Threads from the mirror's inReplyTo chains.
217
- const mContext = /^\/api\/v1\/statuses\/([a-f0-9]+)\/context$/.exec(pathname);
218
- if (mContext) {
219
- const noteUrl = api.lookup(mContext[1]).s?.noteId;
220
- // A Bluesky post's conversation lives on Bluesky: ask for it now, so the
221
- // replies (and their pictures) are in the mirror before the thread is built.
222
- const opened = noteUrl && api.store.getStatuses().find(x => x.noteId === noteUrl);
223
- if (opened?.kind === 'bsky' && typeof api.agent?.bskyfeed?.mirrorThread === 'function') {
224
- await api.agent.bskyfeed.mirrorThread(noteUrl);
225
- }
226
- const all = api.store.getStatuses();
227
- const byId = new Map(all.map(s => [s.noteId, s]));
228
- const ancestors = [];
229
- let cur = noteUrl && byId.get(noteUrl)?.inReplyTo;
230
- while (cur && byId.has(cur) && ancestors.length < 40) {
231
- const s = byId.get(cur);
232
- ancestors.unshift(s);
233
- cur = s.inReplyTo;
234
- }
235
- const descendants = [];
236
- const queue = noteUrl ? [noteUrl] : [];
237
- while (queue.length && descendants.length < 60) {
238
- const id = queue.shift();
239
- for (const s of all) if (s.inReplyTo === id) { descendants.push(s); queue.push(s.noteId); }
240
- }
241
- return send(200, {
242
- ancestors: ancestors.map(s => api.status(s, { all })),
243
- descendants: descendants.map(s => api.status(s, { all })),
244
- });
245
- }
246
-
247
- // Who reacted: only what our own store witnessed, so the lists are the
248
- // reactions we were notified of, not the whole fediverse's count.
249
- const mWho = /^\/api\/v1\/statuses\/([a-f0-9]+)\/(reblogged_by|favourited_by)$/.exec(pathname);
250
- if (mWho && req.method === 'GET') {
251
- const noteUrl = api.store.urlFor(mWho[1]);
252
- if (!noteUrl) return send(404, { error: 'Record not found' });
253
- const type = mWho[2] === 'reblogged_by' ? 'reblog' : 'favourite';
254
- const actors = [...new Set(api.store.getNotifications()
255
- .filter(n => n.noteId === noteUrl && n.type === type).map(n => n.actor))];
256
- return send(200, actors.map(a => api.account(a)));
257
- }
258
-
259
- // Pinning republishes the featured collection, so a visitor's server
260
- // shows the pins too; the actor document names the collection.
261
- const mPin = /^\/api\/v1\/statuses\/([a-f0-9]+)\/(pin|unpin)$/.exec(pathname);
262
- if (mPin && req.method === 'POST') {
263
- const noteUrl = api.store.urlFor(mPin[1]);
264
- const s = noteUrl && api.store.getStatuses().find(x => x.noteId === noteUrl);
265
- if (!s) return send(404, { error: 'Record not found' });
266
- if (s.actor !== api.urls.actor) return send(403, { error: 'not your status' });
267
- const updated = await social.pinStatus(api.agent, s, mPin[2] === 'pin');
268
- return send(200, api.status(updated));
269
- }
270
-
271
- if (pathname === '/api/v1/reports' && req.method === 'POST') {
272
- return send(422, {
273
- error: 'this is your own single-user server, so there is no moderation team to receive a report. Blocking the account is the action that takes effect here.',
274
- });
275
- }
276
-
277
- // Bookmarks are this machine's own list: nothing federates, nothing is
278
- // told, which is what a bookmark means everywhere.
279
- const mBookmark = /^\/api\/v1\/statuses\/([a-f0-9]+)\/(bookmark|unbookmark)$/.exec(pathname);
280
- if (mBookmark && req.method === 'POST') {
281
- const noteUrl = api.store.urlFor(mBookmark[1]);
282
- const s = noteUrl && api.store.getStatuses().find(x => x.noteId === noteUrl);
283
- if (!s) return send(404, { error: 'Record not found' });
284
- const updated = api.store.updateStatus(s.noteId, { bookmarked: mBookmark[2] === 'bookmark' });
285
- return send(200, api.status(updated || s));
286
- }
287
- if (pathname === '/api/v1/bookmarks' || pathname === '/api/v1/favourites') {
288
- const key = pathname.endsWith('bookmarks') ? 'bookmarked' : 'favourited';
289
- const all = api.store.getStatuses();
290
- const items = all.filter(s => s[key])
291
- .sort((a, b) => String(b.published || '').localeCompare(String(a.published || '')));
292
- const { items: page, headers } = api.page(items, url);
293
- return send(200, page.map(s => api.status(s, { all })), headers);
294
- }
295
-
296
- if (pathname === '/api/v1/scheduled_statuses' && req.method === 'GET') {
297
- return send(200, api.store.getScheduled().map(e => api.scheduledJson(e)));
298
- }
299
- const mSched = /^\/api\/v1\/scheduled_statuses\/([a-f0-9]+)$/.exec(pathname);
300
- if (mSched) {
301
- const sched = api.store.getScheduled();
302
- const e = sched.find(x => x.id === mSched[1]);
303
- if (!e) return send(404, { error: 'Record not found' });
304
- if (req.method === 'DELETE') {
305
- api.store.setScheduled(sched.filter(x => x.id !== mSched[1]));
306
- return send(200, {});
307
- }
308
- if (req.method === 'PUT') {
309
- const body = await readBody(req);
310
- const at = Date.parse(body.scheduled_at || '');
311
- if (!Number.isFinite(at)) return send(422, { error: 'scheduled_at required' });
312
- e.scheduledAt = new Date(at).toISOString();
313
- api.store.setScheduled(sched);
314
- }
315
- return send(200, api.scheduledJson(e));
316
- }
317
-
318
- const mPoll = /^\/api\/v1\/polls\/([a-f0-9]+)(\/votes)?$/.exec(pathname);
319
- if (mPoll) {
320
- const noteUrl = api.store.urlFor(mPoll[1]);
321
- const s = noteUrl && api.store.getStatuses().find(x => x.noteId === noteUrl);
322
- if (!s?.poll) return send(404, { error: 'Record not found' });
323
- if (mPoll[2] && req.method === 'POST') {
324
- const body = await readBody(req);
325
- const choices = [].concat(body.choices || body['choices[]'] || []).map(Number)
326
- .filter(Number.isInteger);
327
- if (!choices.length) return send(422, { error: 'choices required' });
328
- const r = await social.votePoll(api.agent, s, choices);
329
- if (!r.ok) return send(422, { error: r.error });
330
- return send(200, api.pollJson(api.store.getStatuses().find(x => x.noteId === noteUrl)));
331
- }
332
- return send(200, api.pollJson(s));
333
- }
334
-
335
- const mAction = /^\/api\/v1\/statuses\/([a-f0-9]+)\/(favourite|unfavourite|reblog|unreblog)$/.exec(pathname);
336
- if (mAction && req.method === 'POST') {
337
- // Acting on a carried row acts on the post itself, as Mastodon does.
338
- const { s } = api.lookup(mAction[1]);
339
- if (!s) return send(404, { error: 'Record not found' });
340
- // A mirrored Bluesky post is not an AP object — a Like or Announce has
341
- // nothing to address. The interaction goes to Bluesky instead, as the
342
- // native record every Bluesky app writes.
343
- if (s.kind === 'bsky') {
344
- const at = api.agent.atproto;
345
- if (!at?.connected()) return send(422, { error: 'this is a Bluesky post — no Bluesky account is connected to act from' });
346
- try {
347
- let patch = null;
348
- if (mAction[2] === 'favourite' && !s.favourited) {
349
- patch = { favourited: true, bskyLike: (await at.like(s.noteId, s.cid || null)).uri };
350
- } else if (mAction[2] === 'unfavourite' && s.favourited) {
351
- if (s.bskyLike) await at.deleteCrossPost(s.bskyLike);
352
- patch = { favourited: false, bskyLike: undefined };
353
- } else if (mAction[2] === 'reblog' && !s.reblogged) {
354
- patch = { reblogged: true, bskyRepost: (await at.repost(s.noteId, s.cid || null)).uri };
355
- } else if (mAction[2] === 'unreblog' && s.reblogged) {
356
- if (s.bskyRepost) await at.deleteCrossPost(s.bskyRepost);
357
- patch = { reblogged: false, bskyRepost: undefined };
358
- }
359
- return send(200, api.status(patch ? (api.store.updateStatus(s.noteId, patch) || s) : s));
360
- } catch (e) { return send(422, { error: e.message }); }
361
- }
362
- // A post that reached us through a connected account is not ours to
363
- // address as the pod actor. Our own posts and our own inbox's timeline
364
- // keep the AP path even when a connected account also saw them: where
365
- // the pod identity has standing, it is the one that acts.
366
- if (s.kind === 'acct') return api.acctAction(send, s, mAction[2]);
367
- const updated = await social[mAction[2]](api.agent, s);
368
- return send(200, api.status(updated || s));
369
- }
370
-
371
- return false;
372
- }