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
@@ -33,7 +33,6 @@ class BatchSendingService {
33
33
  #models;
34
34
  #db;
35
35
  #sentry;
36
- #debugStorageFilePath;
37
36
  #getRequiredUrlRelations;
38
37
  #shuttingDown = false;
39
38
  #inFlight = new Set();
@@ -68,7 +67,6 @@ class BatchSendingService {
68
67
  * @param {object} [dependencies.BEFORE_RETRY_CONFIG]
69
68
  * @param {object} [dependencies.AFTER_RETRY_CONFIG]
70
69
  * @param {object} [dependencies.MAILGUN_API_RETRY_CONFIG]
71
- * @param {string} [dependencies.debugStorageFilePath]
72
70
  */
73
71
  constructor({
74
72
  emailRenderer,
@@ -83,7 +81,6 @@ class BatchSendingService {
83
81
  BEFORE_RETRY_CONFIG,
84
82
  AFTER_RETRY_CONFIG,
85
83
  MAILGUN_API_RETRY_CONFIG,
86
- debugStorageFilePath,
87
84
  }) {
88
85
  this.#emailRenderer = emailRenderer;
89
86
  this.#sendingService = sendingService;
@@ -93,7 +90,6 @@ class BatchSendingService {
93
90
  this.#models = models;
94
91
  this.#db = db;
95
92
  this.#sentry = sentry;
96
- this.#debugStorageFilePath = debugStorageFilePath;
97
93
  this.#getRequiredUrlRelations = getRequiredUrlRelations;
98
94
 
99
95
  if (BEFORE_RETRY_CONFIG) {
@@ -13,7 +13,7 @@ function isUnsplashImage(url) {
13
13
  }
14
14
  const { DateTime } = require('luxon');
15
15
  const htmlToPlaintext = require('@tryghost/html-to-plaintext');
16
- const EmailAddressParser = require('../email-address/email-address-parser');
16
+ const emailAddressParser = require('../email-address/email-address-parser');
17
17
  const { getEmailDesign } = require('../email-rendering/email-design');
18
18
  const { registerHelpers } = require('./helpers/register-helpers');
19
19
  const crypto = require('crypto');
@@ -229,6 +229,8 @@ function cheerioLoad(html) {
229
229
  * @prop {string} id
230
230
  * @prop {RegExp} token
231
231
  * @prop {(member: MemberLike) => string} getValue
232
+ * @prop {boolean} [trusted] - Value is server-generated, so it is inserted into the
233
+ * html body as-is instead of being HTML-escaped. Defaults to false (escaped).
232
234
  */
233
235
 
234
236
  /**
@@ -337,7 +339,7 @@ class EmailRenderer {
337
339
  }
338
340
 
339
341
  #getRawFromAddress(post, newsletter) {
340
- // Pass the raw name through; EmailAddressParser.stringify() is the single
342
+ // Pass the raw name through; emailAddressParser.stringify() is the single
341
343
  // point that escapes it for the RFC5322 quoted-string From header. Escaping
342
344
  // here too would double-escape (e.g. a title containing a double quote).
343
345
  let senderName = this.#settingsCache.get('title') || '';
@@ -394,7 +396,7 @@ class EmailRenderer {
394
396
  { useFallbackAddress },
395
397
  );
396
398
 
397
- return EmailAddressParser.stringify(addresses.from);
399
+ return emailAddressParser.stringify(addresses.from);
398
400
  }
399
401
 
400
402
  /**
@@ -423,7 +425,7 @@ class EmailRenderer {
423
425
  );
424
426
 
425
427
  if (addresses.replyTo) {
426
- return EmailAddressParser.stringify(addresses.replyTo);
428
+ return emailAddressParser.stringify(addresses.replyTo);
427
429
  }
428
430
  return null;
429
431
  }
@@ -920,18 +922,21 @@ class EmailRenderer {
920
922
  getValue: (member) => {
921
923
  return this.createUnsubscribeUrl(member.uuid, { newsletterUuid });
922
924
  },
925
+ trusted: true, // Server-generated URL, must not be HTML-escaped
923
926
  },
924
927
  {
925
928
  id: 'manage_account_url',
926
929
  getValue: () => {
927
930
  return this.createManageAccountUrl();
928
931
  },
932
+ trusted: true, // Server-generated URL, must not be HTML-escaped
929
933
  },
930
934
  {
931
935
  id: 'uuid',
932
936
  getValue: (member) => {
933
937
  return member.uuid;
934
938
  },
939
+ trusted: true, // Server-generated identifier
935
940
  },
936
941
  {
937
942
  id: 'key',
@@ -941,6 +946,7 @@ class EmailRenderer {
941
946
  .update(member.uuid)
942
947
  .digest('hex');
943
948
  },
949
+ trusted: true, // Server-generated hmac
944
950
  },
945
951
  {
946
952
  id: 'first_name',
@@ -1000,6 +1006,7 @@ class EmailRenderer {
1000
1006
  return this.createUnsubscribeUrl(member.uuid, { newsletterUuid });
1001
1007
  },
1002
1008
  required: true, // Used in email headers
1009
+ trusted: true, // Server-generated URL, must not be HTML-escaped
1003
1010
  },
1004
1011
  // Unique ID used for ad images to bypass ESP image proxies
1005
1012
  {
@@ -1007,6 +1014,7 @@ class EmailRenderer {
1007
1014
  getValue: () => {
1008
1015
  return crypto.randomUUID();
1009
1016
  },
1017
+ trusted: true, // Server-generated identifier
1010
1018
  },
1011
1019
  ];
1012
1020
 
@@ -1043,6 +1051,7 @@ class EmailRenderer {
1043
1051
  getValue: fallback
1044
1052
  ? (member) => definition.getValue(member) || fallback
1045
1053
  : definition.getValue,
1054
+ trusted: definition.trusted === true,
1046
1055
  });
1047
1056
  }
1048
1057
  }
@@ -1056,6 +1065,7 @@ class EmailRenderer {
1056
1065
  originalId: definition.id,
1057
1066
  token: new RegExp(`%%\\{${definition.id}\\}%%`, 'g'),
1058
1067
  getValue: definition.getValue,
1068
+ trusted: definition.trusted === true,
1059
1069
  });
1060
1070
  }
1061
1071
  }
@@ -1,5 +1,4 @@
1
1
  const debug = require('@tryghost/debug')('i18n');
2
- const logging = require('@tryghost/logging');
3
2
  const url = require('../../api/endpoints/utils/serializers/output/utils/url');
4
3
  const events = require('../../lib/common/events');
5
4
 
@@ -55,12 +54,6 @@ class EmailServiceWrapper {
55
54
  const emailAnalyticsJobs = require('../email-analytics/jobs');
56
55
  const { cachedImageSizeFromUrl } = require('../../lib/image');
57
56
 
58
- // capture errors from mailgun client and log them in sentry
59
- const errorHandler = (error) => {
60
- logging.info(`Capturing error for mailgun email provider service`);
61
- sentry.captureException(error);
62
- };
63
-
64
57
  // Mailgun client instance for email provider
65
58
  const mailgunClient = new MailgunClient({
66
59
  config: configService,
@@ -78,7 +71,6 @@ class EmailServiceWrapper {
78
71
  const mailgunEmailProvider = new MailgunEmailProvider({
79
72
  mailgunClient,
80
73
  config: configService,
81
- errorHandler,
82
74
  });
83
75
 
84
76
  const emailRenderer = new EmailRenderer({
@@ -134,7 +126,6 @@ class EmailServiceWrapper {
134
126
  db,
135
127
  sentry,
136
128
  getRequiredUrlRelations,
137
- debugStorageFilePath: configService.getContentPath('data'),
138
129
  });
139
130
 
140
131
  if (ghostServer) {
@@ -1,6 +1,7 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const errors = require('@tryghost/errors');
3
3
  const debug = require('@tryghost/debug')('email-service:mailgun-provider-service');
4
+ const { escapeExpression } = require('handlebars');
4
5
 
5
6
  /**
6
7
  * @typedef {object} Config
@@ -35,35 +36,41 @@ const debug = require('@tryghost/debug')('email-service:mailgun-provider-service
35
36
  class MailgunEmailProvider {
36
37
  #mailgunClient;
37
38
  #config;
38
- #errorHandler;
39
39
 
40
40
  /**
41
41
  * @param {object} dependencies
42
42
  * @param {import('../lib/mailgun-client')} dependencies.mailgunClient - mailgun client to send emails
43
43
  * @param {Config} dependencies.config
44
- * @param {Function} [dependencies.errorHandler] - custom error handler for logging exceptions
45
44
  */
46
- constructor({ mailgunClient, config, errorHandler }) {
45
+ constructor({ mailgunClient, config }) {
47
46
  this.#mailgunClient = mailgunClient;
48
47
  this.#config = config;
49
- this.#errorHandler = errorHandler;
50
48
  }
51
49
 
52
- #createRecipientData(replacements) {
50
+ #createRecipientData(replacements, htmlEscapedIds) {
53
51
  let recipientData = {};
54
52
 
55
53
  recipientData = replacements.reduce((acc, replacement) => {
56
54
  const { id, value } = replacement;
57
55
  acc[id] = value;
56
+ // Mailgun's recipient-variables substitution is a simple string replace with
57
+ // no HTML awareness, and the same value is used for both the html and plaintext
58
+ // bodies. Member-controlled values get an extra, escaped variant that only the
59
+ // html body points at. Trusted server-generated values (urls, uuids, hmacs) are
60
+ // skipped so their URLs don't end up entity-encoded inside hrefs.
61
+ if (htmlEscapedIds.has(id)) {
62
+ acc[`${id}_html`] = typeof value === 'string' ? escapeExpression(value) : value;
63
+ }
58
64
  return acc;
59
65
  }, {});
60
66
 
61
67
  return recipientData;
62
68
  }
63
69
 
64
- #updateRecipientVariables(data, replacementDefinitions) {
70
+ #updateRecipientVariables(data, replacementDefinitions, isHtml) {
65
71
  for (const def of replacementDefinitions) {
66
- data = data.replace(def.token, `%recipient.${def.id}%`);
72
+ const useHtmlVariant = isHtml && !def.trusted;
73
+ data = data.replace(def.token, `%recipient.${def.id}${useHtmlVariant ? '_html' : ''}%`);
67
74
  }
68
75
  return data;
69
76
  }
@@ -128,8 +135,11 @@ class MailgunEmailProvider {
128
135
  }
129
136
 
130
137
  // create recipient data for Mailgun using replacement definitions
138
+ const htmlEscapedIds = new Set(
139
+ replacementDefinitions.filter((def) => !def.trusted).map((def) => def.id),
140
+ );
131
141
  const recipientData = recipients.reduce((acc, recipient) => {
132
- acc[recipient.email] = this.#createRecipientData(recipient.replacements);
142
+ acc[recipient.email] = this.#createRecipientData(recipient.replacements, htmlEscapedIds);
133
143
  return acc;
134
144
  }, {});
135
145
 
@@ -139,6 +149,7 @@ class MailgunEmailProvider {
139
149
  messageData[key] = this.#updateRecipientVariables(
140
150
  messageData[key],
141
151
  replacementDefinitions,
152
+ key === 'html',
142
153
  );
143
154
  }
144
155
  });
@@ -165,7 +176,7 @@ class MailgunEmailProvider {
165
176
  message: this.#createMailgunErrorMessage(error),
166
177
  errorDetails: JSON.stringify({ error, messageData }),
167
178
  context: `Mailgun Error ${error.status}: ${error.details}`,
168
- help: `https://ghost.org/docs/newsletters/#bulk-email-configuration`,
179
+ help: `https://docs.ghost.org/newsletters/#bulk-email-configuration`,
169
180
  code: 'BULK_EMAIL_SEND_FAILED',
170
181
  });
171
182
  } else {
@@ -2,10 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DbGiftLink = void 0;
4
4
  const zod_1 = require("zod");
5
- const db_date_1 = require("../../lib/db-date");
5
+ const date_1 = require("../../lib/db-types/date");
6
6
  exports.DbGiftLink = zod_1.z.object({
7
7
  token: zod_1.z.string(),
8
8
  post_id: zod_1.z.string(),
9
- created_at: db_date_1.DbDate,
10
- updated_at: db_date_1.DbDate.nullable(),
9
+ created_at: date_1.DbDate,
10
+ updated_at: date_1.DbDate.nullable(),
11
11
  });
@@ -37,7 +37,7 @@ The buyer's chosen way of handing over a gift subscription: the publication emai
37
37
  _Avoid_: Delivery mode
38
38
 
39
39
  **Redemption link**:
40
- A single-use, time-limited link through which a purchased gift subscription can be viewed and claimed. Its bearer may see the gift's buyer name, intended recipient name, and personal message, but not email-routing or delivery details.
40
+ A single-use, time-limited link through which a purchased gift subscription can be viewed and claimed. Its bearer may see the gift's buyer name, intended recipient name, recipient email, and personal message; the intended recipient does not reserve redemption.
41
41
  _Avoid_: Gift Link
42
42
 
43
43
  **Gift redemption**:
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GIFT_DELIVERY_EMAIL_TAG = exports.GIFT_DELIVERY_STALE_AFTER_MS = exports.GIFT_REMINDER_FLOOR_DAYS = exports.GIFT_REMINDER_LEAD_DAYS = exports.GIFT_SEND_HOUR = exports.GIFT_MAX_SCHEDULE_DAYS = exports.GIFT_EXPIRY_DAYS = void 0;
4
4
  exports.GIFT_EXPIRY_DAYS = 365;
5
5
  // How far ahead a delivery may be scheduled. Portal's picker carries its own
6
- // copy (GIFT_MAX_SCHEDULE_DAYS in beta-gift-page.jsx) since Portal ships
6
+ // copy (GIFT_MAX_SCHEDULE_DAYS in beta-gift-page.tsx) since Portal ships
7
7
  // separately — change them together.
8
8
  exports.GIFT_MAX_SCHEDULE_DAYS = 365;
9
9
  // Site-local hour a scheduled delivery is sent at. Portal never derives
@@ -31,9 +31,9 @@
31
31
  <tr>
32
32
  <td align="left" style="padding-bottom: 22px; text-align: left;">
33
33
  {{#if siteIconUrl}}
34
- <a href="{{siteUrl}}"><img src="{{siteIconUrl}}" alt="{{siteTitle}}" border="0" width="48" height="48" style="border-radius: 4px;"></a>
34
+ <img src="{{siteIconUrl}}" alt="{{siteTitle}}" border="0" width="48" height="48" style="border-radius: 4px;">
35
35
  {{else}}
36
- <a href="{{siteUrl}}" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 17px; font-weight: 700; color: {{accentColor}}; text-decoration: none;">{{siteTitle}}</a>
36
+ <span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 17px; font-weight: 700; color: {{accentColor}};">{{siteTitle}}</span>
37
37
  {{/if}}
38
38
  </td>
39
39
  </tr>
@@ -92,7 +92,7 @@
92
92
  </tr>
93
93
  <tr>
94
94
  <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-top: 40px;">
95
- <p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 16px; font-size: 11px; color: #738A94; font-weight: normal; margin: 0;">{{t 'This message was sent from {siteDomain} to {email} on behalf of {buyerName} ({buyerEmail}).' siteDomain=(linkTag siteUrl siteDomain class="small" style="text-decoration: underline; color: #738A94; font-size: 11px;") email=(linkTag (mailto toEmail) toEmail class="small" style="text-decoration: underline; color: #738A94; font-size: 11px;") buyerName=buyerName buyerEmail=(linkTag (mailto buyerEmail) buyerEmail class="small" style="text-decoration: underline; color: #738A94; font-size: 11px;")}}</p>
95
+ <p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 16px; font-size: 11px; color: #738A94; font-weight: normal; margin: 0;">{{t 'This message was sent from {siteDomain} to {email} on behalf of {buyerName} ({buyerEmail}).' siteDomain=siteDomain email=toEmail buyerName=buyerName buyerEmail=buyerEmail}}</p>
96
96
  </td>
97
97
  </tr>
98
98
  </table>
@@ -7,7 +7,7 @@ exports.GiftBookshelfRepository = void 0;
7
7
  const errors_1 = __importDefault(require("@tryghost/errors"));
8
8
  const mongo_utils_1 = require("@tryghost/mongo-utils");
9
9
  const gift_codec_1 = require("./gift-codec");
10
- const db_date_1 = require("../../lib/db-date");
10
+ const date_1 = require("../../lib/db-types/date");
11
11
  class GiftBookshelfRepository {
12
12
  model;
13
13
  knex;
@@ -117,7 +117,7 @@ class GiftBookshelfRepository {
117
117
  async deleteAbandonedCheckouts(cutoff) {
118
118
  return this.knex('gifts')
119
119
  .where({ status: 'payment_pending' })
120
- .where('checkout_started_at', '<=', (0, db_date_1.toDatabaseDate)(cutoff))
120
+ .where('checkout_started_at', '<=', (0, date_1.toDatabaseDate)(cutoff))
121
121
  .del();
122
122
  }
123
123
  async create(gift, options = {}) {
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.GiftDeliveryBookshelfRepository = void 0;
7
7
  const errors_1 = __importDefault(require("@tryghost/errors"));
8
- const db_date_1 = require("../../lib/db-date");
8
+ const date_1 = require("../../lib/db-types/date");
9
9
  const gift_codec_1 = require("./gift-codec");
10
10
  const gift_delivery_codec_1 = require("./gift-delivery-codec");
11
11
  // A null scheduled_at means the delivery was due at purchase time, so it is
@@ -14,7 +14,7 @@ function dueDeliveries(query, now) {
14
14
  query.andWhere((due) => {
15
15
  due
16
16
  .whereNull('gift_deliveries.scheduled_at')
17
- .orWhere('gift_deliveries.scheduled_at', '<=', (0, db_date_1.toDatabaseDate)(now));
17
+ .orWhere('gift_deliveries.scheduled_at', '<=', (0, date_1.toDatabaseDate)(now));
18
18
  });
19
19
  }
20
20
  // Deliveries that still need a send attempt: never started, or claimed by a
@@ -24,7 +24,7 @@ function recoverableDeliveries(query, staleBefore) {
24
24
  recoverable.where('gift_deliveries.status', 'pending').orWhere((stale) => {
25
25
  stale
26
26
  .where('gift_deliveries.status', 'sending')
27
- .where('gift_deliveries.started_at', '<=', (0, db_date_1.toDatabaseDate)(staleBefore));
27
+ .where('gift_deliveries.started_at', '<=', (0, date_1.toDatabaseDate)(staleBefore));
28
28
  });
29
29
  });
30
30
  }
@@ -43,6 +43,15 @@ class GiftDeliveryBookshelfRepository {
43
43
  const model = await this.model.findOne({ gift_id: giftId }, { require: false, ...options });
44
44
  return model ? (0, gift_delivery_codec_1.decodeGiftDeliveryRow)(model.toJSON()) : null;
45
45
  }
46
+ async getByGiftToken(giftToken, options = {}) {
47
+ const db = options.transacting ?? this.knex;
48
+ const row = await db('gift_deliveries')
49
+ .select('gift_deliveries.*')
50
+ .join('gifts', 'gifts.id', 'gift_deliveries.gift_id')
51
+ .where('gifts.token', giftToken)
52
+ .first();
53
+ return row ? (0, gift_delivery_codec_1.decodeGiftDeliveryRow)(row) : null;
54
+ }
46
55
  async getByProviderMessageId(providerMessageId) {
47
56
  const model = await this.model.findOne({ email_provider_message_id: providerMessageId }, { require: false });
48
57
  return model ? (0, gift_delivery_codec_1.decodeGiftDeliveryRow)(model.toJSON()) : null;
@@ -83,8 +92,8 @@ class GiftDeliveryBookshelfRepository {
83
92
  .join('gifts', 'gifts.id', 'gift_deliveries.gift_id')
84
93
  .where('gift_deliveries.status', 'pending')
85
94
  .where('gifts.status', 'purchased')
86
- .where('gift_deliveries.scheduled_at', '>', (0, db_date_1.toDatabaseDate)(now));
87
- return rows.map((row) => (0, db_date_1.fromDatabaseDate)(row.scheduled_at));
95
+ .where('gift_deliveries.scheduled_at', '>', (0, date_1.toDatabaseDate)(now));
96
+ return rows.map((row) => (0, date_1.fromDatabaseDate)(row.scheduled_at));
88
97
  }
89
98
  async tryStartDelivery(id, now, staleBefore) {
90
99
  const claimed = await this.knex('gift_deliveries')
@@ -100,7 +109,7 @@ class GiftDeliveryBookshelfRepository {
100
109
  .modify(recoverableDeliveries, staleBefore)
101
110
  .update({
102
111
  status: 'sending',
103
- started_at: (0, db_date_1.toDatabaseDate)(now),
112
+ started_at: (0, date_1.toDatabaseDate)(now),
104
113
  });
105
114
  if (claimed !== 1) {
106
115
  return null;
@@ -110,7 +119,7 @@ class GiftDeliveryBookshelfRepository {
110
119
  async markSent(id, sentAt, providerMessageId) {
111
120
  return this.updateState(id, 'sending', {
112
121
  status: 'sent',
113
- email_sent_at: (0, db_date_1.toDatabaseDate)(sentAt),
122
+ email_sent_at: (0, date_1.toDatabaseDate)(sentAt),
114
123
  email_provider_message_id: providerMessageId,
115
124
  started_at: null,
116
125
  });
@@ -119,7 +128,7 @@ class GiftDeliveryBookshelfRepository {
119
128
  // details so the message can still be correlated with transport outcomes
120
129
  async recordCancelledAcceptance(id, sentAt, providerMessageId) {
121
130
  return this.updateState(id, 'cancelled', {
122
- email_sent_at: (0, db_date_1.toDatabaseDate)(sentAt),
131
+ email_sent_at: (0, date_1.toDatabaseDate)(sentAt),
123
132
  email_provider_message_id: providerMessageId,
124
133
  });
125
134
  }
@@ -145,7 +154,7 @@ class GiftDeliveryBookshelfRepository {
145
154
  return updated === 1;
146
155
  }
147
156
  async recordOutcome({ providerMessageId, outcome, timestamp, error, }) {
148
- const outcomeAt = (0, db_date_1.toDatabaseDate)(timestamp);
157
+ const outcomeAt = (0, date_1.toDatabaseDate)(timestamp);
149
158
  const lowerPriorityOutcomes = outcome === 'permanent_failed'
150
159
  ? ['temporary_failed', 'delivered']
151
160
  : outcome === 'delivered'
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DbGiftDelivery = exports.GiftDeliveryOutcomeSchema = exports.GiftDeliveryStatusSchema = void 0;
4
4
  const zod_1 = require("zod");
5
- const db_date_1 = require("../../lib/db-date");
5
+ const date_1 = require("../../lib/db-types/date");
6
6
  exports.GiftDeliveryStatusSchema = zod_1.z.enum([
7
7
  'pending',
8
8
  'sending',
@@ -21,11 +21,11 @@ exports.DbGiftDelivery = zod_1.z.object({
21
21
  gift_id: zod_1.z.string(),
22
22
  recipient_email: zod_1.z.string().email(),
23
23
  status: exports.GiftDeliveryStatusSchema.default('pending'),
24
- scheduled_at: db_date_1.DbDate.nullable().default(null),
25
- started_at: db_date_1.DbDate.nullable().default(null),
26
- email_sent_at: db_date_1.DbDate.nullable().default(null),
24
+ scheduled_at: date_1.DbDate.nullable().default(null),
25
+ started_at: date_1.DbDate.nullable().default(null),
26
+ email_sent_at: date_1.DbDate.nullable().default(null),
27
27
  email_provider_message_id: zod_1.z.string().nullable().default(null),
28
28
  outcome: exports.GiftDeliveryOutcomeSchema.default('unknown'),
29
- outcome_at: db_date_1.DbDate.nullable().default(null),
29
+ outcome_at: date_1.DbDate.nullable().default(null),
30
30
  outcome_error: zod_1.z.string().nullable().default(null),
31
31
  });
@@ -41,6 +41,10 @@ class GiftDeliveryService {
41
41
  await this.deps.giftDeliveryRepository.create(delivery, options);
42
42
  return delivery.id;
43
43
  }
44
+ async getRecipientEmailForGift(giftToken, options = {}) {
45
+ const delivery = await this.deps.giftDeliveryRepository.getByGiftToken(giftToken, options);
46
+ return delivery?.recipientEmail ?? null;
47
+ }
44
48
  async dispatchForGift({ giftId, }) {
45
49
  const delivery = await this.deps.giftDeliveryRepository.getByGiftId(giftId);
46
50
  if (!delivery || delivery.status !== 'pending') {
@@ -182,7 +182,6 @@ class GiftEmailService {
182
182
  const giftLink = `${siteUrl.replace(/\/$/, '')}/gift/${token}`;
183
183
  const { html, text } = await this.renderer.renderDelivery({
184
184
  siteTitle,
185
- siteUrl,
186
185
  siteIconUrl: this.blogIcon.getIconUrl({ absolute: true, fallbackToDefault: false }),
187
186
  siteDomain,
188
187
  accentColor: this.accentColor,
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DbGift = exports.GiftStatusSchema = exports.GiftCadenceSchema = void 0;
4
4
  const zod_1 = require("zod");
5
- const db_date_1 = require("../../lib/db-date");
5
+ const date_1 = require("../../lib/db-types/date");
6
6
  exports.GiftCadenceSchema = zod_1.z.enum(['month', 'year']);
7
7
  exports.GiftStatusSchema = zod_1.z.enum([
8
8
  'payment_pending',
@@ -32,14 +32,14 @@ exports.DbGift = zod_1.z.object({
32
32
  amount: zod_1.z.number().int().nonnegative(),
33
33
  stripe_checkout_session_id: zod_1.z.string().nullable(),
34
34
  stripe_payment_intent_id: zod_1.z.string().nullable(),
35
- checkout_started_at: db_date_1.DbDate.nullable().default(null),
36
- consumes_at: db_date_1.DbDate.nullable(),
37
- expires_at: db_date_1.DbDate.nullable(),
35
+ checkout_started_at: date_1.DbDate.nullable().default(null),
36
+ consumes_at: date_1.DbDate.nullable(),
37
+ expires_at: date_1.DbDate.nullable(),
38
38
  status: exports.GiftStatusSchema,
39
- purchased_at: db_date_1.DbDate.nullable(),
40
- redeemed_at: db_date_1.DbDate.nullable(),
41
- consumed_at: db_date_1.DbDate.nullable(),
42
- expired_at: db_date_1.DbDate.nullable(),
43
- refunded_at: db_date_1.DbDate.nullable(),
44
- consumes_soon_reminder_sent_at: db_date_1.DbDate.nullable().default(null),
39
+ purchased_at: date_1.DbDate.nullable(),
40
+ redeemed_at: date_1.DbDate.nullable(),
41
+ consumed_at: date_1.DbDate.nullable(),
42
+ expired_at: date_1.DbDate.nullable(),
43
+ refunded_at: date_1.DbDate.nullable(),
44
+ consumes_soon_reminder_sent_at: date_1.DbDate.nullable().default(null),
45
45
  });
@@ -565,7 +565,7 @@ class GiftService {
565
565
  transacting,
566
566
  newMember: input.newMember,
567
567
  });
568
- const redemption = await this.serializeRedemption(redeemed);
568
+ const redemption = await this.serializeRedemption(redeemed, { transacting });
569
569
  return { redeemed, member, redemption };
570
570
  };
571
571
  const { redeemed, member, redemption } = input.transacting
@@ -1044,7 +1044,8 @@ class GiftService {
1044
1044
  });
1045
1045
  return true;
1046
1046
  }
1047
- async serializeRedemption(gift) {
1047
+ async serializeRedemption(gift, options = {}) {
1048
+ const recipientEmail = await this.deps.giftDeliveryService.getRecipientEmailForGift(gift.token, options);
1048
1049
  const tier = await this.deps.tiersService.api.read(gift.tierId);
1049
1050
  if (!tier) {
1050
1051
  throw new errors_1.default.InternalServerError({
@@ -1060,6 +1061,7 @@ class GiftService {
1060
1061
  amount: gift.amount,
1061
1062
  buyer_name: gift.buyerName,
1062
1063
  recipient_name: gift.recipientName,
1064
+ recipient_email: recipientEmail,
1063
1065
  message: gift.personalMessage,
1064
1066
  expires_at: gift.expiresAt,
1065
1067
  consumes_at: gift.consumesAt,
@@ -14,7 +14,7 @@ const send_gift_delivery_event_1 = require("./events/send-gift-delivery-event");
14
14
  // Persistent scheduling adapters keep their queue across restarts and opt out
15
15
  // of boot-time rebuilds (same contract post scheduling honours in boot.js).
16
16
  let rescheduleDeliveriesOnBoot = true;
17
- async function init(options) {
17
+ function init(options) {
18
18
  if (exports.service) {
19
19
  return;
20
20
  }
@@ -37,7 +37,7 @@ async function init(options) {
37
37
  const labsService = require('../../../shared/labs');
38
38
  const urlUtils = require('../../../shared/url-utils').default;
39
39
  const settingsHelpers = require('../settings-helpers');
40
- const EmailAddressParser = require('../email-address/email-address-parser');
40
+ const emailAddressParser = require('../email-address/email-address-parser');
41
41
  const { blogIcon } = require('../../../server/lib/image');
42
42
  const { t } = require('../i18n');
43
43
  const repository = new gift_bookshelf_repository_1.GiftBookshelfRepository({
@@ -57,7 +57,7 @@ async function init(options) {
57
57
  bulkMailer: new MailgunClient({ config, settings: settingsCache }),
58
58
  settingsCache,
59
59
  urlUtils,
60
- getFromAddress: () => EmailAddressParser.stringify(settingsHelpers.getDefaultEmail()),
60
+ getFromAddress: () => emailAddressParser.stringify(settingsHelpers.getDefaultEmail()),
61
61
  getReplyToAddress: () => settingsHelpers.getMembersSupportAddress(),
62
62
  blogIcon,
63
63
  t,
@@ -1,6 +1,6 @@
1
1
  const path = require('path');
2
2
  const logging = require('@tryghost/logging');
3
- const jobsService = require('../../jobs');
3
+ const jobManager = require('../../jobs');
4
4
  const CleanGiftsJob = require('./clean-gifts-job').default;
5
5
 
6
6
  let hasScheduled = {
@@ -31,7 +31,7 @@ function scheduleJob(key, name, jobFile) {
31
31
  const at = randomOffPeakDailyCron();
32
32
 
33
33
  logging.info(`[Background Job] ${name} scheduled at ${at}`);
34
- jobsService.addJob({
34
+ jobManager.addJob({
35
35
  at,
36
36
  job: path.resolve(__dirname, jobFile),
37
37
  name,
@@ -43,14 +43,14 @@ function scheduleJob(key, name, jobFile) {
43
43
  }
44
44
 
45
45
  module.exports = {
46
- async scheduleGiftCleanupJob(classBasedJobs) {
46
+ async scheduleGiftCleanupJob(jobsService) {
47
47
  if (alreadyScheduledOrTest('cleanup')) {
48
48
  return;
49
49
  }
50
50
 
51
51
  const cron = randomOffPeakDailyCron();
52
52
  logging.info(`[Background Job] clean-gifts scheduled at ${cron}`);
53
- await classBasedJobs.scheduleRecurring(new CleanGiftsJob(), { cron });
53
+ await jobsService.scheduleRecurring(new CleanGiftsJob(), { cron });
54
54
 
55
55
  hasScheduled.cleanup = true;
56
56
  },
@@ -160,7 +160,7 @@ class IndexNowPingService {
160
160
  err,
161
161
  message: err.message,
162
162
  context: (0, tpl_1.default)(constants_1.messages.requestFailedError, { service: 'IndexNow' }),
163
- help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://ghost.org/docs/' }),
163
+ help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://docs.ghost.org/' }),
164
164
  }),
165
165
  };
166
166
  }
@@ -181,7 +181,7 @@ class IndexNowPingService {
181
181
  err,
182
182
  message: err.message,
183
183
  context: (0, tpl_1.default)(constants_1.messages.requestFailedError, { service: 'IndexNow' }),
184
- help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://ghost.org/docs/' }),
184
+ help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://docs.ghost.org/' }),
185
185
  }),
186
186
  };
187
187
  }
@@ -30,7 +30,9 @@ async function accept(invitation) {
30
30
  throw new errors.NotFoundError({ message: tpl(messages.inviteExpired) });
31
31
  }
32
32
 
33
- let user = await models.User.findOne({ email: data.email }, options);
33
+ const email = invite.get('email');
34
+
35
+ let user = await models.User.findOne({ email }, options);
34
36
  if (user) {
35
37
  throw new errors.ValidationError({
36
38
  message: tpl(messages.inviteEmailAlreadyExist.message),
@@ -45,7 +47,7 @@ async function accept(invitation) {
45
47
 
46
48
  await models.User.add(
47
49
  {
48
- email: data.email,
50
+ email,
49
51
  name: data.name,
50
52
  password: data.password,
51
53
  roles: [roleId],
@@ -9,22 +9,13 @@ const models = require('../../models');
9
9
  const sentry = require('../../../shared/sentry');
10
10
  const domainEvents = require('@tryghost/domain-events');
11
11
  const config = require('../../../shared/config');
12
- const WorkerModelEventBridge = require('./worker-model-event-bridge');
13
12
  const errorHandler = (error, workerMeta) => {
14
13
  logging.error(error, `[Background Job] ${workerMeta.name} failed`);
15
14
  sentry.captureException(error);
16
15
  };
17
16
  const events = require('../../lib/common/events');
18
- const workerModelEventBridge = new WorkerModelEventBridge({ models, events, logging, sentry });
19
17
 
20
18
  const workerMessageHandler = ({ name, message }) => {
21
- if (workerModelEventBridge.isModelEventMessage(message)) {
22
- // Carries its own `eventName` rather than job-manager's reserved `event` key,
23
- // so it routes through the bridge instead of being dispatched as a raw domain event.
24
- workerModelEventBridge.handle(message, { jobName: name });
25
- return;
26
- }
27
-
28
19
  if (typeof message === 'string' && !['done', 'cancelled'].includes(message)) {
29
20
  logging.info(`[Background Job] ${name}: ${message}`);
30
21
  }