ghost 6.60.0 → 6.62.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 (613) hide show
  1. package/components/ghost-storage-base-3.0.0.tgz +0 -0
  2. package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
  3. package/components/tryghost-adapter-base-jobs-0.0.0.tgz +0 -0
  4. package/components/tryghost-adapter-base-redirects-0.0.0.tgz +0 -0
  5. package/components/tryghost-adapter-base-route-settings-0.0.0.tgz +0 -0
  6. package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
  7. package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
  8. package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
  9. package/components/tryghost-checkout-0.0.0.tgz +0 -0
  10. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  11. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  12. package/components/tryghost-kg-card-factory-5.2.4.tgz +0 -0
  13. package/components/tryghost-kg-clean-basic-html-4.3.4.tgz +0 -0
  14. package/components/tryghost-kg-converters-1.2.5.tgz +0 -0
  15. package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
  16. package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
  17. package/components/tryghost-kg-default-transforms-1.3.4.tgz +0 -0
  18. package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
  19. package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
  20. package/components/tryghost-kg-markdown-html-renderer-7.2.4.tgz +0 -0
  21. package/components/tryghost-kg-utils-1.1.4.tgz +0 -0
  22. package/components/tryghost-nql-string-0.0.0.tgz +0 -0
  23. package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
  24. package/content/settings/README.md +1 -1
  25. package/content/themes/casper/.gitignore +28 -0
  26. package/content/themes/casper/assets/built/casper.js +1 -1
  27. package/content/themes/casper/assets/built/screen.css +1 -1
  28. package/content/themes/casper/assets/css/screen.css +2 -1
  29. package/content/themes/casper/assets/js/lightbox.js +63 -46
  30. package/content/themes/casper/package.json +6 -6
  31. package/content/themes/casper/page.hbs +1 -0
  32. package/content/themes/casper/post.hbs +1 -0
  33. package/content/themes/source/.gitignore +28 -0
  34. package/content/themes/source/assets/built/screen.css +1 -1
  35. package/content/themes/source/assets/built/source.js +1 -1
  36. package/content/themes/source/assets/css/screen.css +2 -1
  37. package/content/themes/source/assets/js/lightbox.js +62 -45
  38. package/content/themes/source/assets/js/main.js +2 -2
  39. package/content/themes/source/package.json +4 -4
  40. package/content/themes/source/partials/feature-image.hbs +1 -0
  41. package/core/boot.js +62 -21
  42. package/core/built/admin/assets/Combination-B0l4MKVh.js +41 -0
  43. package/core/built/admin/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
  44. package/core/built/admin/assets/InterVariable-Italic-FCBEiFp6.woff2 +0 -0
  45. package/core/built/admin/assets/{PolarAngleAxis-C4qtHy1B.js → PolarAngleAxis-pkMyqz8g.js} +1 -1
  46. package/core/built/admin/assets/{RadialBarChart-Bh09Stsj.js → RadialBarChart-JAKoS4KT.js} +1 -1
  47. package/core/built/admin/assets/{about-BgpmhCuM.js → about-Dyae_UT6.js} +1 -1
  48. package/core/built/admin/assets/account-migration-CESa0mnX.js +1 -0
  49. package/core/built/admin/assets/{action-list-lGzZLHc8.js → action-list-C4v0-du8.js} +1 -1
  50. package/core/built/admin/assets/activitypub/{account-migration-DMHuPnJn.js → account-migration-By69CgCp.js} +16 -16
  51. package/core/built/admin/assets/activitypub/activitypub.js +9 -10
  52. package/core/built/admin/assets/activitypub/{avatar-DhTo5D1B.js → avatar-DLPL3Abs.js} +59 -68
  53. package/core/built/admin/assets/activitypub/{avatar-flipboard-DnVgbEfa.js → avatar-flipboard-C9iDY-QV.js} +2 -2
  54. package/core/built/admin/assets/activitypub/{bluesky-sharing-BT4zAlW7.js → bluesky-sharing-BJcPMrDd.js} +37 -37
  55. package/core/built/admin/assets/activitypub/{content-formatters-BeDZ-DIa.js → content-formatters-3rTHg3mp.js} +18 -18
  56. package/core/built/admin/assets/activitypub/{copy-8sqxUuNd.js → copy-DIAOQoCZ.js} +2 -2
  57. package/core/built/admin/assets/activitypub/{domain-xQDDu1CS.js → domain-DUR4xSkV.js} +121 -121
  58. package/core/built/admin/assets/activitypub/{edit-profile-BXdF_r2G.js → edit-profile-BqtfzxCp.js} +40 -40
  59. package/core/built/admin/assets/activitypub/{explore-CMt7gKlL.js → explore-BxuJd-J4.js} +27 -27
  60. package/core/built/admin/assets/activitypub/{feed-Bwqdddp_.js → feed-BM1TcksA.js} +51 -51
  61. package/core/built/admin/assets/activitypub/{field-4co_8FVg.js → field-Dn7HHx2-.js} +3 -3
  62. package/core/built/admin/assets/activitypub/{hash-DwakMs4X.js → hash-Bm3WxYN4.js} +2 -2
  63. package/core/built/admin/assets/activitypub/inbox-CCjkuow2.js +1284 -0
  64. package/core/built/admin/assets/activitypub/{inbox-ckD4wo_r.js → inbox-d8oJRTf4.js} +2 -2
  65. package/core/built/admin/assets/activitypub/label-1AA_s9Fa.js +16 -0
  66. package/core/built/admin/assets/activitypub/layout-2-0bw6HN.js +1 -0
  67. package/core/built/admin/assets/activitypub/{moderation-KCCO7L2J.js → moderation-CnmxEB8w.js} +91 -91
  68. package/core/built/admin/assets/activitypub/{note-BX_Bz5A0.js → note-ZKc_Bnba.js} +24 -24
  69. package/core/built/admin/assets/activitypub/{notifications-BQOYGvRv.js → notifications-CB2tJZau.js} +51 -51
  70. package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-BsJ9E5qf.js} +2 -2
  71. package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-CSUJJIlh.js} +2 -2
  72. package/core/built/admin/assets/activitypub/{preferences-6h43G9_q.js → preferences-0-JZnUkI.js} +1519 -1519
  73. package/core/built/admin/assets/activitypub/{profile-BMN9VVZ2.js → profile-C35cFIhM.js} +256 -256
  74. package/core/built/admin/assets/activitypub/{reply-ZNo04xsO.js → reply-DYK5vVqb.js} +2 -2
  75. package/core/built/admin/assets/activitypub/{routes-3B9mUQ7i.js → routes-BD4vscyc.js} +796 -790
  76. package/core/built/admin/assets/activitypub/{separator-D9taVCCa.js → separator-BbQqTm-p.js} +3 -3
  77. package/core/built/admin/assets/activitypub/settings-BsMROdqh.js +315 -0
  78. package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-O0RL9YCN.js} +2 -2
  79. package/core/built/admin/assets/activitypub/{step-1-BsGGnBuT.js → step-1-BMSx7c_X.js} +6 -6
  80. package/core/built/admin/assets/activitypub/{step-2-teosIS0k.js → step-2-DtPQzlTH.js} +6 -6
  81. package/core/built/admin/assets/activitypub/{step-3-BjD5TokC.js → step-3-CLlOZTyt.js} +11 -11
  82. package/core/built/admin/assets/activitypub/{tabs-Cvwl1wXU.js → tabs-Dxk-b9M-.js} +306 -306
  83. package/core/built/admin/assets/activitypub/{topic-filter-C3LZJc2X.js → topic-filter-5yZH6tId.js} +3 -3
  84. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-Dp9f0gov.js → use-activity-pub-queries-CV50qe03.js} +3 -3
  85. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-C4RI0sa9.js → use-navigate-with-base-path-Bmk5h4lW.js} +220 -220
  86. package/core/built/admin/assets/activitypub/{use-reply-chain-data-C2oNDMUH.js → use-reply-chain-data-Cbvzgjzd.js} +30 -30
  87. package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-BjcoP_HC.js} +7 -5
  88. package/core/built/admin/assets/activitypub/{x-Dxm6pV9X.js → x-DbQZOLiI.js} +2 -2
  89. package/core/built/admin/assets/add-integration-modal-BlF6rs_f.js +1 -0
  90. package/core/built/admin/assets/add-newsletter-modal-CglVQqah.js +1 -0
  91. package/core/built/admin/assets/add-recommendation-modal-wz7BsuaG.js +1 -0
  92. package/core/built/admin/assets/analytics-C4HE1gBg.js +1 -0
  93. package/core/built/admin/assets/{announcement-bar-modal-BTHiy1ZO.js → announcement-bar-modal-Ci4zz8jO.js} +1 -1
  94. package/core/built/admin/assets/{api-keys-Boy5pLbD.js → api-keys-Ck-Yteiv.js} +1 -1
  95. package/core/built/admin/assets/audience-CtbA54Sn.js +1 -0
  96. package/core/built/admin/assets/{automated-emails-te1D5kq-.js → automated-emails-D5VVMND9.js} +1 -1
  97. package/core/built/admin/assets/automations-CzKt5fb8.js +1 -0
  98. package/core/built/admin/assets/bluesky-sharing-BEtJ_gL_.js +1 -0
  99. package/core/built/admin/assets/{box-By_EgGtm.js → box-CdfQAP_F.js} +1 -1
  100. package/core/built/admin/assets/{brand-icon-09YqFZjV.js → brand-icon-CrIGOA3Z.js} +1 -1
  101. package/core/built/admin/assets/{breadcrumb-CcFr_ltt.js → breadcrumb-zUrZrBtW.js} +1 -1
  102. package/core/built/admin/assets/{button-BshWPHvn.js → button-eNMKQWXr.js} +1 -1
  103. package/core/built/admin/assets/{card-CiiE7QfM.js → card--VNbfgo3.js} +1 -1
  104. package/core/built/admin/assets/{chart-BnXyfH11.js → chart-BrhA41Zi.js} +1 -1
  105. package/core/built/admin/assets/chart-helpers-CfBKt0vT.js +1 -0
  106. package/core/built/admin/assets/{checkbox-Dwwr_3Py.js → checkbox-CgOn_tKW.js} +1 -1
  107. package/core/built/admin/assets/{chunk.524.91ecb33e6afc3bd8949b.js → chunk.524.a697dee88db67fdf6021.js} +4 -4
  108. package/core/built/admin/assets/{chunk.582.512549909741883f960c.js → chunk.582.5ed5d124cfca9c259b9c.js} +6 -6
  109. package/core/built/admin/assets/{chunk.16.f76a6314082d813d67e0.js → chunk.598.7e056fabb47ce7dbd73f.js} +14 -14
  110. package/core/built/admin/assets/{code-editor-view-BwIdPy_k.js → code-editor-view-BYNoAoNV.js} +1 -1
  111. package/core/built/admin/assets/{code-editor-view-CtkF82Fv.js → code-editor-view-K2wI-I5f.js} +1 -1
  112. package/core/built/admin/assets/color-picker-Ddw80xX6.js +3 -0
  113. package/core/built/admin/assets/color-picker-field-D9nUhvA7.js +1 -0
  114. package/core/built/admin/assets/combobox-w9j8PPQT.js +1 -0
  115. package/core/built/admin/assets/command-BfpHORBv.js +1 -0
  116. package/core/built/admin/assets/comments-BLmCmyCs.js +1 -0
  117. package/core/built/admin/assets/confirmation-context-CBM8G0Vj.js +1 -0
  118. package/core/built/admin/assets/{container-LiZf3XdY.js → container-BuQG1wuP.js} +1 -1
  119. package/core/built/admin/assets/{content-api-modal-BtpNI92-.js → content-api-modal-TXRz3U7S.js} +1 -1
  120. package/core/built/admin/assets/context-menu-_QMdd3kp.js +1 -0
  121. package/core/built/admin/assets/{copy-field-CglgRZyG.js → copy-field-6N01S07E.js} +1 -1
  122. package/core/built/admin/assets/create-ghost-browse-value-source-qIBymvvf.js +1 -0
  123. package/core/built/admin/assets/custom-field-type-option-BddFlJFa.js +1 -0
  124. package/core/built/admin/assets/custom-integration-modal-DmNquxUV.js +1 -0
  125. package/core/built/admin/assets/{data-list-CupF7bjM.js → data-list-CA2jYGPq.js} +1 -1
  126. package/core/built/admin/assets/{date-range-select-JPwM0yUj.js → date-range-select-uvz_DtPh.js} +1 -1
  127. package/core/built/admin/assets/design-and-theme-modal-BSmo12Op.js +2 -0
  128. package/core/built/admin/assets/{detail-page-D8lx2SdP.js → detail-page-Dnv-CdR1.js} +1 -1
  129. package/core/built/admin/assets/dirty-confirm-dialog-BZ1iytEd.js +1 -0
  130. package/core/built/admin/assets/{disabled-sources-indicator-BTJ2ClQu.js → disabled-sources-indicator-DMRrxsiJ.js} +1 -1
  131. package/core/built/admin/assets/{dist-DzcfoDJ3.js → dist-8YJUlf3B.js} +1 -1
  132. package/core/built/admin/assets/{dist-Cb5RSHSg.js → dist-B3keLvjj.js} +1 -1
  133. package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
  134. package/core/built/admin/assets/{dist-BT_Z-eCn.js → dist-Dgt2cr6a.js} +1 -1
  135. package/core/built/admin/assets/domain-BNYrt0aD.js +1 -0
  136. package/core/built/admin/assets/dropzone-D7nFdAe5.js +5 -0
  137. package/core/built/admin/assets/edit-profile-C5Asm4LA.js +1 -0
  138. package/core/built/admin/assets/editor-REokrzci.js +8 -0
  139. package/core/built/admin/assets/{embed-signup-form-modal-BFTPf04i.js → embed-signup-form-modal-Ds6mPEi5.js} +1 -1
  140. package/core/built/admin/assets/{empty-indicator-WB1WgT9h.js → empty-indicator-D9QdpuNX.js} +1 -1
  141. package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
  142. package/core/built/admin/assets/explore-UY10Egsp.js +1 -0
  143. package/core/built/admin/assets/feature-image-placeholder-D1iF_8bc.js +1 -0
  144. package/core/built/admin/assets/feed-81C8mJWR.js +1 -0
  145. package/core/built/admin/assets/{field-LmNk7wZh.js → field-Dihp5p18.js} +1 -1
  146. package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
  147. package/core/built/admin/assets/filter-sources-BO9xUPj7.js +1 -0
  148. package/core/built/admin/assets/filters-CRUWecfY.js +1 -0
  149. package/core/built/admin/assets/filters-DirqNXjH.js +1 -0
  150. package/core/built/admin/assets/first-promoter-modal-CT6MxYZb.js +1 -0
  151. package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8eabfc1ece81b03cf7b90780d31487e8.css} +1 -1
  152. package/core/built/admin/assets/{ghost-403cb39badad3df411fc0ba27d220047.js → ghost-c2848508292937415f20f5a830eea59e.js} +31 -28
  153. package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-a7bebe2c561f55369dcf29f4c820f7ff.css} +1 -1
  154. package/core/built/admin/assets/gift-link-modal-CQVAye17.js +1 -0
  155. package/core/built/admin/assets/{grid-CUciBfjf.js → grid-Dj29PY05.js} +1 -1
  156. package/core/built/admin/assets/growth-BWIu-6xj.js +3 -0
  157. package/core/built/admin/assets/growth-DU29oxeA.js +1 -0
  158. package/core/built/admin/assets/{heading-CRZZ2FUe.js → heading-Dh5SFVjL.js} +1 -1
  159. package/core/built/admin/assets/history-modal-CFd1Hvx6.js +1 -0
  160. package/core/built/admin/assets/html-field-CJBCLTvv.js +1 -0
  161. package/core/built/admin/assets/{images-C0XvUYMb.js → images-scfkWZiK.js} +1 -1
  162. package/core/built/admin/assets/{inbox-DZXDUt4s.js → inbox-Mcp4DXZN.js} +14 -14
  163. package/core/built/admin/assets/index-6MkPdCtr.js +4 -0
  164. package/core/built/admin/assets/index-Bn7QhcZu.css +2 -0
  165. package/core/built/admin/assets/index.es-CNnuNH0d.js +1 -0
  166. package/core/built/admin/assets/{inline-Cw-gigDW.js → inline-BWSs_VzR.js} +1 -1
  167. package/core/built/admin/assets/{input-group-BPAxETpQ.js → input-group-CMhe2DvY.js} +1 -1
  168. package/core/built/admin/assets/{input-surface-BdOe4KzO.js → input-surface-BsrIZeSF.js} +1 -1
  169. package/core/built/admin/assets/{integration-header-B4DyXV06.js → integration-header-Bm6IDb1A.js} +1 -1
  170. package/core/built/admin/assets/invite-user-modal-DfheMXs0.js +1 -0
  171. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
  172. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
  173. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  174. package/core/built/admin/assets/{koenig-lexical-60O_8aiO.js → koenig-lexical-DBSqAuiI.js} +3 -3
  175. package/core/built/admin/assets/koenig-loader-aFQNlJlD.js +2 -0
  176. package/core/built/admin/assets/kpi-card-DBRMfGOW.js +1 -0
  177. package/core/built/admin/assets/{kpi-card-fUHZlzBX.js → kpi-card-DFafD1qq.js} +1 -1
  178. package/core/built/admin/assets/kpi-helpers-Cv8i8hns.js +1 -0
  179. package/core/built/admin/assets/kpi-tabs-BJItvLYm.js +1 -0
  180. package/core/built/admin/assets/{label-VIG969IC.js → label-BnSCvffu.js} +1 -1
  181. package/core/built/admin/assets/label-picker-KVoo91sh.js +1 -0
  182. package/core/built/admin/assets/layout-Bjv2Ll-5.js +1 -0
  183. package/core/built/admin/assets/{link-helpers-Dtq9fxQg.js → link-helpers-MVDdnFCY.js} +1 -1
  184. package/core/built/admin/assets/{list-page-CdsnQR9N.js → list-page-BucXJ0hi.js} +1 -1
  185. package/core/built/admin/assets/member-custom-fields-DDQV6QeG.js +1 -0
  186. package/core/built/admin/assets/member-detail-CdJF6Agw.js +1 -0
  187. package/core/built/admin/assets/members-DjQbq9Z2.js +4 -0
  188. package/core/built/admin/assets/{modal-page-BMTzFHVO.js → modal-page-xCivTMvI.js} +1 -1
  189. package/core/built/admin/assets/moderation-AgCIEso4.js +1 -0
  190. package/core/built/admin/assets/{multi-select-combobox-CGohnsxJ.js → multi-select-combobox-BcITkUVr.js} +1 -1
  191. package/core/built/admin/assets/navigation-modal-BkT7b1M2.js +1 -0
  192. package/core/built/admin/assets/newsletter-BMMAuvgq.js +1 -0
  193. package/core/built/admin/assets/newsletter-detail-modal-0SCJ7Zpm.js +1 -0
  194. package/core/built/admin/assets/{newsletter-emails-D5ql1rud.js → newsletter-emails-DKzwafuh.js} +1 -1
  195. package/core/built/admin/assets/newsletters-BRBb_uQC.js +1 -0
  196. package/core/built/admin/assets/note-DyGHtS9a.js +1 -0
  197. package/core/built/admin/assets/notifications-ZgWniKna.js +1 -0
  198. package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
  199. package/core/built/admin/assets/offers-container-modal-B-E8TIWr.js +1 -0
  200. package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-CzIsre-d.js} +1 -1
  201. package/core/built/admin/assets/onboarding-qg8Akovm.js +1 -0
  202. package/core/built/admin/assets/{onboarding-route-Cu_ROWPn.js → onboarding-route-CaavZulg.js} +1 -1
  203. package/core/built/admin/assets/overview-BW8GLeYi.js +1 -0
  204. package/core/built/admin/assets/overview-BkXZNzaZ.js +1 -0
  205. package/core/built/admin/assets/{page-header-Cfds8pCg.js → page-header-De0VzKBi.js} +1 -1
  206. package/core/built/admin/assets/pagemenu-B5KKCpbA.js +1 -0
  207. package/core/built/admin/assets/pages-jgaFm69d.js +1 -0
  208. package/core/built/admin/assets/pages-route-CIUAQxtY.js +1 -0
  209. package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
  210. package/core/built/admin/assets/{pintura-modal-TDTrJ89x.js → pintura-modal-BZ2J9w3n.js} +1 -1
  211. package/core/built/admin/assets/portal-frame-B6Hr9wHc.js +1 -0
  212. package/core/built/admin/assets/portal-modal-D4ceei3t.js +1 -0
  213. package/core/built/admin/assets/post-analytics-header-BYCsT0GP.js +1 -0
  214. package/core/built/admin/assets/post-analytics-ot7f6pih.js +1 -0
  215. package/core/built/admin/assets/{post-analytics-provider-Cu3jNeFh.js → post-analytics-provider-Bo1gmYaP.js} +1 -1
  216. package/core/built/admin/assets/{post-share-modal-P1_M6o-H.js → post-share-modal-C-PaYZ_e.js} +1 -1
  217. package/core/built/admin/assets/posts-DuGazgTb.js +1 -0
  218. package/core/built/admin/assets/posts-list-screen-CBGGgjjj.js +2 -0
  219. package/core/built/admin/assets/posts-route-D6xmS7Vf.js +1 -0
  220. package/core/built/admin/assets/preferences-C5YJLp74.js +5 -0
  221. package/core/built/admin/assets/{preview-chrome-BOVO6_PE.js → preview-chrome-BljUBlOk.js} +1 -1
  222. package/core/built/admin/assets/{preview-modal-MlTjP8UU.js → preview-modal-BfeFqi5y.js} +1 -1
  223. package/core/built/admin/assets/profile-B8mx2yAu.js +1 -0
  224. package/core/built/admin/assets/{radio-group-CjtmsCPl.js → radio-group-DczlLKOn.js} +1 -1
  225. package/core/built/admin/assets/{router-provider-CJC58zTy.js → router-provider-B0gZyiGJ.js} +1 -1
  226. package/core/built/admin/assets/{schemas-CRsC53ls.js → schemas-DppqmpeJ.js} +2 -2
  227. package/core/built/admin/assets/select-cb0t_TAJ.js +1 -0
  228. package/core/built/admin/assets/settings-DZqxR0Da.js +1 -0
  229. package/core/built/admin/assets/settings-DvfTNdHQ.js +4 -0
  230. package/core/built/admin/assets/{settings-breadcrumbs-sLDNedBW.js → settings-breadcrumbs-DLzbRRSt.js} +1 -1
  231. package/core/built/admin/assets/{shade-app-F7WxOyfk-nufqw1hd.js → shade-app-CcS3f8MZ-vwURazk8.js} +2 -2
  232. package/core/built/admin/assets/share-modal-D2-Bz1_I.js +1 -0
  233. package/core/built/admin/assets/{skeleton-D7hwjdry.js → skeleton-Ce9GgUpf.js} +1 -1
  234. package/core/built/admin/assets/slack-modal-DYDTUria.js +1 -0
  235. package/core/built/admin/assets/sort-button-VVeQjjbu.js +1 -0
  236. package/core/built/admin/assets/{source-icon-BPsD5ees.js → source-icon-Ck5_5Kgq.js} +1 -1
  237. package/core/built/admin/assets/{stack-CIfOAAVf.js → stack-B2eszIiq.js} +1 -1
  238. package/core/built/admin/assets/stats-Rjmk5owg.js +1 -0
  239. package/core/built/admin/assets/stats-view-BGGmkmgv.js +1 -0
  240. package/core/built/admin/assets/{step-1-CMta6YFO.js → step-1-CsaBjeN4.js} +1 -1
  241. package/core/built/admin/assets/{step-2-BG04nh5q.js → step-2-D2vnxOOM.js} +1 -1
  242. package/core/built/admin/assets/{step-3-ZnMaVIPj.js → step-3-wBoLdGEb.js} +2 -2
  243. package/core/built/admin/assets/{stripe-button-DDoUKN5a.js → stripe-button-CDgLz0S0.js} +1 -1
  244. package/core/built/admin/assets/stripe-connect-modal-CSjMJetP.js +1 -0
  245. package/core/built/admin/assets/{switch-C9djUIMO.js → switch-CI4gLWqb.js} +1 -1
  246. package/core/built/admin/assets/{table-CrqQtkR2.js → table-Do6iQ83Q.js} +1 -1
  247. package/core/built/admin/assets/{tabs-CGisSbWq.js → tabs-D2yWLMp_.js} +1 -1
  248. package/core/built/admin/assets/tag-detail-BhXlOsCa.js +2 -0
  249. package/core/built/admin/assets/tags-ldukRApe.js +1 -0
  250. package/core/built/admin/assets/testimonials-modal-CtnZBJKl.js +1 -0
  251. package/core/built/admin/assets/{text-DU9Hv33_.js → text-BQDSDsKs.js} +1 -1
  252. package/core/built/admin/assets/{textarea-d9qEkMOP.js → textarea-DJ1Q5V39.js} +1 -1
  253. package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +1 -0
  254. package/core/built/admin/assets/{toggle-group-CtKZURJd.js → toggle-group-ByUJsxwD.js} +1 -1
  255. package/core/built/admin/assets/{topic-filter-D8JT8Tq1.js → topic-filter-BgC3g5_v.js} +1 -1
  256. package/core/built/admin/assets/{transistor-modal-6PUf0idx.js → transistor-modal-Drr0SNfo.js} +1 -1
  257. package/core/built/admin/assets/trend-badge-6ye93YAW.js +1 -0
  258. package/core/built/admin/assets/{unsplash-modal-BPuDBPja.js → unsplash-modal-p6AoQoWp.js} +1 -1
  259. package/core/built/admin/assets/{use-analytics-data--opuzwcz.js → use-analytics-data-CWCMAESo.js} +1 -1
  260. package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
  261. package/core/built/admin/assets/use-check-theme-limit-error-Cw3WQHy8.js +2 -0
  262. package/core/built/admin/assets/use-filter-params-BIni9taJ.js +1 -0
  263. package/core/built/admin/assets/use-growth-stats-DCVG3s9w.js +1 -0
  264. package/core/built/admin/assets/{use-limiter-TDSNiHPB.js → use-limiter-D2WRRx0H.js} +1 -1
  265. package/core/built/admin/assets/{use-navigate-with-base-path-CK989MlC.js → use-navigate-with-base-path-BHPA228f.js} +1 -1
  266. package/core/built/admin/assets/{use-pintura-config-CnCGrDFk.js → use-pintura-config-h-J0Lvta.js} +1 -1
  267. package/core/built/admin/assets/{use-pintura-editor-ntphvtUd.js → use-pintura-editor-BfN1UwzH.js} +1 -1
  268. package/core/built/admin/assets/use-post-referrers-Czg47m8s.js +1 -0
  269. package/core/built/admin/assets/use-reply-chain-data-ns0caK8k.js +1 -0
  270. package/core/built/admin/assets/{use-router-history-entry-BwfQS2mq.js → use-router-history-entry-uldn7zJO.js} +1 -1
  271. package/core/built/admin/assets/{use-setting-group-DQxV42-O.js → use-setting-group-DpcuCUDg.js} +1 -1
  272. package/core/built/admin/assets/use-settings-navigation-CZjGrhsp.js +1 -0
  273. package/core/built/admin/assets/{use-simple-pagination-B2TdNX67.js → use-simple-pagination-DzJWobPR.js} +1 -1
  274. package/core/built/admin/assets/{use-staff-users-QrR9voeC.js → use-staff-users-Csipb-O0.js} +1 -1
  275. package/core/built/admin/assets/use-tinybird-query-CSnGXzZh.js +1 -0
  276. package/core/built/admin/assets/use-tinybird-token-DTOKRR7e.js +1 -0
  277. package/core/built/admin/assets/{use-unsaved-changes-guard-DpYJcj1d.js → use-unsaved-changes-guard-CBzs-KPi.js} +1 -1
  278. package/core/built/admin/assets/{use-url-input-WnIqckzS.js → use-url-input-DFr8lCbS.js} +1 -1
  279. package/core/built/admin/assets/user-detail-modal-B_iUClI6.js +1 -0
  280. package/core/built/admin/assets/users-Cg-OeGzC.js +1 -0
  281. package/core/built/admin/assets/{virtual-list-D3MfPNOh.js → virtual-list-BW-padMe.js} +1 -1
  282. package/core/built/admin/assets/web-C1v33ehA.js +2 -0
  283. package/core/built/admin/assets/web-C4BKzn2T.js +1 -0
  284. package/core/built/admin/assets/{zapier-modal-BO6PS_Vd.js → zapier-modal-BBFfI6Ml.js} +1 -1
  285. package/core/built/admin/index.html +24 -30
  286. package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
  287. package/core/frontend/helpers/cancel_link.js +2 -2
  288. package/core/frontend/helpers/pagination.js +2 -2
  289. package/core/frontend/helpers/social_accounts.js +2 -2
  290. package/core/frontend/public/ghost.css +1 -1
  291. package/core/frontend/public/ghost.min.css +1 -1
  292. package/core/frontend/services/rendering/renderer.js +15 -0
  293. package/core/frontend/services/sitemap/user-map-generator.js +9 -2
  294. package/core/server/adapters/storage/LocalStorageBase.js +8 -5
  295. package/core/server/api/endpoints/db.js +19 -5
  296. package/core/server/api/endpoints/index.js +6 -2
  297. package/core/server/api/endpoints/mail.js +1 -1
  298. package/core/server/api/endpoints/member-metafields.js +89 -0
  299. package/core/server/api/endpoints/members.js +4 -4
  300. package/core/server/api/endpoints/posts.js +4 -3
  301. package/core/server/api/endpoints/tiers-checkout-config.js +59 -0
  302. package/core/server/api/endpoints/utils/serializers/input/members.js +4 -7
  303. package/core/server/api/endpoints/utils/serializers/output/config.js +1 -0
  304. package/core/server/api/endpoints/utils/serializers/output/index.js +6 -2
  305. package/core/server/api/endpoints/utils/serializers/output/{member-custom-fields.js → member-metafields.js} +2 -4
  306. package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
  307. package/core/server/api/endpoints/utils/serializers/output/tiers-checkout-config.js +12 -0
  308. package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
  309. package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
  310. package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
  311. package/core/server/data/exporter/table-lists.js +3 -0
  312. package/core/server/data/importer/content-files.js +57 -0
  313. package/core/server/data/importer/handlers/image.js +2 -2
  314. package/core/server/data/importer/import-archive.js +131 -0
  315. package/core/server/data/importer/import-manager.js +18 -180
  316. package/core/server/data/importer/importers/content-file-importer.js +66 -4
  317. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  318. package/core/server/data/migrations/utils/migrations.js +1 -1
  319. package/core/server/data/migrations/versions/6.61/2026-08-19-14-30-20-add-written-by-to-members-custom-field-values.js +42 -0
  320. package/core/server/data/migrations/versions/6.61/2026-08-19-14-38-53-add-members-custom-field-bindings-table.js +26 -0
  321. package/core/server/data/migrations/versions/6.61/2026-08-19-14-48-06-add-tier-checkout-field-tables.js +35 -0
  322. package/core/server/data/schema/schema.js +90 -0
  323. package/core/server/data/seeders/importers/automation-action-revisions-importer.js +3 -3
  324. package/core/server/data/seeders/importers/automation-actions-importer.js +3 -3
  325. package/core/server/data/seeders/importers/automation-run-steps-importer.js +3 -3
  326. package/core/server/data/seeders/importers/automation-runs-importer.js +5 -5
  327. package/core/server/data/seeders/importers/automations-importer.js +3 -3
  328. package/core/server/data/seeders/importers/comment-reports-importer.js +1 -1
  329. package/core/server/data/seeders/importers/comments-importer.js +1 -1
  330. package/core/server/data/seeders/importers/email-batches-importer.js +1 -1
  331. package/core/server/data/seeders/importers/email-recipients-importer.js +1 -1
  332. package/core/server/data/seeders/importers/emails-importer.js +1 -1
  333. package/core/server/data/seeders/importers/labels-importer.js +1 -1
  334. package/core/server/data/seeders/importers/members-click-events-importer.js +1 -1
  335. package/core/server/data/seeders/importers/members-created-events-importer.js +1 -1
  336. package/core/server/data/seeders/importers/members-feedback-importer.js +1 -1
  337. package/core/server/data/seeders/importers/members-importer.js +1 -1
  338. package/core/server/data/seeders/importers/members-login-events-importer.js +1 -1
  339. package/core/server/data/seeders/importers/members-products-importer.js +1 -1
  340. package/core/server/data/seeders/importers/members-status-events-importer.js +1 -1
  341. package/core/server/data/seeders/importers/members-stripe-customers-importer.js +1 -1
  342. package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +1 -1
  343. package/core/server/data/seeders/importers/members-subscribe-events-importer.js +1 -1
  344. package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +1 -1
  345. package/core/server/data/seeders/importers/offer-redemptions-importer.js +1 -1
  346. package/core/server/data/seeders/importers/offers-importer.js +1 -1
  347. package/core/server/data/seeders/importers/posts-importer.js +1 -1
  348. package/core/server/data/seeders/importers/table-importer.js +2 -2
  349. package/core/server/data/seeders/importers/tags-importer.js +1 -1
  350. package/core/server/data/seeders/importers/users-importer.js +1 -1
  351. package/core/server/data/seeders/importers/web-mentions-importer.js +1 -1
  352. package/core/server/data/seeders/utils/random.js +3 -3
  353. package/core/server/ghost-server.js +3 -2
  354. package/core/server/lib/db-types/boolean.js +18 -0
  355. package/core/server/lib/image/image-size.js +24 -0
  356. package/core/server/lib/package-json/parse.js +2 -2
  357. package/core/server/lib/promise-pool.js +31 -0
  358. package/core/server/models/member.js +6 -17
  359. package/core/server/models/post.js +2 -2
  360. package/core/server/models/relations/authors.js +2 -16
  361. package/core/server/models/user.js +9 -2
  362. package/core/server/services/auth/passwordreset.js +13 -0
  363. package/core/server/services/automations/database-automations-repository.js +26 -26
  364. package/core/server/services/automations/poll.js +1 -0
  365. package/core/server/services/comments/comments-controller.js +30 -9
  366. package/core/server/services/comments/comments-service.js +55 -5
  367. package/core/server/services/content-import/csv/formula.js +12 -0
  368. package/core/server/services/content-import/csv/index.js +6 -1
  369. package/core/server/services/content-import/csv/parse.js +27 -6
  370. package/core/server/services/content-import/csv/serialize.js +13 -0
  371. package/core/server/services/content-import/import/assets.js +74 -0
  372. package/core/server/services/content-import/import/completion-email.js +164 -0
  373. package/core/server/services/content-import/import/errors-file.js +36 -0
  374. package/core/server/services/content-import/import/importer.js +204 -54
  375. package/core/server/services/content-import/import/local-media-url.js +63 -0
  376. package/core/server/services/content-import/import/media.js +254 -0
  377. package/core/server/services/content-import/import/post-data.js +1 -1
  378. package/core/server/services/content-import/import/post-link.js +11 -0
  379. package/core/server/services/content-import/import/post-repository.js +100 -0
  380. package/core/server/services/content-import/import/reader.js +9 -2
  381. package/core/server/services/content-import/import/relations.js +149 -0
  382. package/core/server/services/content-import/import/report.js +34 -0
  383. package/core/server/services/content-import/import/row.js +11 -2
  384. package/core/server/services/content-import/import/schema.js +30 -0
  385. package/core/server/services/content-import/import/source.js +125 -0
  386. package/core/server/services/content-import/import/staged-file.js +29 -0
  387. package/core/server/services/content-import/import/store.js +25 -2
  388. package/core/server/services/content-import/index.js +58 -34
  389. package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
  390. package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
  391. package/core/server/services/custom-redirects/redirects-service.js +1 -1
  392. package/core/server/services/custom-redirects/validation.js +1 -1
  393. package/core/server/services/email-address/email-address-parser.js +30 -38
  394. package/core/server/services/email-address/email-address-service.js +37 -4
  395. package/core/server/services/email-analytics/email-analytics-service.js +8 -1
  396. package/core/server/services/email-analytics/index.js +2 -7
  397. package/core/server/services/email-analytics/lib/queries.js +7 -1
  398. package/core/server/services/email-service/batch-sending-service.js +0 -4
  399. package/core/server/services/email-service/email-renderer.js +14 -4
  400. package/core/server/services/email-service/email-service-wrapper.js +0 -9
  401. package/core/server/services/email-service/mailgun-email-provider.js +20 -9
  402. package/core/server/services/gift-links/schema.js +3 -3
  403. package/core/server/services/gifts/CONTEXT.md +1 -1
  404. package/core/server/services/gifts/constants.js +1 -1
  405. package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
  406. package/core/server/services/gifts/gift-bookshelf-repository.js +2 -2
  407. package/core/server/services/gifts/gift-delivery-bookshelf-repository.js +18 -9
  408. package/core/server/services/gifts/gift-delivery-schema.js +5 -5
  409. package/core/server/services/gifts/gift-delivery-service.js +4 -0
  410. package/core/server/services/gifts/gift-email-service.js +0 -1
  411. package/core/server/services/gifts/gift-schema.js +10 -10
  412. package/core/server/services/gifts/gift-service.js +4 -2
  413. package/core/server/services/gifts/index.js +3 -3
  414. package/core/server/services/gifts/jobs/index.js +4 -4
  415. package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
  416. package/core/server/services/invitations/accept.js +4 -2
  417. package/core/server/services/jobs/job-service.js +0 -9
  418. package/core/server/services/jobs-service/register-job-handlers.js +25 -15
  419. package/core/server/services/lib/mailgun-client.js +44 -8
  420. package/core/server/services/mail/ghost-mailer.js +4 -4
  421. package/core/server/services/media-inliner/external-media-inliner-job.js +12 -0
  422. package/core/server/services/media-inliner/external-media-inliner.js +103 -29
  423. package/core/server/services/media-inliner/service.js +13 -41
  424. package/core/server/services/media-inliner/types.js +2 -0
  425. package/core/server/services/member-welcome-emails/service.js +7 -7
  426. package/core/server/services/members/api.js +1 -0
  427. package/core/server/services/members/import-export/csv/parse.js +0 -7
  428. package/core/server/services/members/import-export/export/exporter.js +4 -6
  429. package/core/server/services/members/import-export/import/completion-email.js +2 -5
  430. package/core/server/services/members/import-export/import/importer.js +21 -5
  431. package/core/server/services/members/import-export/import/row.js +0 -3
  432. package/core/server/services/members/import-export/import/stripe-utils.js +6 -1
  433. package/core/server/services/members/import-export/index.js +10 -12
  434. package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
  435. package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
  436. package/core/server/services/members/jobs/index.js +48 -24
  437. package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
  438. package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
  439. package/core/server/services/members/members-api/members-api.js +9 -6
  440. package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
  441. package/core/server/services/members/members-api/services/member-bread-service.js +53 -63
  442. package/core/server/services/members/members-api/services/payments-service.js +47 -1
  443. package/core/server/services/members/service.js +1 -5
  444. package/core/server/services/members-custom-fields/actions.js +27 -1
  445. package/core/server/services/members-custom-fields/bindings-service.js +120 -0
  446. package/core/server/services/members-custom-fields/codec.js +3 -4
  447. package/core/server/services/members-custom-fields/definitions-service.js +165 -22
  448. package/core/server/services/members-custom-fields/filter.js +75 -93
  449. package/core/server/services/members-custom-fields/index.js +11 -4
  450. package/core/server/services/members-custom-fields/key.js +2 -1
  451. package/core/server/services/members-custom-fields/models.js +1 -1
  452. package/core/server/services/members-custom-fields/queries.js +5 -0
  453. package/core/server/services/members-custom-fields/schema.js +37 -6
  454. package/core/server/services/members-custom-fields/serializers.js +3 -5
  455. package/core/server/services/members-custom-fields/values-service.js +65 -31
  456. package/core/server/services/mentions/mention-controller.js +23 -21
  457. package/core/server/services/mentions/process-webmention-job.js +16 -0
  458. package/core/server/services/mentions/service.js +8 -4
  459. package/core/server/services/public-config/config.js +7 -0
  460. package/core/server/services/route-settings/validation-errors.js +1 -1
  461. package/core/server/services/route-settings/yaml-parser.js +1 -1
  462. package/core/server/services/settings/settings-service.js +1 -8
  463. package/core/server/services/settings-helpers/settings-helpers.js +4 -6
  464. package/core/server/services/slack-ping/slack-ping-service.js +1 -1
  465. package/core/server/services/staff/staff-service-emails.js +2 -2
  466. package/core/server/services/stripe/config.js +14 -8
  467. package/core/server/services/stripe/service.js +10 -1
  468. package/core/server/services/stripe/services/checkout/completed-session.js +68 -0
  469. package/core/server/services/stripe/services/checkout/session-options.js +100 -0
  470. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +71 -1
  471. package/core/server/services/stripe/stripe-api.js +31 -0
  472. package/core/server/services/stripe/stripe-service.js +26 -9
  473. package/core/server/services/stripe/webhook-controller.js +10 -0
  474. package/core/server/services/tier-checkout-config/codec.js +99 -0
  475. package/core/server/services/tier-checkout-config/index.js +26 -0
  476. package/core/server/services/tier-checkout-config/models.js +63 -0
  477. package/core/server/services/tier-checkout-config/queries.js +80 -0
  478. package/core/server/services/tier-checkout-config/schema.js +33 -0
  479. package/core/server/services/tier-checkout-config/serializers.js +128 -0
  480. package/core/server/services/tier-checkout-config/service.js +304 -0
  481. package/core/server/services/tiers/service.js +21 -0
  482. package/core/server/services/update-check/index.js +13 -13
  483. package/core/server/services/update-check/jobs/update-check-job.js +7 -0
  484. package/core/server/services/update-check/update-check-service.js +2 -2
  485. package/core/server/web/admin/controller.js +1 -1
  486. package/core/server/web/api/endpoints/admin/routes.js +34 -20
  487. package/core/server/web/api/middleware/upload.js +2 -2
  488. package/core/server/web/parent/app.js +5 -0
  489. package/core/server/web/parent/middleware/filter-query-parameters.js +94 -0
  490. package/core/server/web/parent/middleware/index.js +1 -0
  491. package/core/server/web/query-parameter-policy/index.js +9 -0
  492. package/core/server/web/query-parameter-policy/policy.json +58 -0
  493. package/core/server/web/query-parameter-policy/schema.js +38 -0
  494. package/core/shared/config/defaults.json +3 -0
  495. package/core/shared/config/env/config.testing-mysql.json +4 -1
  496. package/core/shared/config/env/config.testing.json +3 -0
  497. package/core/shared/config/overrides.json +4 -2
  498. package/core/shared/labs.js +9 -15
  499. package/package.json +25 -25
  500. package/pnpm-lock.yaml +741 -108
  501. package/pnpm-workspace.yaml +12 -9
  502. package/tsconfig.json +2 -3
  503. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  504. package/core/built/admin/assets/Combination-gnJO3vIw.js +0 -41
  505. package/core/built/admin/assets/account-migration-8qTEI1i1.js +0 -1
  506. package/core/built/admin/assets/activitypub/inbox-DQ5CwLma.js +0 -1284
  507. package/core/built/admin/assets/activitypub/label-B72sfvEU.js +0 -16
  508. package/core/built/admin/assets/activitypub/layout-CXajhRsL.js +0 -1
  509. package/core/built/admin/assets/activitypub/settings-71gCm3SO.js +0 -315
  510. package/core/built/admin/assets/add-integration-modal--YpTq3c0.js +0 -1
  511. package/core/built/admin/assets/add-newsletter-modal-C8Ix2hol.js +0 -1
  512. package/core/built/admin/assets/add-recommendation-modal-CScuNFz4.js +0 -1
  513. package/core/built/admin/assets/alert-dialog-wEbVxANM.js +0 -1
  514. package/core/built/admin/assets/analytics-Cnji45H5.js +0 -1
  515. package/core/built/admin/assets/app-utils-D2Wp7ZSS.js +0 -1
  516. package/core/built/admin/assets/audience-DTLMXAFH.js +0 -1
  517. package/core/built/admin/assets/automations-BWpRCZ_f.js +0 -1
  518. package/core/built/admin/assets/bluesky-sharing-DHOpQxff.js +0 -1
  519. package/core/built/admin/assets/chart-helpers-B3OqQ6Ez.js +0 -1
  520. package/core/built/admin/assets/color-picker-Bmo1r9Fc.js +0 -3
  521. package/core/built/admin/assets/color-picker-field-DywowPhF.js +0 -1
  522. package/core/built/admin/assets/combobox-C4QCh6Yw.js +0 -1
  523. package/core/built/admin/assets/command-DcLbSifC.js +0 -1
  524. package/core/built/admin/assets/comments-Bxy_3WyE.js +0 -1
  525. package/core/built/admin/assets/confirmation-context-CLFHhyyH.js +0 -1
  526. package/core/built/admin/assets/custom-field-type-option-D0PXoSnP.js +0 -10
  527. package/core/built/admin/assets/custom-integration-modal-DCIHKN33.js +0 -1
  528. package/core/built/admin/assets/design-and-theme-modal-CZ-PkW7o.js +0 -23
  529. package/core/built/admin/assets/dialog-Db7c164G.js +0 -1
  530. package/core/built/admin/assets/dirty-confirm-dialog-CmARpZQS.js +0 -1
  531. package/core/built/admin/assets/dist-QLZuGq7o2.js +0 -1
  532. package/core/built/admin/assets/domain-D0SAtc-T.js +0 -1
  533. package/core/built/admin/assets/dropzone-CaPOeDRZ.js +0 -5
  534. package/core/built/admin/assets/edit-profile-By7v5XW5.js +0 -1
  535. package/core/built/admin/assets/editor-COXn4Atu.js +0 -8
  536. package/core/built/admin/assets/explore-BsNYrubV.js +0 -1
  537. package/core/built/admin/assets/feed-8RR1O1bK.js +0 -1
  538. package/core/built/admin/assets/filter-sources-4C0kF1NU.js +0 -1
  539. package/core/built/admin/assets/filters-CV5jCb9n.js +0 -1
  540. package/core/built/admin/assets/filters-Dmr0PoqU.js +0 -1
  541. package/core/built/admin/assets/first-promoter-modal-OCzSaL3B.js +0 -1
  542. package/core/built/admin/assets/gift-link-modal-0mzjn5oF.js +0 -1
  543. package/core/built/admin/assets/growth-55vWlGT_.js +0 -1
  544. package/core/built/admin/assets/growth-DA5AluYw.js +0 -3
  545. package/core/built/admin/assets/history-modal-G1s5hHz7.js +0 -1
  546. package/core/built/admin/assets/html-field-BegxsWpw.js +0 -1
  547. package/core/built/admin/assets/index-CDP9tIOk.js +0 -4
  548. package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
  549. package/core/built/admin/assets/index.es-BMUCj9TR.js +0 -1
  550. package/core/built/admin/assets/input-UHrKuvBT.js +0 -1
  551. package/core/built/admin/assets/invite-user-modal-BrAkxEO3.js +0 -1
  552. package/core/built/admin/assets/koenig-loader-DwVY_V-H.js +0 -1
  553. package/core/built/admin/assets/kpi-card-LERqWBoY.js +0 -1
  554. package/core/built/admin/assets/kpi-helpers-DB3ouhYF.js +0 -1
  555. package/core/built/admin/assets/kpi-tabs-BGvtMD8S.js +0 -1
  556. package/core/built/admin/assets/label-picker-BBWykUeA.js +0 -1
  557. package/core/built/admin/assets/layout-Di5K7doM.js +0 -1
  558. package/core/built/admin/assets/loading-indicator-SFTqyYVE.js +0 -1
  559. package/core/built/admin/assets/member-custom-fields-gOv6Hoh3.js +0 -1
  560. package/core/built/admin/assets/member-detail-D7mZDDp3.js +0 -1
  561. package/core/built/admin/assets/member-route-0Aa52Ntz.js +0 -1
  562. package/core/built/admin/assets/members-DvZG9t69.js +0 -2
  563. package/core/built/admin/assets/moderation-DzzPLDyl.js +0 -1
  564. package/core/built/admin/assets/navigation-modal-CI8Bx5vn.js +0 -1
  565. package/core/built/admin/assets/newsletter-Bg3cq5U-.js +0 -1
  566. package/core/built/admin/assets/newsletter-detail-modal-DQU3r4g2.js +0 -1
  567. package/core/built/admin/assets/newsletters-DMDfZbMS.js +0 -1
  568. package/core/built/admin/assets/note-i8k6pjaw.js +0 -1
  569. package/core/built/admin/assets/notifications-psA_2Ph4.js +0 -1
  570. package/core/built/admin/assets/offers-container-modal-BWfjSdyg.js +0 -1
  571. package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
  572. package/core/built/admin/assets/overview-C-6xOLaf.js +0 -1
  573. package/core/built/admin/assets/overview-DaLhpRrC.js +0 -1
  574. package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
  575. package/core/built/admin/assets/popover-CFgqFDvC.js +0 -1
  576. package/core/built/admin/assets/portal-frame-DjBF-uy2.js +0 -1
  577. package/core/built/admin/assets/portal-modal-Cf0pBAk8.js +0 -1
  578. package/core/built/admin/assets/post-analytics-Buz1COoY.js +0 -1
  579. package/core/built/admin/assets/post-analytics-header-B-P0eFnT.js +0 -1
  580. package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
  581. package/core/built/admin/assets/preferences-Cq1aOiLy.js +0 -5
  582. package/core/built/admin/assets/profile-D6dHYf2o.js +0 -1
  583. package/core/built/admin/assets/select-D_RQaXgt.js +0 -1
  584. package/core/built/admin/assets/settings-B5hJKZ5C.js +0 -1
  585. package/core/built/admin/assets/settings-DIo_F-MF.js +0 -4
  586. package/core/built/admin/assets/share-modal-CLBfj377.js +0 -1
  587. package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
  588. package/core/built/admin/assets/slack-modal-Bt9I_tEo.js +0 -1
  589. package/core/built/admin/assets/sort-button-DMBXF7tP.js +0 -1
  590. package/core/built/admin/assets/stats-B_YkF7bp.js +0 -1
  591. package/core/built/admin/assets/stats-view-BOCp9RG8.js +0 -1
  592. package/core/built/admin/assets/stripe-connect-modal-BeSukI8q.js +0 -1
  593. package/core/built/admin/assets/tag-detail-2a3BfzTW.js +0 -2
  594. package/core/built/admin/assets/tags-Dp2_8UzL.js +0 -1
  595. package/core/built/admin/assets/testimonials-modal-C9nrypNo.js +0 -1
  596. package/core/built/admin/assets/tier-detail-modal-CxRwgTPR.js +0 -1
  597. package/core/built/admin/assets/use-check-theme-limit-error-C9-QhGdV.js +0 -1
  598. package/core/built/admin/assets/use-filter-params-CSpAvgD2.js +0 -1
  599. package/core/built/admin/assets/use-growth-stats-BOmoPDHJ.js +0 -1
  600. package/core/built/admin/assets/use-post-referrers-CbXLFIex.js +0 -1
  601. package/core/built/admin/assets/use-reply-chain-data-JYFKSO83.js +0 -1
  602. package/core/built/admin/assets/use-settings-navigation-BBzro2-V.js +0 -1
  603. package/core/built/admin/assets/use-tinybird-query-D2Aeoty5.js +0 -39
  604. package/core/built/admin/assets/use-tinybird-token-DBuwMmln.js +0 -1
  605. package/core/built/admin/assets/user-detail-modal-59mBJqxN.js +0 -1
  606. package/core/built/admin/assets/users-5msE1WMs.js +0 -1
  607. package/core/built/admin/assets/web-DUuX7nE2.js +0 -2
  608. package/core/built/admin/assets/web-N8ucs2aG.js +0 -1
  609. package/core/server/api/endpoints/member-custom-fields.js +0 -100
  610. package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
  611. package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
  612. package/core/server/services/update-check/run-update-check.js +0 -63
  613. /package/core/server/lib/{db-date.js → db-types/date.js} +0 -0
@@ -11,6 +11,7 @@ const mail = require('../mail');
11
11
 
12
12
  const messages = {
13
13
  userNotFound: 'User not found.',
14
+ userSuspended: 'This account has been suspended.',
14
15
  resetPassword: 'Reset Password',
15
16
  expired: {
16
17
  message: 'Cannot reset password.',
@@ -46,6 +47,14 @@ function generateToken(email, settingsAPI, transaction) {
46
47
  throw new errors.NotFoundError({ message: tpl(messages.userNotFound) });
47
48
  }
48
49
 
50
+ // Prevent suspended users from generating a reset token. This same check must appear
51
+ // below in doReset() to account for password reset tokens that were generated prior
52
+ // to suspension since they have a 24-hour lifetime.
53
+ // Locked users must still be able to recover access by resetting their password.
54
+ if (user.isInactive()) {
55
+ throw new errors.NoPermissionError({ message: tpl(messages.userSuspended) });
56
+ }
57
+
49
58
  token = security.tokens.resetToken.generateHash({
50
59
  expires: moment().add(1, 'days').valueOf(),
51
60
  email: email,
@@ -128,6 +137,10 @@ function doReset(options, tokenParts, settingsAPI) {
128
137
  }
129
138
  }
130
139
 
140
+ if (user.isInactive()) {
141
+ throw new errors.NoPermissionError({ message: tpl(messages.userSuspended) });
142
+ }
143
+
131
144
  const updatedUser = await models.User.changePassword(
132
145
  {
133
146
  oldPassword: oldPassword,
@@ -13,7 +13,7 @@ const dequal_1 = require("dequal");
13
13
  const lexical_1 = __importDefault(require("../../lib/lexical"));
14
14
  const url_utils_1 = __importDefault(require("../../../shared/url-utils"));
15
15
  const constants_1 = require("../member-welcome-emails/constants");
16
- const db_date_1 = require("../../lib/db-date");
16
+ const date_1 = require("../../lib/db-types/date");
17
17
  const stale_lock_cutoff_1 = require("./stale-lock-cutoff");
18
18
  const HOUR_MS = 60 * 60 * 1000;
19
19
  const DEFAULT_WELCOME_EMAIL_AUTOMATIONS = [
@@ -93,7 +93,7 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier, })
93
93
  const updatedAutomation = await updateAutomation(trx, {
94
94
  ...automation,
95
95
  status: data.status,
96
- updated_at: (0, db_date_1.toDatabaseDate)(now),
96
+ updated_at: (0, date_1.toDatabaseDate)(now),
97
97
  });
98
98
  await replaceAutomationGraph(trx, updatedAutomation.id, data.actions, data.edges);
99
99
  if (updatedAutomation.status === 'inactive') {
@@ -130,7 +130,7 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier, })
130
130
  .update({
131
131
  email_sent_count: trx.raw('COALESCE(??, 0) + ?', ['email_sent_count', 1]),
132
132
  });
133
- const now = (0, db_date_1.toDatabaseDate)(new Date());
133
+ const now = (0, date_1.toDatabaseDate)(new Date());
134
134
  await trx('automated_email_recipients').insert({
135
135
  id: (0, bson_objectid_1.default)().toHexString(),
136
136
  member_id: options.memberId,
@@ -281,7 +281,7 @@ async function ensureDefaultAutomations(trx) {
281
281
  }
282
282
  }
283
283
  async function ensureAutomation(trx, defaults) {
284
- const now = (0, db_date_1.toDatabaseDate)(new Date());
284
+ const now = (0, date_1.toDatabaseDate)(new Date());
285
285
  const id = (0, bson_objectid_1.default)().toHexString();
286
286
  await trx('automations')
287
287
  .insert({
@@ -313,7 +313,7 @@ async function ensureWelcomeEmailAction(trx, automationId) {
313
313
  if (!email) {
314
314
  return;
315
315
  }
316
- const now = (0, db_date_1.toDatabaseDate)(new Date());
316
+ const now = (0, date_1.toDatabaseDate)(new Date());
317
317
  const actionId = (0, bson_objectid_1.default)().toHexString();
318
318
  await insertActions(trx, [
319
319
  {
@@ -347,7 +347,7 @@ async function trigger(trx, options) {
347
347
  return;
348
348
  }
349
349
  const now = new Date();
350
- const nowString = (0, db_date_1.toDatabaseDate)(now);
350
+ const nowString = (0, date_1.toDatabaseDate)(now);
351
351
  const readyAt = getReadyAtForAction(firstAction, now, fakeWaitHoursMultiplier);
352
352
  const run = {
353
353
  id: (0, bson_objectid_1.default)().toHexString(),
@@ -366,14 +366,14 @@ async function trigger(trx, options) {
366
366
  });
367
367
  }
368
368
  async function insertRunStep(trx, { automationRunId, automationActionRevisionId, now, readyAt, }) {
369
- const nowString = (0, db_date_1.toDatabaseDate)(now);
369
+ const nowString = (0, date_1.toDatabaseDate)(now);
370
370
  await trx('automation_run_steps').insert({
371
371
  id: (0, bson_objectid_1.default)().toHexString(),
372
372
  created_at: nowString,
373
373
  updated_at: nowString,
374
374
  automation_run_id: automationRunId,
375
375
  automation_action_revision_id: automationActionRevisionId,
376
- ready_at: (0, db_date_1.toDatabaseDate)(readyAt),
376
+ ready_at: (0, date_1.toDatabaseDate)(readyAt),
377
377
  });
378
378
  }
379
379
  async function fetchAndLockSteps(trx, limit) {
@@ -388,9 +388,9 @@ async function fetchAndLockSteps(trx, limit) {
388
388
  // 2. Try to lock those rows.
389
389
  // 3. Select any rows we successfully locked.
390
390
  const now = new Date();
391
- const nowString = (0, db_date_1.toDatabaseDate)(now);
391
+ const nowString = (0, date_1.toDatabaseDate)(now);
392
392
  const staleLockCutoff = (0, stale_lock_cutoff_1.getStaleLockCutoff)(now);
393
- const staleLockCutoffString = (0, db_date_1.toDatabaseDate)(staleLockCutoff);
393
+ const staleLockCutoffString = (0, date_1.toDatabaseDate)(staleLockCutoff);
394
394
  const lockId = node_crypto_1.default.randomUUID();
395
395
  // 1. Select up to `limit` candidate rows.
396
396
  const candidates = await trx('automation_run_steps')
@@ -444,17 +444,17 @@ async function findNextPendingReadyAt(trx, staleLockCutoff) {
444
444
  .select({ next_ready_at: 'ready_at' })
445
445
  .where('status', 'pending')
446
446
  .where((builder) => {
447
- builder.whereNull('locked_by').orWhere('locked_at', '<', (0, db_date_1.toDatabaseDate)(staleLockCutoff));
447
+ builder.whereNull('locked_by').orWhere('locked_at', '<', (0, date_1.toDatabaseDate)(staleLockCutoff));
448
448
  })
449
449
  .orderBy('ready_at')
450
450
  .first();
451
- return row?.next_ready_at ? (0, db_date_1.fromDatabaseDate)(row.next_ready_at) : null;
451
+ return row?.next_ready_at ? (0, date_1.fromDatabaseDate)(row.next_ready_at) : null;
452
452
  }
453
453
  function buildStepToRun(row) {
454
454
  const base = {
455
455
  id: row.id,
456
456
  step_attempts: row.step_attempts,
457
- ready_at: (0, db_date_1.fromDatabaseDate)(row.ready_at),
457
+ ready_at: (0, date_1.fromDatabaseDate)(row.ready_at),
458
458
  locked_by: row.locked_by,
459
459
  automation_run_id: row.automation_run_id,
460
460
  automation_id: row.automation_id,
@@ -544,7 +544,7 @@ async function findNextActionRevision(trx, sourceActionId) {
544
544
  return row ?? null;
545
545
  }
546
546
  async function markStepTerminal(trx, step, status) {
547
- const nowString = (0, db_date_1.toDatabaseDate)(new Date());
547
+ const nowString = (0, date_1.toDatabaseDate)(new Date());
548
548
  return await updateStep(trx, step, {
549
549
  status,
550
550
  finished_at: nowString,
@@ -556,12 +556,12 @@ async function retryStep(trx, step, retryAt) {
556
556
  await markStepTerminal(trx, step, 'automation disabled');
557
557
  return false;
558
558
  }
559
- const nowString = (0, db_date_1.toDatabaseDate)(new Date());
559
+ const nowString = (0, date_1.toDatabaseDate)(new Date());
560
560
  return await updateStep(trx, step, {
561
561
  status: 'pending',
562
562
  started_at: null,
563
563
  finished_at: null,
564
- ready_at: (0, db_date_1.toDatabaseDate)(retryAt),
564
+ ready_at: (0, date_1.toDatabaseDate)(retryAt),
565
565
  updated_at: nowString,
566
566
  });
567
567
  }
@@ -586,8 +586,8 @@ function getReadyAtForAction(action, now, fakeWaitHoursMultiplier) {
586
586
  }
587
587
  }
588
588
  async function cancelCancelablePendingStepsForAutomation(trx, automationId, now) {
589
- const nowString = (0, db_date_1.toDatabaseDate)(now);
590
- const staleLockCutoff = (0, db_date_1.toDatabaseDate)((0, stale_lock_cutoff_1.getStaleLockCutoff)(now));
589
+ const nowString = (0, date_1.toDatabaseDate)(now);
590
+ const staleLockCutoff = (0, date_1.toDatabaseDate)((0, stale_lock_cutoff_1.getStaleLockCutoff)(now));
591
591
  await trx('automation_run_steps')
592
592
  .update({
593
593
  status: 'automation disabled',
@@ -707,7 +707,7 @@ async function replaceAutomationGraph(trx, automationId, submittedActions, edges
707
707
  revision.action_id,
708
708
  revision,
709
709
  ]));
710
- const now = (0, db_date_1.toDatabaseDate)(new Date());
710
+ const now = (0, date_1.toDatabaseDate)(new Date());
711
711
  const actionsToInsert = [];
712
712
  const revisionsToInsert = [];
713
713
  for (const action of actions) {
@@ -884,14 +884,14 @@ async function insertActionRevisions(trx, revisions) {
884
884
  }
885
885
  function getNextRevisionCreatedAt(latestCreatedAt, requestedCreatedAt) {
886
886
  if (!latestCreatedAt) {
887
- return (0, db_date_1.toDatabaseDate)(requestedCreatedAt);
887
+ return (0, date_1.toDatabaseDate)(requestedCreatedAt);
888
888
  }
889
- const requestedTime = (0, db_date_1.fromDatabaseDate)(requestedCreatedAt).getTime();
890
- const latestTime = (0, db_date_1.fromDatabaseDate)(latestCreatedAt).getTime();
889
+ const requestedTime = (0, date_1.fromDatabaseDate)(requestedCreatedAt).getTime();
890
+ const latestTime = (0, date_1.fromDatabaseDate)(latestCreatedAt).getTime();
891
891
  if (requestedTime > latestTime) {
892
- return (0, db_date_1.toDatabaseDate)(requestedCreatedAt);
892
+ return (0, date_1.toDatabaseDate)(requestedCreatedAt);
893
893
  }
894
- return (0, db_date_1.toDatabaseDate)(new Date(latestTime + 1000));
894
+ return (0, date_1.toDatabaseDate)(new Date(latestTime + 1000));
895
895
  }
896
896
  function buildActionRevision(actionId, action, createdAt) {
897
897
  switch (action.type) {
@@ -970,7 +970,7 @@ function buildAutomationBrowseResult(automation) {
970
970
  ...buildAutomationSummary(automation),
971
971
  stats: {
972
972
  last_run_created_at: automation.last_run_created_at
973
- ? (0, db_date_1.fromDatabaseDate)(automation.last_run_created_at)
973
+ ? (0, date_1.fromDatabaseDate)(automation.last_run_created_at)
974
974
  : null,
975
975
  total_run_count: Number(automation.total_run_count ?? 0),
976
976
  in_progress_run_count: Number(automation.in_progress_run_count ?? 0),
@@ -978,7 +978,7 @@ function buildAutomationBrowseResult(automation) {
978
978
  };
979
979
  }
980
980
  function serializeDate(date) {
981
- const normalizedDate = (0, db_date_1.fromDatabaseDate)(date);
981
+ const normalizedDate = (0, date_1.fromDatabaseDate)(date);
982
982
  normalizedDate.setMilliseconds(0);
983
983
  return normalizedDate.toISOString();
984
984
  }
@@ -119,6 +119,7 @@ const processStep = async ({ automationsApi, memberWelcomeEmailService, schedule
119
119
  subject: step.email_subject,
120
120
  },
121
121
  member: {
122
+ // Note that we don't use `automation_run.member_email` here. That's only for the historical record, not for functionality.
122
123
  email: member.get('email'),
123
124
  name: member.get('name'),
124
125
  uuid: member.get('uuid'),
@@ -14,6 +14,7 @@ const messages = {
14
14
  cannotDestroyComments: 'You cannot destroy comments.',
15
15
  memberNotFound: 'Unable to find member',
16
16
  unsupportedReportCountFilter: 'Unsupported count.reports filter',
17
+ errorParsingFilter: 'Error parsing filter',
17
18
  };
18
19
 
19
20
  module.exports = class CommentsController {
@@ -26,6 +27,16 @@ module.exports = class CommentsController {
26
27
  this.stats = stats;
27
28
  }
28
29
 
30
+ #getPostIdFromFilter(query) {
31
+ if (typeof query.post_id === 'string') {
32
+ return query.post_id;
33
+ }
34
+
35
+ // Only equality conditions required by an AND can scope a legacy browse.
36
+ // Choosing an ID from an OR or an exclusion would authorize the wrong posts.
37
+ return query.$and?.map((part) => this.#getPostIdFromFilter(part)).find(Boolean);
38
+ }
39
+
29
40
  #withPostFilter(options) {
30
41
  const nextOptions = { ...options };
31
42
 
@@ -138,7 +149,17 @@ module.exports = class CommentsController {
138
149
  * @param {Frame} frame
139
150
  */
140
151
  async browse(frame) {
141
- return await this.service.getComments(this.#withPostFilter(frame.options));
152
+ const options = { ...frame.options };
153
+ if (!options.post_id && options.filter) {
154
+ let query;
155
+ try {
156
+ query = nql(options.filter).parse();
157
+ } catch (err) {
158
+ throw new errors.BadRequestError({ message: tpl(messages.errorParsingFilter), err });
159
+ }
160
+ options.post_id = this.#getPostIdFromFilter(query);
161
+ }
162
+ return await this.service.getComments(this.#withPostFilter(options));
142
163
  }
143
164
 
144
165
  async adminBrowse(frame) {
@@ -345,14 +366,14 @@ module.exports = class CommentsController {
345
366
  async like(frame) {
346
367
  this.#checkMember(frame);
347
368
 
369
+ const comment = await this.service.getCommentByID(frame.options.id, frame.options);
370
+
348
371
  const result = await this.service.likeComment(
349
372
  frame.options.id,
350
373
  frame.options?.context?.member,
351
374
  frame.options,
352
375
  );
353
376
 
354
- const comment = await this.service.getCommentByID(frame.options.id, frame.options);
355
-
356
377
  this.setCacheInvalidationHeaders(comment, frame);
357
378
 
358
379
  return result;
@@ -364,14 +385,14 @@ module.exports = class CommentsController {
364
385
  async unlike(frame) {
365
386
  this.#checkMember(frame);
366
387
 
388
+ const comment = await this.service.getCommentByID(frame.options.id, frame.options);
389
+
367
390
  const result = await this.service.unlikeComment(
368
391
  frame.options.id,
369
392
  frame.options?.context?.member,
370
393
  frame.options,
371
394
  );
372
395
 
373
- const comment = await this.service.getCommentByID(frame.options.id, frame.options);
374
-
375
396
  this.setCacheInvalidationHeaders(comment, frame);
376
397
 
377
398
  return result;
@@ -420,14 +441,14 @@ module.exports = class CommentsController {
420
441
  async dislike(frame) {
421
442
  this.#checkMember(frame);
422
443
 
444
+ const comment = await this.service.getCommentByID(frame.options.id, frame.options);
445
+
423
446
  const result = await this.service.dislikeComment(
424
447
  frame.options.id,
425
448
  frame.options?.context?.member,
426
449
  frame.options,
427
450
  );
428
451
 
429
- const comment = await this.service.getCommentByID(frame.options.id, frame.options);
430
-
431
452
  this.setCacheInvalidationHeaders(comment, frame);
432
453
 
433
454
  return result;
@@ -439,14 +460,14 @@ module.exports = class CommentsController {
439
460
  async undislike(frame) {
440
461
  this.#checkMember(frame);
441
462
 
463
+ const comment = await this.service.getCommentByID(frame.options.id, frame.options);
464
+
442
465
  const result = await this.service.undislikeComment(
443
466
  frame.options.id,
444
467
  frame.options?.context?.member,
445
468
  frame.options,
446
469
  );
447
470
 
448
- const comment = await this.service.getCommentByID(frame.options.id, frame.options);
449
-
450
471
  this.setCacheInvalidationHeaders(comment, frame);
451
472
 
452
473
  return result;
@@ -13,7 +13,9 @@ const messages = {
13
13
  alreadyDisliked: 'This comment was disliked already',
14
14
  replyToReply: 'Can not reply to a reply',
15
15
  commentsNotEnabled: 'Comments are not enabled for this site.',
16
+ postIdRequired: 'A post ID is required to read comments.',
16
17
  cannotCommentOnPost: 'You do not have permission to comment on this post.',
18
+ cannotReadComment: 'You do not have permission to read comments on this post',
17
19
  cannotEditComment: 'You do not have permission to edit comments',
18
20
  cannotPinReply: 'Replies cannot be pinned',
19
21
  cannotPinDeletedComment: 'Deleted comments cannot be pinned',
@@ -39,7 +41,7 @@ const COMMENT_STATUSES_IN_REPLY_TO = [COMMENT_STATUS_PUBLISHED, COMMENT_STATUS_H
39
41
  // new `comment.get(...)` call has one obvious place to register its column.
40
42
  const REPLY_PARENT_REQUIRED_COLUMNS = ['parent_id', 'post_id'];
41
43
  const IN_REPLY_TO_REQUIRED_COLUMNS = ['parent_id'];
42
- const OWNERSHIP_REQUIRED_COLUMNS = ['member_id'];
44
+ const OWNERSHIP_REQUIRED_COLUMNS = ['member_id', 'post_id'];
43
45
  const REPORT_REQUIRED_COLUMNS = ['post_id', 'member_id', 'html', 'created_at'];
44
46
 
45
47
  function getColumnList(columns) {
@@ -167,11 +169,14 @@ class CommentsService {
167
169
  }
168
170
 
169
171
  /** @private */
170
- checkPostAccess(postModel, memberModel) {
171
- const access = this.contentGating.checkPostAccess(postModel.toJSON(), memberModel.toJSON());
172
+ checkPostAccess(postModel, memberModel, { action = 'comment' } = {}) {
173
+ const access = this.contentGating.checkPostAccess(
174
+ postModel.toJSON(),
175
+ memberModel ? memberModel.toJSON() : null,
176
+ );
172
177
  if (access === this.contentGating.BLOCK_ACCESS) {
173
178
  throw new errors.NoPermissionError({
174
- message: tpl(messages.cannotCommentOnPost),
179
+ message: tpl(action === 'read' ? messages.cannotReadComment : messages.cannotCommentOnPost),
175
180
  });
176
181
  }
177
182
  }
@@ -189,6 +194,32 @@ class CommentsService {
189
194
  });
190
195
  }
191
196
 
197
+ async #checkPostAccessForRead(postId, options) {
198
+ if (options.isAdmin) {
199
+ return;
200
+ }
201
+
202
+ if (!postId) {
203
+ throw new errors.ValidationError({ message: tpl(messages.postIdRequired) });
204
+ }
205
+
206
+ const postModel = await this.models.Post.findOne(
207
+ { id: postId },
208
+ { require: true, transacting: options.transacting, withRelated: ['tiers'] },
209
+ );
210
+
211
+ let memberModel = null;
212
+ const memberId = options.context?.member?.id;
213
+ if (memberId) {
214
+ memberModel = await this.models.Member.findOne(
215
+ { id: memberId },
216
+ { require: true, transacting: options.transacting, withRelated: ['products'] },
217
+ );
218
+ }
219
+
220
+ this.checkPostAccess(postModel, memberModel, { action: 'read' });
221
+ }
222
+
192
223
  /**
193
224
  * Primary comment lookup: a single keyed fetch with the allowed statuses
194
225
  * applied in the query (`WHERE id = ? AND status IN (...)`), optionally locked
@@ -520,6 +551,7 @@ class CommentsService {
520
551
  */
521
552
  async getComments(options) {
522
553
  this.checkEnabled();
554
+ await this.#checkPostAccessForRead(options.post_id, options);
523
555
  const page = await this.models.Comment.findPage(
524
556
  withPinnedSelect({ ...options, parentId: null, pinnedFirst: true }),
525
557
  );
@@ -659,6 +691,17 @@ class CommentsService {
659
691
  */
660
692
  async getReplies(id, options, { includeHidden = false } = {}) {
661
693
  this.checkEnabled();
694
+
695
+ const parentComment = await this.#fetchCommentByID(id, options, {
696
+ requiredColumns: ['post_id'],
697
+ });
698
+
699
+ if (!parentComment) {
700
+ throw new errors.NotFoundError({ message: tpl(messages.commentNotFound) });
701
+ }
702
+
703
+ await this.#checkPostAccessForRead(parentComment.get('post_id'), options);
704
+
662
705
  const page = await this.models.Comment.findPage(
663
706
  withPinnedSelect({ ...options, parentId: id }, { includeHidden }),
664
707
  );
@@ -740,7 +783,9 @@ class CommentsService {
740
783
  async getCommentByID(id, options = {}) {
741
784
  this.checkEnabled();
742
785
 
743
- return await this.#getReadableCommentByID(id, options);
786
+ const model = await this.#getReadableCommentByID(id, options, ['post_id']);
787
+ await this.#checkPostAccessForRead(model.get('post_id'), options);
788
+ return model;
744
789
  }
745
790
 
746
791
  /**
@@ -908,6 +953,9 @@ class CommentsService {
908
953
  });
909
954
  }
910
955
 
956
+ // Mutation responses include replies, so they require the same post access as reads.
957
+ await this.#checkPostAccessForRead(existingComment.get('post_id'), options);
958
+
911
959
  const model = await this.models.Comment.edit(
912
960
  {
913
961
  status: COMMENT_STATUS_DELETED,
@@ -943,6 +991,8 @@ class CommentsService {
943
991
  });
944
992
  }
945
993
 
994
+ await this.#checkPostAccessForRead(existingComment.get('post_id'), options);
995
+
946
996
  if (!comment) {
947
997
  return existingComment;
948
998
  }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stripFormulaGuard = stripFormulaGuard;
4
+ const FORMULA_TRIGGERS = ['=', '+', '-', '@', '\t', '\r'];
5
+ // Report files prefix formula-shaped cells with an apostrophe. Remove exactly
6
+ // that guard during re-import so repeated fixes do not change publisher data.
7
+ function stripFormulaGuard(cell) {
8
+ if (cell.charAt(0) === "'" && FORMULA_TRIGGERS.includes(cell.charAt(1))) {
9
+ return cell.slice(1);
10
+ }
11
+ return cell;
12
+ }
@@ -3,6 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.parse = void 0;
6
+ exports.stripFormulaGuard = exports.serialize = exports.parseWithSource = exports.parse = void 0;
7
7
  var parse_1 = require("./parse");
8
8
  Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return __importDefault(parse_1).default; } });
9
+ Object.defineProperty(exports, "parseWithSource", { enumerable: true, get: function () { return parse_1.parseWithSource; } });
10
+ var serialize_1 = require("./serialize");
11
+ Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return __importDefault(serialize_1).default; } });
12
+ var formula_1 = require("./formula");
13
+ Object.defineProperty(exports, "stripFormulaGuard", { enumerable: true, get: function () { return formula_1.stripFormulaGuard; } });
@@ -4,8 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.default = parse;
7
+ exports.parseWithSource = parseWithSource;
7
8
  const papaparse_1 = __importDefault(require("papaparse"));
8
9
  const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ const formula_1 = require("./formula");
9
11
  const errors = require('@tryghost/errors');
10
12
  // A column named after an Object.prototype member is unsafe as a key.
11
13
  function isSafeColumnName(name) {
@@ -17,44 +19,63 @@ function isSafeColumnName(name) {
17
19
  function isFatal(error) {
18
20
  return error.type === 'Quotes';
19
21
  }
22
+ function isEmptyRow(row) {
23
+ return !Object.values(row).some((value) => {
24
+ if (Array.isArray(value)) {
25
+ return value.some((cell) => typeof cell === 'string' && cell.trim().length > 0);
26
+ }
27
+ return value.trim().length > 0;
28
+ });
29
+ }
20
30
  // headerMapping renames headers to the columns they emit under; unmapped columns
21
31
  // carry through, and one mapped to an empty target is dropped.
22
32
  async function parse(path, headerMapping) {
33
+ const parsed = await parseWithSource(path, headerMapping);
34
+ return parsed.rows.map(({ data }) => data);
35
+ }
36
+ async function parseWithSource(path, headerMapping) {
23
37
  // Buffered rather than streamed: files are bounded by the interim row cap, and
24
38
  // papaparse's stream mode drops results.errors, which is what catches a
25
39
  // malformed quoted field before it imports as garbage.
26
40
  const content = (await fs_extra_1.default.readFile(path, 'utf8')).replace(/^\ufeff/, '');
27
41
  const parsed = papaparse_1.default.parse(content, {
28
42
  header: true,
29
- skipEmptyLines: true,
43
+ // Empty records stay in the parser output long enough to contribute to the
44
+ // publisher-visible spreadsheet line number, then are dropped below.
45
+ skipEmptyLines: false,
30
46
  });
31
47
  const fatal = parsed.errors.find(isFatal);
32
48
  if (fatal) {
33
49
  throw new errors.ValidationError({ message: `${fatal.code}: ${fatal.message}` });
34
50
  }
35
51
  const rows = [];
36
- for (const parsedRow of parsed.data) {
52
+ for (const [index, parsedRow] of parsed.data.entries()) {
53
+ if (isEmptyRow(parsedRow)) {
54
+ continue;
55
+ }
37
56
  const row = {};
57
+ const source = Object.create(null);
38
58
  for (const [header, value] of Object.entries(parsedRow)) {
39
59
  // non-string values are papaparse's __parsed_extra overflow from ragged rows
40
60
  if (typeof value !== 'string') {
41
61
  continue;
42
62
  }
63
+ source[header] = value;
43
64
  // hasOwn: a prototype-named header must not match an inherited method on the mapping
44
65
  if (headerMapping && Object.hasOwn(headerMapping, header)) {
45
66
  if (!headerMapping[header]) {
46
67
  continue;
47
68
  }
48
- row[headerMapping[header]] = value;
69
+ row[headerMapping[header]] = (0, formula_1.stripFormulaGuard)(value);
49
70
  }
50
71
  else if (isSafeColumnName(header)) {
51
- row[header] = value;
72
+ row[header] = (0, formula_1.stripFormulaGuard)(value);
52
73
  }
53
74
  }
54
75
  if (!Object.keys(row).length) {
55
76
  continue;
56
77
  }
57
- rows.push(row);
78
+ rows.push({ data: row, source, line: index + 2 });
58
79
  }
59
- return rows;
80
+ return { columns: parsed.meta.fields ?? [], rows };
60
81
  }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = serialize;
7
+ const papaparse_1 = __importDefault(require("papaparse"));
8
+ // Import reports are opened in spreadsheets, so formula-shaped cells must never
9
+ // be emitted verbatim. Papa Parse prefixes them with an apostrophe when this
10
+ // option is enabled.
11
+ function serialize(rows, { columns, header = true } = {}) {
12
+ return papaparse_1.default.unparse(rows, { columns, header, escapeFormulae: true });
13
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PreparedAssetBatch = void 0;
4
+ exports.prepareAssetBatch = prepareAssetBatch;
5
+ exports.belongsToAssetDirectory = belongsToAssetDirectory;
6
+ const content_files_1 = require("../../../data/importer/content-files");
7
+ class PreparedAssetBatch {
8
+ groups;
9
+ constructor(groups) {
10
+ this.groups = groups;
11
+ }
12
+ get files() {
13
+ return this.groups.flatMap((group) => group.files);
14
+ }
15
+ async store() {
16
+ const results = await Promise.allSettled(this.groups.map((group) => group.importer.doImport(group.files)));
17
+ const failure = results.find((result) => result.status === 'rejected');
18
+ if (failure) {
19
+ const rollbackResults = await Promise.allSettled(results.flatMap((result, index) => result.status === 'fulfilled' ? [this.groups[index].importer.rollback(result.value)] : []));
20
+ const rollbackFailures = rollbackResults.flatMap((result) => result.status === 'rejected' ? [result.reason] : []);
21
+ if (rollbackFailures.length > 0) {
22
+ // AggregateError is the native error for preserving storage and rollback
23
+ // failures; unlike GhostError it takes an iterable before its options.
24
+ // eslint-disable-next-line ghost/ghost-custom/ghost-error-usage
25
+ throw new AggregateError([failure.reason, ...rollbackFailures], 'Asset storage failed and rollback was incomplete.', { cause: failure.reason });
26
+ }
27
+ throw failure.reason;
28
+ }
29
+ }
30
+ rewriteRows(rows) {
31
+ const importData = {
32
+ data: { data: { posts: rows, tags: [], users: [] } },
33
+ };
34
+ for (const group of this.groups) {
35
+ importData[group.type] = group.files;
36
+ group.importer.preProcess(importData);
37
+ }
38
+ }
39
+ }
40
+ exports.PreparedAssetBatch = PreparedAssetBatch;
41
+ async function prepareAssetBatch(archive, directory, baseDirectory, deps = {}) {
42
+ const handlers = deps.handlers ?? (0, content_files_1.createContentFileHandlers)();
43
+ const importers = deps.importers ?? (0, content_files_1.createContentFileImporters)();
44
+ const importerByType = new Map(importers.map((importer) => [importer.type, importer]));
45
+ const groups = await Promise.all(handlers.map(async (handler) => {
46
+ const files = archive
47
+ .getFiles(directory, handler.extensions)
48
+ .filter((file) => belongsToAssetDirectory(file.name, handler.type, baseDirectory));
49
+ if (files.length === 0) {
50
+ return;
51
+ }
52
+ const importer = importerByType.get(handler.type);
53
+ if (!importer) {
54
+ return;
55
+ }
56
+ return {
57
+ type: handler.type,
58
+ files: await handler.loadFile(files, baseDirectory),
59
+ importer,
60
+ };
61
+ }));
62
+ const presentGroups = groups.filter((group) => group !== undefined);
63
+ return presentGroups.length > 0 ? new PreparedAssetBatch(presentGroups) : undefined;
64
+ }
65
+ function belongsToAssetDirectory(fileName, type, baseDirectory) {
66
+ const parts = fileName.split('/').filter(Boolean);
67
+ if (baseDirectory && parts[0] === baseDirectory) {
68
+ parts.shift();
69
+ }
70
+ if (parts[0] === 'content') {
71
+ parts.shift();
72
+ }
73
+ return parts.length > 1 && parts[0] === type;
74
+ }