ghost 6.64.0 → 6.65.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 (672) hide show
  1. package/bin/create-migration.js +15 -0
  2. package/components/tryghost-adapter-base-scheduling-0.2.4.tgz +0 -0
  3. package/components/tryghost-api-framework-0.0.0.tgz +0 -0
  4. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  5. package/components/tryghost-kg-default-cards-10.3.6.tgz +0 -0
  6. package/components/tryghost-kg-lexical-html-renderer-1.5.1.tgz +0 -0
  7. package/components/tryghost-metafield-types-0.0.0.tgz +0 -0
  8. package/content/themes/casper/assets/built/casper.js +1 -1
  9. package/content/themes/casper/assets/built/screen.css +1 -1
  10. package/content/themes/casper/assets/css/screen.css +15 -2
  11. package/content/themes/casper/assets/js/init.js +37 -9
  12. package/content/themes/casper/package.json +8 -8
  13. package/content/themes/source/assets/built/screen.css +1 -1
  14. package/content/themes/source/assets/built/source.js +1 -1
  15. package/content/themes/source/assets/css/screen.css +14 -1
  16. package/content/themes/source/assets/js/main.js +24 -4
  17. package/content/themes/source/package.json +7 -7
  18. package/core/boot.js +22 -16
  19. package/core/bridge.js +1 -1
  20. package/core/built/admin/assets/Combination-DQ6f9A5P.js +41 -0
  21. package/core/built/admin/assets/{PolarAngleAxis-a81ieQUO.js → PolarAngleAxis-BBaU7PRV.js} +1 -1
  22. package/core/built/admin/assets/RadialBarChart-Bp20JPnA.js +1 -0
  23. package/core/built/admin/assets/{about-39CAfroa.js → about-Dp43j18M.js} +1 -1
  24. package/core/built/admin/assets/accordion-h62UzFhj.js +1 -0
  25. package/core/built/admin/assets/account-migration-CBTbtX6Q.js +1 -0
  26. package/core/built/admin/assets/action-list-DC9QpX-l.js +1 -0
  27. package/core/built/admin/assets/activitypub/{account-migration-KA6Jjf9L.js → account-migration-B1DUZS4Q.js} +8 -8
  28. package/core/built/admin/assets/activitypub/activitypub.js +24 -11
  29. package/core/built/admin/assets/activitypub/avatar-CRGud8yf.js +153 -0
  30. package/core/built/admin/assets/activitypub/{avatar-flipboard-csQaNeYK.js → avatar-flipboard-BZNFAXfm.js} +3 -3
  31. package/core/built/admin/assets/activitypub/{bluesky-sharing-C7nTDMvw.js → bluesky-sharing-Cg_v-LwS.js} +30 -31
  32. package/core/built/admin/assets/activitypub/{chunk-KS7C4IRE-Ck3O4oo2.js → chunk-KS7C4IRE-CTUL98Lc.js} +2498 -1885
  33. package/core/built/admin/assets/activitypub/{content-formatters-CLcjaBwV.js → content-formatters-D7GWP7nH.js} +23 -24
  34. package/core/built/admin/assets/activitypub/{copy-DcOh8kXw.js → copy-CgzTvoeR.js} +2 -2
  35. package/core/built/admin/assets/activitypub/{domain-fZ-X8i4-.js → domain-C3G_nkHU.js} +46 -46
  36. package/core/built/admin/assets/activitypub/{edit-profile-BqMLQV88.js → edit-profile-C8cCY-AK.js} +927 -928
  37. package/core/built/admin/assets/activitypub/{explore-B4yPoP8E.js → explore-NlDT4inq.js} +11 -11
  38. package/core/built/admin/assets/activitypub/{feed-BRC_mvAe.js → feed-DF22jCTV.js} +10 -10
  39. package/core/built/admin/assets/activitypub/{field-COacNgOt.js → field-95-iuTte.js} +4 -4
  40. package/core/built/admin/assets/activitypub/{hash-C7u-irQQ.js → hash-R7LMLnhY.js} +2 -2
  41. package/core/built/admin/assets/activitypub/{inbox-CbTTdDQ3.js → inbox-DUJUiV6x.js} +2 -2
  42. package/core/built/admin/assets/activitypub/{inbox-BW-yvUoN.js → inbox-DerExBzA.js} +416 -414
  43. package/core/built/admin/assets/activitypub/{label-kPMmYI7l.js → label-EwCn1QYc.js} +4 -4
  44. package/core/built/admin/assets/activitypub/layout-Dy6NnW1G.js +1 -0
  45. package/core/built/admin/assets/activitypub/{moderation-CuidJzc0.js → moderation-BSkfiVYo.js} +73 -75
  46. package/core/built/admin/assets/activitypub/{note-CAMRRSqD.js → note-DOnAJTXK.js} +9 -9
  47. package/core/built/admin/assets/activitypub/{notifications-BmNlXGgp.js → notifications-DZc6XTjG.js} +27 -27
  48. package/core/built/admin/assets/activitypub/{onboarding-Dmun9jr_.js → onboarding-8vEIwYTH.js} +3 -3
  49. package/core/built/admin/assets/activitypub/{onboarding-Bqg7fh_L.js → onboarding-DYVqbNmp.js} +2 -2
  50. package/core/built/admin/assets/activitypub/{preferences--oH19wf9.js → preferences-DDok6F2N.js} +1418 -1390
  51. package/core/built/admin/assets/activitypub/{profile-DH_tQx2D.js → profile-DjVa2hUk.js} +254 -255
  52. package/core/built/admin/assets/activitypub/{reply-Cap9PxSH.js → reply-DtXBpHxu.js} +2 -2
  53. package/core/built/admin/assets/activitypub/routes-Cw302e1c.js +4946 -0
  54. package/core/built/admin/assets/activitypub/{separator-CAxxu8VV.js → separator-FpRpVDd3.js} +8 -9
  55. package/core/built/admin/assets/activitypub/settings-yK-puALn.js +314 -0
  56. package/core/built/admin/assets/activitypub/{site-BYps63oh.js → site-CHw0R2PA.js} +2 -2
  57. package/core/built/admin/assets/activitypub/{step-1-CKjR2KAm.js → step-1-737bnvxk.js} +7 -7
  58. package/core/built/admin/assets/activitypub/{step-2-B6PKfOUQ.js → step-2-DBaIsAsM.js} +7 -7
  59. package/core/built/admin/assets/activitypub/{step-3-C-qBbcUo.js → step-3-BBmy9m9V.js} +23 -23
  60. package/core/built/admin/assets/activitypub/tabs-LQ2xirdm.js +1101 -0
  61. package/core/built/admin/assets/activitypub/{topic-filter-DsUOuu0k.js → topic-filter-75Nu0CKj.js} +4 -4
  62. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-CX9snsLs.js → use-activity-pub-queries-CYI2QJMs.js} +58 -58
  63. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-DsJTGDSS.js → use-navigate-with-base-path-B4jZ8hyg.js} +3924 -1403
  64. package/core/built/admin/assets/activitypub/{use-reply-chain-data-AJi9zkzm.js → use-reply-chain-data-BHmFxc3U.js} +6 -6
  65. package/core/built/admin/assets/activitypub/users-CSjOwpT9.js +886 -0
  66. package/core/built/admin/assets/activitypub/{x-DR8AT3-4.js → x-B9ptWCds.js} +2 -2
  67. package/core/built/admin/assets/{add-integration-modal-B12oRifD.js → add-integration-modal-BwePhq95.js} +1 -1
  68. package/core/built/admin/assets/add-newsletter-modal-Zv0I7Msm.js +1 -0
  69. package/core/built/admin/assets/{add-recommendation-modal-CJf92edY.js → add-recommendation-modal-cdLv0wHy.js} +1 -1
  70. package/core/built/admin/assets/analytics-DY8_SaP7.js +1 -0
  71. package/core/built/admin/assets/announcement-bar-modal-C-2yWwag.js +1 -0
  72. package/core/built/admin/assets/api-keys-BHKATUqQ.js +1 -0
  73. package/core/built/admin/assets/{audience-6GXevic-.js → audience-wRcSN0jV.js} +1 -1
  74. package/core/built/admin/assets/{automated-emails-DJQ4uNZo.js → automated-emails-CzUa3v4d.js} +1 -1
  75. package/core/built/admin/assets/automations-DupSsSOr.js +1 -0
  76. package/core/built/admin/assets/badge-CI1Z0xyG.js +1 -0
  77. package/core/built/admin/assets/bluesky-sharing-B8PC1SBj.js +1 -0
  78. package/core/built/admin/assets/box-LUuYRT-1.js +1 -0
  79. package/core/built/admin/assets/brand-icon-CrmbX86T.js +1 -0
  80. package/core/built/admin/assets/breadcrumb-DDDpzLyo.js +1 -0
  81. package/core/built/admin/assets/button-D414TI3B.js +1 -0
  82. package/core/built/admin/assets/calendar-Cp_opo3i.js +1 -0
  83. package/core/built/admin/assets/card-C2dfd5u0.js +1 -0
  84. package/core/built/admin/assets/chart-B_UNLXse.js +63 -0
  85. package/core/built/admin/assets/chart-helpers-Czu_9QpJ.js +1 -0
  86. package/core/built/admin/assets/checkbox-CFFqf0Nh.js +1 -0
  87. package/core/built/admin/assets/{chunk.368.22ce1b732c0b40abd3f1.js → chunk.201.6961b57ed7a281ac193e.js} +23 -19
  88. package/core/built/admin/assets/chunk.524.0b850e72ec49a0fa3882.js +25 -0
  89. package/core/built/admin/assets/chunk.582.db2ae9e968256e8d58ac.js +27 -0
  90. package/core/built/admin/assets/code-editor-view-Bd_nnHKk.js +1 -0
  91. package/core/built/admin/assets/code-editor-view-BeU3Yf9M.js +1 -0
  92. package/core/built/admin/assets/color-picker-Bzm1V7qg.js +3 -0
  93. package/core/built/admin/assets/color-picker-field-DP0moHz9.js +1 -0
  94. package/core/built/admin/assets/combobox-6_ruuTuj.js +1 -0
  95. package/core/built/admin/assets/command-B5wfm6pd.js +1 -0
  96. package/core/built/admin/assets/comments-BB26dUSl.js +1 -0
  97. package/core/built/admin/assets/confirmation-context-znVJD4pX.js +1 -0
  98. package/core/built/admin/assets/container-CHHif8km.js +1 -0
  99. package/core/built/admin/assets/{content-api-modal-0ZjuLcQ8.js → content-api-modal-DOHwl0yZ.js} +1 -1
  100. package/core/built/admin/assets/context-menu-BpY46Dlb.js +1 -0
  101. package/core/built/admin/assets/copy-field-DRBx6Ady.js +1 -0
  102. package/core/built/admin/assets/create-ghost-browse-value-source-eIXo5Qws.js +1 -0
  103. package/core/built/admin/assets/custom-field-type-option-DrSlETOI.js +1 -0
  104. package/core/built/admin/assets/custom-integration-modal-Dgo425Ec.js +1 -0
  105. package/core/built/admin/assets/data-list-DM8yqpXi.js +1 -0
  106. package/core/built/admin/assets/date-range-select-DdC23c13.js +1 -0
  107. package/core/built/admin/assets/design-and-theme-modal-CbSu9IT4.js +2 -0
  108. package/core/built/admin/assets/detail-page-CN4NdhpV.js +1 -0
  109. package/core/built/admin/assets/dirty-confirm-dialog-BT_Vq9TD.js +1 -0
  110. package/core/built/admin/assets/{disabled-sources-indicator-CLZhMv8J.js → disabled-sources-indicator-C5xtW0Q2.js} +1 -1
  111. package/core/built/admin/assets/dist-B40T-RCQ.js +1 -0
  112. package/core/built/admin/assets/dist-CrlaEoaK.js +1 -0
  113. package/core/built/admin/assets/domain-BPReCZa8.js +1 -0
  114. package/core/built/admin/assets/dropzone-B2auMkf2.js +5 -0
  115. package/core/built/admin/assets/edit-profile-B7XTBzKe.js +1 -0
  116. package/core/built/admin/assets/editor-BcaC9dqm.js +8 -0
  117. package/core/built/admin/assets/editor-screen-FuMpItC8.js +27 -0
  118. package/core/built/admin/assets/email-sending-status-provider-9d81o1C2.js +1 -0
  119. package/core/built/admin/assets/embed-signup-form-modal-CbVbMsxl.js +8 -0
  120. package/core/built/admin/assets/empty-indicator-CSQts7GV.js +1 -0
  121. package/core/built/admin/assets/explore-DbSXFTJN.js +1 -0
  122. package/core/built/admin/assets/feature-image-placeholder-DFXA4vfJ.js +1 -0
  123. package/core/built/admin/assets/feed-W7RlF-Gp.js +1 -0
  124. package/core/built/admin/assets/field-BXEh3ptU.js +1 -0
  125. package/core/built/admin/assets/filter-sources-DHK2IoCk.js +1 -0
  126. package/core/built/admin/assets/filters-0SYNTqyQ.js +1 -0
  127. package/core/built/admin/assets/filters-DTtZKQyq.js +1 -0
  128. package/core/built/admin/assets/{first-promoter-modal-wr73Dldc.js → first-promoter-modal-DcoN_OXu.js} +1 -1
  129. package/core/built/admin/assets/{ghost-a1e6e172c6917e8ef8fa6b0007756d9b.js → ghost-25495154132af7305cb7b646fd83f48f.js} +562 -514
  130. package/core/built/admin/assets/gift-link-modal-BX-Q1TOk.js +1 -0
  131. package/core/built/admin/assets/grid-BEUIDQX7.js +1 -0
  132. package/core/built/admin/assets/growth-G6PLO4aF.js +1 -0
  133. package/core/built/admin/assets/growth-tkD-fBOY.js +3 -0
  134. package/core/built/admin/assets/heading-ih-fOVqF.js +1 -0
  135. package/core/built/admin/assets/history-modal-Ca-gStoq.js +1 -0
  136. package/core/built/admin/assets/html-field-B3CrKV9Y.js +1 -0
  137. package/core/built/admin/assets/images-H-BIm8OQ.js +1 -0
  138. package/core/built/admin/assets/{inbox-DgSZ6w2p.js → inbox-DBbDVMPz.js} +14 -14
  139. package/core/built/admin/assets/index-DOF2jDq0.js +4 -0
  140. package/core/built/admin/assets/index-JrrNchW1.css +2 -0
  141. package/core/built/admin/assets/input-group-CvH-3d3F.js +1 -0
  142. package/core/built/admin/assets/input-surface-CL23Mlh8.js +1 -0
  143. package/core/built/admin/assets/integration-header-C7GXGis_.js +1 -0
  144. package/core/built/admin/assets/invite-user-modal-EJ2_6RpV.js +1 -0
  145. package/core/built/admin/assets/isPlainObject-BzzgUf1E.js +1 -0
  146. package/core/built/admin/assets/{koenig-lexical-CXVgQFUk.js → koenig-lexical-Dkwee5FG.js} +1 -1
  147. package/core/built/admin/assets/koenig-loader-BzXCXHoA.js +2 -0
  148. package/core/built/admin/assets/kpi-card-iCDUTgOR.js +1 -0
  149. package/core/built/admin/assets/kpi-card-jTnpLKGr.js +1 -0
  150. package/core/built/admin/assets/kpi-helpers-Criu0YAf.js +1 -0
  151. package/core/built/admin/assets/kpi-tabs-DbOmmyOo.js +1 -0
  152. package/core/built/admin/assets/label-Du0yqMqL.js +1 -0
  153. package/core/built/admin/assets/label-picker-Bq1XXr1D.js +1 -0
  154. package/core/built/admin/assets/{labels-KMkFoRG6.js → labels-0x2NfLtC.js} +1 -1
  155. package/core/built/admin/assets/layout-Ckwzsnsu.js +1 -0
  156. package/core/built/admin/assets/lib-CCz2mjm8.js +2 -0
  157. package/core/built/admin/assets/link-helpers-o9GgBTni.js +1 -0
  158. package/core/built/admin/assets/{links-FwNCVyVe.js → links-Ctujreuh.js} +1 -1
  159. package/core/built/admin/assets/list-page-CH_wnDC3.js +1 -0
  160. package/core/built/admin/assets/member-activity-CsAh6MxK.js +1 -0
  161. package/core/built/admin/assets/member-activity-feed-0ytsQbtY.js +1 -0
  162. package/core/built/admin/assets/member-custom-fields-CTFGnnYv.js +1 -0
  163. package/core/built/admin/assets/member-detail-QU3vB1ML.js +1 -0
  164. package/core/built/admin/assets/members-CtMVO_AB.js +4 -0
  165. package/core/built/admin/assets/modal-page-8Ipfl51B.js +1 -0
  166. package/core/built/admin/assets/moderation-B8VtA-W0.js +1 -0
  167. package/core/built/admin/assets/multi-select-combobox-_9wEYmGv.js +1 -0
  168. package/core/built/admin/assets/navigation-modal-CGcjJvkc.js +1 -0
  169. package/core/built/admin/assets/newsletter-BpHjjqmq.js +1 -0
  170. package/core/built/admin/assets/newsletter-detail-modal-DzTbGOyo.js +1 -0
  171. package/core/built/admin/assets/newsletter-emails-BMKH4Osp.js +1 -0
  172. package/core/built/admin/assets/newsletters-BxC84_cL.js +1 -0
  173. package/core/built/admin/assets/note-BPtEzzZS.js +1 -0
  174. package/core/built/admin/assets/notifications-ng3ulEdp.js +1 -0
  175. package/core/built/admin/assets/offers-container-modal-CwqnRa3T.js +1 -0
  176. package/core/built/admin/assets/onboarding-route-CplZzd7F.js +1 -0
  177. package/core/built/admin/assets/overview-B0yD9OoX.js +1 -0
  178. package/core/built/admin/assets/overview-C4eJzQqi.js +1 -0
  179. package/core/built/admin/assets/page-header-CdCpekG9.js +1 -0
  180. package/core/built/admin/assets/pagemenu-CKQD9hoP.js +1 -0
  181. package/core/built/admin/assets/pages-route-CKsnxIvw.js +1 -0
  182. package/core/built/admin/assets/{pintura-modal-BljM7hf8.js → pintura-modal-C5jzeyGk.js} +1 -1
  183. package/core/built/admin/assets/portal-frame-DYo0bh0E.js +1 -0
  184. package/core/built/admin/assets/portal-modal-C0d8xjKa.js +1 -0
  185. package/core/built/admin/assets/post-analytics-C5C7IyAm.js +1 -0
  186. package/core/built/admin/assets/post-analytics-header-DKWHwoK2.js +1 -0
  187. package/core/built/admin/assets/{post-analytics-provider-CgreZDjS.js → post-analytics-provider-BqCPPxmW.js} +1 -1
  188. package/core/built/admin/assets/post-share-modal-wxmqbAv_.js +1 -0
  189. package/core/built/admin/assets/posts-list-screen-B978ZO0R.js +2 -0
  190. package/core/built/admin/assets/posts-route-CDqxKazl.js +1 -0
  191. package/core/built/admin/assets/preferences-CnejTRc4.js +5 -0
  192. package/core/built/admin/assets/preview-chrome-C7yZWVLZ.js +1 -0
  193. package/core/built/admin/assets/preview-modal-CFUxUGHp.js +1 -0
  194. package/core/built/admin/assets/profile-ClRGiOqA.js +1 -0
  195. package/core/built/admin/assets/radio-group-CTmLo0h9.js +1 -0
  196. package/core/built/admin/assets/router-provider-DDZvgS3V.js +1 -0
  197. package/core/built/admin/assets/select-D_4xWFYv.js +1 -0
  198. package/core/built/admin/assets/settings-BRl7-7a9.js +1 -0
  199. package/core/built/admin/assets/settings-BoQcPa-y.js +4 -0
  200. package/core/built/admin/assets/settings-breadcrumbs-C9Yxl81q.js +1 -0
  201. package/core/built/admin/assets/{dist-BXHrDV19.js → shade-scope-Cccj-c7I-D0XwkdKQ.js} +5 -3
  202. package/core/built/admin/assets/share-modal-DBqZobuR.js +1 -0
  203. package/core/built/admin/assets/simple-pagination-D5t_ox6x.js +1 -0
  204. package/core/built/admin/assets/skeleton-CPcTiTSX.js +1 -0
  205. package/core/built/admin/assets/{slack-modal-D7W_fNON.js → slack-modal-BF9ex8cd.js} +1 -1
  206. package/core/built/admin/assets/sort-button-C0EXGjnS.js +1 -0
  207. package/core/built/admin/assets/{source-icon-CQboPZQ3.js → source-icon-BzzftCQ2.js} +1 -1
  208. package/core/built/admin/assets/stats-view-CzpGoHzF.js +1 -0
  209. package/core/built/admin/assets/{step-1-BKhjy0PV.js → step-1-CBUYUPPF.js} +1 -1
  210. package/core/built/admin/assets/{step-2-PxA1OM7R.js → step-2-CEIXUwQa.js} +1 -1
  211. package/core/built/admin/assets/{step-3-BJbAiq16.js → step-3-C1HA5i1N.js} +2 -2
  212. package/core/built/admin/assets/stripe-button-DMFsLs80.js +1 -0
  213. package/core/built/admin/assets/stripe-connect-modal-CEvxCUTv.js +1 -0
  214. package/core/built/admin/assets/switch-DoOJF2yg.js +1 -0
  215. package/core/built/admin/assets/table-BDYbUHJz.js +1 -0
  216. package/core/built/admin/assets/tabs-BZyz4ZCH.js +1 -0
  217. package/core/built/admin/assets/tag-detail-CFzaz_9E.js +2 -0
  218. package/core/built/admin/assets/tag-picker-BKUCZuRc.js +1 -0
  219. package/core/built/admin/assets/tags-Bs1FiD7m.js +1 -0
  220. package/core/built/admin/assets/{testimonials-modal-Dkt6ODLW.js → testimonials-modal-CVm0_7E-.js} +1 -1
  221. package/core/built/admin/assets/text-BLI0C8Mc.js +1 -0
  222. package/core/built/admin/assets/textarea-C5qolByg.js +1 -0
  223. package/core/built/admin/assets/tier-detail-modal-Cmwzi-e7.js +1 -0
  224. package/core/built/admin/assets/toggle-group-BTL1QsWY.js +1 -0
  225. package/core/built/admin/assets/{topic-filter-DVOe3D-b.js → topic-filter-BMjhquv7.js} +1 -1
  226. package/core/built/admin/assets/transistor-modal-hMv53jF8.js +1 -0
  227. package/core/built/admin/assets/trend-badge-1w_HEzkG.js +1 -0
  228. package/core/built/admin/assets/{unsplash-modal-DXt7Brum.js → unsplash-modal-jzC8lEB2.js} +1 -1
  229. package/core/built/admin/assets/use-analytics-data-B3lGOxsC.js +1 -0
  230. package/core/built/admin/assets/use-availability-DnKqOyqd.js +1 -0
  231. package/core/built/admin/assets/{use-check-theme-limit-error-JD-J5aaZ.js → use-check-theme-limit-error-C1tc2P4N.js} +2 -2
  232. package/core/built/admin/assets/use-filter-params-DU-aiaTb.js +1 -0
  233. package/core/built/admin/assets/{use-filterable-api-CEMSAYPg.js → use-filterable-api-CxCrnPxG.js} +1 -1
  234. package/core/built/admin/assets/use-growth-stats-E13rMQUE.js +1 -0
  235. package/core/built/admin/assets/use-limiter-DlL7au90.js +19 -0
  236. package/core/built/admin/assets/{use-navigate-with-base-path-88EQpw2k.js → use-navigate-with-base-path-BzgNwMAx.js} +1 -1
  237. package/core/built/admin/assets/{use-pintura-config-BmU45Ruy.js → use-pintura-config-CtEV1JQY.js} +1 -1
  238. package/core/built/admin/assets/{use-pintura-editor-Bz2bZ4iT.js → use-pintura-editor-CaxE64kD.js} +1 -1
  239. package/core/built/admin/assets/use-reply-chain-data-BST2OgCM.js +1 -0
  240. package/core/built/admin/assets/use-sending-eta-DR9ueMH8.js +1 -0
  241. package/core/built/admin/assets/use-setting-group-ldtX1Vsk.js +1 -0
  242. package/core/built/admin/assets/use-settings-navigation-CzGU4sus.js +1 -0
  243. package/core/built/admin/assets/use-staff-users-DoeXaPsb.js +1 -0
  244. package/core/built/admin/assets/use-tinybird-query-BaBNCaj0.js +1 -0
  245. package/core/built/admin/assets/{use-tinybird-token-Lk1RSn0t.js → use-tinybird-token-CnZ19NDf.js} +1 -1
  246. package/core/built/admin/assets/{use-url-input-DpmbDppC.js → use-url-input-C5KHJw79.js} +1 -1
  247. package/core/built/admin/assets/user-detail-modal-Dm0KfPeR.js +1 -0
  248. package/core/built/admin/assets/{vendor-2dd263291938d407802568d3357ec69e.js → vendor-97e91ff8dd1457c668f9ef103ee1a77b.js} +2748 -2977
  249. package/core/built/admin/assets/virtual-list-tAuPUICw.js +1 -0
  250. package/core/built/admin/assets/web-BQlKcW2x.js +2 -0
  251. package/core/built/admin/assets/web-NTT5DkEz.js +1 -0
  252. package/core/built/admin/assets/{zapier-modal-BafLUO4R.js → zapier-modal-DsHG9Oev.js} +1 -1
  253. package/core/built/admin/index.html +22 -24
  254. package/core/frontend/apps/private-blogging/index.js +2 -2
  255. package/core/frontend/apps/private-blogging/lib/middleware.js +1 -1
  256. package/core/frontend/apps/private-blogging/lib/router.js +1 -1
  257. package/core/frontend/helpers/cancel_link.js +3 -3
  258. package/core/frontend/helpers/content.js +2 -2
  259. package/core/frontend/helpers/content_api_url.js +1 -1
  260. package/core/frontend/helpers/date.js +1 -1
  261. package/core/frontend/helpers/foreach.js +5 -5
  262. package/core/frontend/helpers/get.js +7 -4
  263. package/core/frontend/helpers/ghost_head.js +2 -2
  264. package/core/frontend/helpers/has.js +1 -3
  265. package/core/frontend/helpers/link.js +7 -7
  266. package/core/frontend/helpers/link_class.js +2 -2
  267. package/core/frontend/helpers/navigation.js +1 -2
  268. package/core/frontend/helpers/recommendations.js +5 -6
  269. package/core/frontend/helpers/tiers.js +1 -1
  270. package/core/frontend/helpers/total_members.js +1 -1
  271. package/core/frontend/helpers/total_paid_members.js +1 -1
  272. package/core/frontend/meta/author-url.js +1 -1
  273. package/core/frontend/meta/modified-date.js +1 -1
  274. package/core/frontend/meta/published-date.js +1 -1
  275. package/core/frontend/meta/schema.js +3 -8
  276. package/core/frontend/meta/structured-data.js +1 -2
  277. package/core/frontend/services/assets-minification/minifier.js +1 -1
  278. package/core/frontend/services/data/entry-lookup.js +1 -1
  279. package/core/frontend/services/data/fetch-data.js +2 -2
  280. package/core/frontend/services/rendering/format-response.js +1 -1
  281. package/core/frontend/services/rendering/renderer.js +3 -0
  282. package/core/frontend/services/rendering/templates.js +1 -1
  283. package/core/frontend/services/routing/controllers/static.js +1 -1
  284. package/core/frontend/services/routing/parent-router.js +1 -1
  285. package/core/frontend/services/routing/registry.js +1 -1
  286. package/core/frontend/services/sitemap/base-site-map-generator.js +68 -97
  287. package/core/frontend/services/sitemap/site-map-index-generator.js +16 -21
  288. package/core/frontend/services/sitemap/site-map-manager.js +82 -43
  289. package/core/frontend/services/sitemap/sitemap-xml.js +72 -0
  290. package/core/frontend/services/theme-engine/handlebars/utils.js +8 -8
  291. package/core/frontend/services/theme-engine/i18n/i18n.js +4 -5
  292. package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +1 -1
  293. package/core/frontend/services/theme-engine/preview.js +1 -1
  294. package/core/frontend/utils/member-count.js +2 -2
  295. package/core/frontend/web/routers/serve-public-file.js +1 -1
  296. package/core/server/adapters/scheduling/README.md +4 -0
  297. package/core/server/adapters/scheduling/get-scheduler-idempotency-key.js +21 -0
  298. package/core/server/adapters/storage/LocalStorageBase.js +2 -1
  299. package/core/server/api/endpoints/automated-emails.js +8 -2
  300. package/core/server/api/endpoints/db.js +1 -1
  301. package/core/server/api/endpoints/emails.js +3 -3
  302. package/core/server/api/endpoints/mail.js +1 -1
  303. package/core/server/api/endpoints/member-signin-urls.js +1 -1
  304. package/core/server/api/endpoints/members.js +3 -3
  305. package/core/server/api/endpoints/oembed.js +1 -1
  306. package/core/server/api/endpoints/posts.js +1 -1
  307. package/core/server/api/endpoints/settings.js +2 -2
  308. package/core/server/api/endpoints/themes.js +5 -5
  309. package/core/server/api/endpoints/utils/serializers/input/pages.js +2 -2
  310. package/core/server/api/endpoints/utils/serializers/input/posts.js +2 -2
  311. package/core/server/api/endpoints/utils/serializers/input/tags.js +1 -1
  312. package/core/server/api/endpoints/utils/serializers/input/utils/slug-filter-order.js +4 -4
  313. package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +8 -5
  314. package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +1 -1
  315. package/core/server/api/endpoints/utils/serializers/output/pages.js +4 -4
  316. package/core/server/api/endpoints/utils/serializers/output/posts.js +4 -4
  317. package/core/server/api/endpoints/utils/serializers/output/search-index.js +11 -11
  318. package/core/server/api/endpoints/utils/serializers/output/settings.js +1 -1
  319. package/core/server/api/endpoints/utils/serializers/output/utils/extra-attrs.js +3 -3
  320. package/core/server/api/endpoints/utils/validators/input/automated_emails.js +23 -33
  321. package/core/server/api/endpoints/utils/validators/input/settings.js +3 -3
  322. package/core/server/data/exporter/exporter.js +1 -2
  323. package/core/server/data/exporter/table-lists.js +1 -0
  324. package/core/server/data/importer/handlers/image.js +1 -2
  325. package/core/server/data/importer/handlers/json.js +1 -3
  326. package/core/server/data/importer/handlers/markdown.js +4 -8
  327. package/core/server/data/importer/import-manager.js +1 -1
  328. package/core/server/data/importer/importers/content-file-importer.js +4 -8
  329. package/core/server/data/importer/importers/data/base.js +10 -10
  330. package/core/server/data/importer/importers/data/custom-theme-settings-importer.js +1 -1
  331. package/core/server/data/importer/importers/data/data-importer.js +3 -4
  332. package/core/server/data/importer/importers/data/posts-importer.js +10 -10
  333. package/core/server/data/importer/importers/data/products-importer.js +3 -3
  334. package/core/server/data/importer/importers/data/settings-importer.js +2 -2
  335. package/core/server/data/importer/importers/data/stripe-prices-importer.js +1 -1
  336. package/core/server/data/importer/importers/data/stripe-products-importer.js +1 -1
  337. package/core/server/data/importer/importers/data/tags-importer.js +1 -1
  338. package/core/server/data/importer/importers/data/users-importer.js +2 -2
  339. package/core/server/data/importer/importers/json-to-html.js +12 -9
  340. package/core/server/data/migrations/versions/5.0/2022-05-11-13-12-rename-settings.js +1 -1
  341. package/core/server/data/migrations/versions/6.65/2026-09-16-15-35-26-add-members-metafield-change-events.js +17 -0
  342. package/core/server/data/schema/fixtures/fixture-manager.js +3 -3
  343. package/core/server/data/schema/index.js +1 -1
  344. package/core/server/data/schema/schema.js +26 -0
  345. package/core/server/data/schema/validator.js +96 -123
  346. package/core/server/data/seeders/importers/email-recipients-importer.js +2 -2
  347. package/core/server/data/seeders/importers/members-login-events-importer.js +1 -1
  348. package/core/server/data/seeders/importers/members-newsletters-importer.js +1 -1
  349. package/core/server/data/seeders/importers/members-paid-subscription-events-importer.js +1 -1
  350. package/core/server/data/seeders/importers/members-status-events-importer.js +1 -1
  351. package/core/server/data/seeders/importers/members-stripe-customers-importer.js +1 -1
  352. package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +1 -1
  353. package/core/server/data/seeders/importers/members-subscribe-events-importer.js +2 -2
  354. package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +1 -1
  355. package/core/server/data/tinybird/pipes/mv_hits.pipe +25 -20
  356. package/core/server/data/tinybird/scripts/docker-analytics-manager.js +2 -2
  357. package/core/server/ghost-server.js +1 -19
  358. package/core/server/lib/image/image-size.js +1 -3
  359. package/core/server/lib/request-external.js +53 -117
  360. package/core/server/models/base/plugins/actions.js +2 -3
  361. package/core/server/models/base/plugins/crud.js +1 -2
  362. package/core/server/models/base/plugins/events.js +4 -4
  363. package/core/server/models/base/plugins/raw-knex.js +3 -3
  364. package/core/server/models/base/plugins/sanitize.js +1 -1
  365. package/core/server/models/benefit.js +1 -1
  366. package/core/server/models/collection.js +1 -1
  367. package/core/server/models/comment.js +3 -3
  368. package/core/server/models/invite.js +2 -5
  369. package/core/server/models/label.js +3 -6
  370. package/core/server/models/member.js +7 -10
  371. package/core/server/models/newsletter.js +1 -1
  372. package/core/server/models/permission.js +3 -6
  373. package/core/server/models/post.js +20 -23
  374. package/core/server/models/product.js +4 -1
  375. package/core/server/models/relations/authors.js +9 -12
  376. package/core/server/models/role.js +2 -5
  377. package/core/server/models/settings.js +3 -3
  378. package/core/server/models/tag.js +2 -5
  379. package/core/server/models/user.js +8 -10
  380. package/core/server/models/webhook.js +2 -4
  381. package/core/server/notify.js +2 -2
  382. package/core/server/services/adapter-manager/utils.js +6 -1
  383. package/core/server/services/api-version-compatibility/legacy-api-path-match.js +2 -2
  384. package/core/server/services/auth/api-key/admin.js +2 -2
  385. package/core/server/services/auth/api-key/content.js +1 -1
  386. package/core/server/services/auth/passwordreset.js +1 -1
  387. package/core/server/services/auth/setup.js +1 -3
  388. package/core/server/services/automations/README.md +19 -0
  389. package/core/server/services/automations/poll.js +3 -1
  390. package/core/server/services/automations/service.js +2 -2
  391. package/core/server/services/automations/welcome-email-automation-poll.js +199 -293
  392. package/core/server/services/comments/comments-controller.js +9 -30
  393. package/core/server/services/comments/comments-service-email-renderer.js +1 -1
  394. package/core/server/services/comments/comments-service-emails.js +1 -1
  395. package/core/server/services/comments/comments-service.js +27 -58
  396. package/core/server/services/comments/comments-stats-service.js +1 -1
  397. package/core/server/services/content-import/import/staged-file.js +9 -9
  398. package/core/server/services/content-import/index.js +1 -1
  399. package/core/server/services/custom-redirects/validation.js +1 -1
  400. package/core/server/services/email-analytics/email-analytics-service-wrapper.js +23 -55
  401. package/core/server/services/email-analytics/index.js +35 -19
  402. package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.js +31 -60
  403. package/core/server/services/email-service/README.md +35 -0
  404. package/core/server/services/email-service/batch-sending-service.js +13 -14
  405. package/core/server/services/email-service/email-renderer.js +50 -14
  406. package/core/server/services/email-service/email-service-wrapper.js +3 -2
  407. package/core/server/services/email-service/email-service.js +33 -8
  408. package/core/server/services/email-service/email-templates/partials/feedback-button.hbs +2 -1
  409. package/core/server/services/email-service/email-templates/partials/styles.hbs +0 -6
  410. package/core/server/services/email-service/email-templates/template.hbs +1 -1
  411. package/core/server/services/email-service/jobs/send-email-job.js +12 -0
  412. package/core/server/services/email-service/mailgun-email-provider.js +7 -2
  413. package/core/server/services/email-service/sending-service.js +1 -1
  414. package/core/server/services/gifts/gift-service.js +12 -3
  415. package/core/server/services/gifts/index.js +0 -2
  416. package/core/server/services/gifts/jobs/index.js +12 -24
  417. package/core/server/services/gifts/jobs/send-gift-reminders-job.js +6 -46
  418. package/core/server/services/invitations/accept.js +2 -2
  419. package/core/server/services/jobs/job-service.js +0 -28
  420. package/core/server/services/jobs-service/jobs-service.js +5 -0
  421. package/core/server/services/jobs-service/register-job-handlers.js +17 -1
  422. package/core/server/services/lib/mailgun-client.js +16 -1
  423. package/core/server/services/lib/mailgun-recipient-message-id.js +49 -0
  424. package/core/server/services/limits.js +1 -1
  425. package/core/server/services/mail/ghost-mailer.js +1 -1
  426. package/core/server/services/member-attribution/member-attribution-service.js +1 -1
  427. package/core/server/services/member-attribution/referrer-translator.js +1 -1
  428. package/core/server/services/members/account-service.js +3 -3
  429. package/core/server/services/members/api.js +1 -1
  430. package/core/server/services/members/import-export/import/importer.js +25 -16
  431. package/core/server/services/members/import-export/import/spool.js +11 -15
  432. package/core/server/services/members/import-export/index.js +6 -4
  433. package/core/server/services/members/jobs/index.js +1 -1
  434. package/core/server/services/members/jobs/members-import-job.js +18 -0
  435. package/core/server/services/members/member-avatar.js +18 -0
  436. package/core/server/services/members/members-api/controllers/member-controller.js +2 -2
  437. package/core/server/services/members/members-api/members-api.js +4 -4
  438. package/core/server/services/members/members-api/repositories/event-repository.js +36 -1
  439. package/core/server/services/members/members-api/repositories/member-repository.js +55 -17
  440. package/core/server/services/members/members-api/repositories/product-repository.js +1 -1
  441. package/core/server/services/members/members-api/services/member-bread-service.js +4 -7
  442. package/core/server/services/members/service.js +7 -2
  443. package/core/server/services/members/stats/members-stats.js +2 -2
  444. package/core/server/services/members-events/event-storage.js +2 -2
  445. package/core/server/services/members-metafields/actions.js +23 -2
  446. package/core/server/services/members-metafields/bindings-service.js +5 -5
  447. package/core/server/services/members-metafields/definitions-service.js +2 -7
  448. package/core/server/services/members-metafields/index.js +2 -1
  449. package/core/server/services/members-metafields/queries.js +7 -1
  450. package/core/server/services/members-metafields/schema.js +49 -1
  451. package/core/server/services/members-metafields/values-service.js +112 -10
  452. package/core/server/services/mentions/mention-sending-service.js +2 -2
  453. package/core/server/services/mentions/mention.js +3 -4
  454. package/core/server/services/mentions/mentions-api.js +4 -1
  455. package/core/server/services/mentions-jobs/job-service.js +0 -28
  456. package/core/server/services/milestones/milestones-service.js +1 -1
  457. package/core/server/services/newsletters/newsletters-service.js +1 -1
  458. package/core/server/services/notifications/notifications.js +3 -3
  459. package/core/server/services/oembed/oembed-service.js +79 -3
  460. package/core/server/services/permissions/can-this.js +1 -2
  461. package/core/server/services/post-scheduling/post-scheduling.js +8 -1
  462. package/core/server/services/posts/post-scheduling.js +7 -0
  463. package/core/server/services/settings/settings-bread-service.js +3 -3
  464. package/core/server/services/settings/settings-utils.js +1 -1
  465. package/core/server/services/settings-helpers/settings-helpers.js +1 -1
  466. package/core/server/services/staff/staff-service-emails.js +9 -9
  467. package/core/server/services/stats/posts-stats-service.js +10 -10
  468. package/core/server/services/stats/referrers-stats-service.js +1 -1
  469. package/core/server/services/stats/subscription-stats-service.js +3 -3
  470. package/core/server/services/stats/utils/tinybird.js +8 -1
  471. package/core/server/services/stripe/stripe-api.js +3 -3
  472. package/core/server/services/stripe/stripe-migrations.js +6 -6
  473. package/core/server/services/themes/storage.js +21 -26
  474. package/core/server/services/themes/theme-storage.js +2 -2
  475. package/core/server/services/tiers/tier.js +15 -15
  476. package/core/server/services/tinybird-sync/index.js +3 -0
  477. package/core/server/services/tinybird-sync/tinybird-sync-service.js +7 -2
  478. package/core/server/services/update-check/update-check-service.js +3 -3
  479. package/core/server/services/webhooks/serialize.js +1 -1
  480. package/core/server/web/api/app.js +0 -5
  481. package/core/server/web/api/middleware/upload.js +29 -2
  482. package/core/server/web/parent/middleware/index.js +1 -1
  483. package/core/server/web/parent/middleware/log-request.js +5 -0
  484. package/core/server/web/parent/middleware/queue-request.js +104 -59
  485. package/core/server/web/shared/middleware/api/spam-prevention.js +2 -2
  486. package/core/shared/config/defaults.json +6 -1
  487. package/core/shared/custom-theme-settings-cache/custom-theme-settings-service.js +1 -1
  488. package/core/shared/labs.js +3 -2
  489. package/core/shared/settings-cache/cache-manager.js +1 -1
  490. package/nodemon.json +1 -1
  491. package/package.json +6 -7
  492. package/pnpm-lock.yaml +126 -728
  493. package/pnpm-workspace.yaml +4 -7
  494. package/tsconfig.json +1 -1
  495. package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
  496. package/core/built/admin/assets/Combination-DWfJPcz9.js +0 -41
  497. package/core/built/admin/assets/RadialBarChart-CHRBhiBN.js +0 -1
  498. package/core/built/admin/assets/_baseAssignValue-DcPokYW8.js +0 -1
  499. package/core/built/admin/assets/accordion-CJmRaqK7.js +0 -1
  500. package/core/built/admin/assets/account-migration-DYf7skbb.js +0 -1
  501. package/core/built/admin/assets/action-list-Crnh-_UI.js +0 -1
  502. package/core/built/admin/assets/activitypub/avatar-DVJF5bxP.js +0 -261
  503. package/core/built/admin/assets/activitypub/layout-BL4_jtuV.js +0 -1
  504. package/core/built/admin/assets/activitypub/routes-DdyY9uFF.js +0 -7181
  505. package/core/built/admin/assets/activitypub/settings-B6EEcVkW.js +0 -315
  506. package/core/built/admin/assets/activitypub/tabs-DLhZtVde.js +0 -1083
  507. package/core/built/admin/assets/activitypub/users-inweyKL5.js +0 -1499
  508. package/core/built/admin/assets/add-newsletter-modal-CTvXiIqY.js +0 -1
  509. package/core/built/admin/assets/analytics-PHR1Fggi.js +0 -1
  510. package/core/built/admin/assets/announcement-bar-modal-Bql0CXdp.js +0 -1
  511. package/core/built/admin/assets/api-keys-CubH-7_H.js +0 -1
  512. package/core/built/admin/assets/automations-DcZSLFDU.js +0 -1
  513. package/core/built/admin/assets/badge-qP06OT7C.js +0 -1
  514. package/core/built/admin/assets/bluesky-sharing-CJw4d4Mf.js +0 -1
  515. package/core/built/admin/assets/box-CZ_LSVSy.js +0 -1
  516. package/core/built/admin/assets/brand-icon-D3ffDYaC.js +0 -1
  517. package/core/built/admin/assets/breadcrumb-Chn1Ip_q.js +0 -1
  518. package/core/built/admin/assets/button-DvIh2Bq-.js +0 -1
  519. package/core/built/admin/assets/calendar-1QGoStFM.js +0 -1
  520. package/core/built/admin/assets/card-FHQ4D10L.js +0 -1
  521. package/core/built/admin/assets/chart-helpers-CNpA7re_.js +0 -1
  522. package/core/built/admin/assets/chart-jVz9Nf9t.js +0 -63
  523. package/core/built/admin/assets/checkbox-DKht9xMl.js +0 -1
  524. package/core/built/admin/assets/chunk.524.cc9be98e44890cedc8c8.js +0 -25
  525. package/core/built/admin/assets/chunk.582.e6fe742b3217207b11a6.js +0 -27
  526. package/core/built/admin/assets/code-editor-view-BLQIV85-.js +0 -1
  527. package/core/built/admin/assets/code-editor-view-Cg5eJxcr.js +0 -1
  528. package/core/built/admin/assets/color-picker-DQoghc0t.js +0 -3
  529. package/core/built/admin/assets/color-picker-field-BbeK5RRs.js +0 -1
  530. package/core/built/admin/assets/combobox-weO4FBbv.js +0 -1
  531. package/core/built/admin/assets/command-DlLrCm9V.js +0 -1
  532. package/core/built/admin/assets/comments-BjTitLmP.js +0 -1
  533. package/core/built/admin/assets/confirmation-context-IyqoXVk-.js +0 -1
  534. package/core/built/admin/assets/container-DAimjOF_.js +0 -1
  535. package/core/built/admin/assets/context-menu-BtioYFrg.js +0 -1
  536. package/core/built/admin/assets/copy-field-C6ujqJlP.js +0 -1
  537. package/core/built/admin/assets/create-ghost-browse-value-source-DAZMWZNq.js +0 -1
  538. package/core/built/admin/assets/custom-integration-modal-Dm8QI_J4.js +0 -1
  539. package/core/built/admin/assets/data-list-C0CKkeWW.js +0 -1
  540. package/core/built/admin/assets/date-range-select-DrjHQdgz.js +0 -1
  541. package/core/built/admin/assets/design-and-theme-modal-CXVOzBWu.js +0 -2
  542. package/core/built/admin/assets/detail-page-QpLIL-EO.js +0 -1
  543. package/core/built/admin/assets/dirty-confirm-dialog-DWwxREGh.js +0 -1
  544. package/core/built/admin/assets/dist-Bf-HQtVL.js +0 -1
  545. package/core/built/admin/assets/dist-CUwte9v_.js +0 -1
  546. package/core/built/admin/assets/dist-FEQQAwTe.js +0 -1
  547. package/core/built/admin/assets/domain-DBrBic6q.js +0 -1
  548. package/core/built/admin/assets/dropzone-D61QVcEY.js +0 -5
  549. package/core/built/admin/assets/edit-profile-jCqJBxqw.js +0 -1
  550. package/core/built/admin/assets/editor-8Fm4UBEd.js +0 -8
  551. package/core/built/admin/assets/editor-screen-BSX_uC2B.js +0 -27
  552. package/core/built/admin/assets/email-sending-status-provider-DnNhlIvt.js +0 -1
  553. package/core/built/admin/assets/embed-signup-form-modal-DqtBs1WE.js +0 -8
  554. package/core/built/admin/assets/empty-indicator-L4Ql5Db7.js +0 -1
  555. package/core/built/admin/assets/en-Cx75dJv5.js +0 -1
  556. package/core/built/admin/assets/explore-DXhDCtKw.js +0 -1
  557. package/core/built/admin/assets/feature-image-placeholder-e2q6TcH6.js +0 -1
  558. package/core/built/admin/assets/feed-mmt4noNL.js +0 -1
  559. package/core/built/admin/assets/field-p7KnP98B.js +0 -1
  560. package/core/built/admin/assets/filter-bar-CiIKBg3D.js +0 -1
  561. package/core/built/admin/assets/filter-sources-I-dRaQxl.js +0 -1
  562. package/core/built/admin/assets/filters-1injvyxJ.js +0 -1
  563. package/core/built/admin/assets/filters-DnpO6GWX.js +0 -1
  564. package/core/built/admin/assets/gift-link-modal-C3H7YFXO.js +0 -1
  565. package/core/built/admin/assets/grid-5vplBYri.js +0 -1
  566. package/core/built/admin/assets/growth-B1og1kQp.js +0 -1
  567. package/core/built/admin/assets/growth-Bf6OHZlK.js +0 -3
  568. package/core/built/admin/assets/heading-BB21QAbb.js +0 -1
  569. package/core/built/admin/assets/history-modal-t_qEnxPx.js +0 -1
  570. package/core/built/admin/assets/html-field-COLQbV4r.js +0 -1
  571. package/core/built/admin/assets/images-4mvoc3lB.js +0 -1
  572. package/core/built/admin/assets/index-B3HZU2i8.css +0 -2
  573. package/core/built/admin/assets/index-DDd-zhNL.js +0 -4
  574. package/core/built/admin/assets/inline-B8H6NzIw.js +0 -1
  575. package/core/built/admin/assets/input-group-CLIN2ykI.js +0 -1
  576. package/core/built/admin/assets/input-surface-wSO5CRy5.js +0 -1
  577. package/core/built/admin/assets/integration-header-CKGrXNVP.js +0 -1
  578. package/core/built/admin/assets/invite-user-modal-BaN2mdhI.js +0 -1
  579. package/core/built/admin/assets/koenig-loader-B1XPPY5C.js +0 -2
  580. package/core/built/admin/assets/kpi-card-CRLPVlFW.js +0 -1
  581. package/core/built/admin/assets/kpi-card-CRPbW8NZ.js +0 -1
  582. package/core/built/admin/assets/kpi-helpers-D7zT96bp.js +0 -1
  583. package/core/built/admin/assets/kpi-tabs-DE_yh9Go.js +0 -1
  584. package/core/built/admin/assets/label-CgeBxy4o.js +0 -1
  585. package/core/built/admin/assets/label-picker-DGDp4Vwr.js +0 -1
  586. package/core/built/admin/assets/layout-DWnOMly4.js +0 -1
  587. package/core/built/admin/assets/lib-_QYaUU89.js +0 -2
  588. package/core/built/admin/assets/link-helpers-8J7ixADV.js +0 -1
  589. package/core/built/admin/assets/list-page-DLMP0PxC.js +0 -1
  590. package/core/built/admin/assets/member-activity-ClMWFyvN.js +0 -1
  591. package/core/built/admin/assets/member-activity-feed-BQY5Rwaj.js +0 -1
  592. package/core/built/admin/assets/member-custom-fields-Dd_ie1zG.js +0 -1
  593. package/core/built/admin/assets/member-detail-DjwkGVne.js +0 -1
  594. package/core/built/admin/assets/members--N9lhk1N.js +0 -4
  595. package/core/built/admin/assets/modal-page-Dz-9TP4E.js +0 -1
  596. package/core/built/admin/assets/moderation-DfYBKq9s.js +0 -1
  597. package/core/built/admin/assets/multi-select-combobox-BcBEzUW_.js +0 -1
  598. package/core/built/admin/assets/navigation-modal-Cd-scywg.js +0 -1
  599. package/core/built/admin/assets/newsletter-detail-modal-CFRY6vg_.js +0 -1
  600. package/core/built/admin/assets/newsletter-emails-4ntck1AC.js +0 -1
  601. package/core/built/admin/assets/newsletter-o6eCJtab.js +0 -1
  602. package/core/built/admin/assets/newsletters-Bmlv0edG.js +0 -1
  603. package/core/built/admin/assets/note-CWs3LF-0.js +0 -1
  604. package/core/built/admin/assets/notifications-BjSvTJqh.js +0 -1
  605. package/core/built/admin/assets/offers-container-modal-Bc9A196w.js +0 -1
  606. package/core/built/admin/assets/onboarding-route-Di1LJYEE.js +0 -1
  607. package/core/built/admin/assets/overview-DE7NHZQN.js +0 -1
  608. package/core/built/admin/assets/overview-DEF-ZY6x.js +0 -1
  609. package/core/built/admin/assets/page-header-B-G_g42C.js +0 -1
  610. package/core/built/admin/assets/pagemenu-CnkTDO71.js +0 -1
  611. package/core/built/admin/assets/pages-route-VT7r7YhG.js +0 -1
  612. package/core/built/admin/assets/portal-frame-D9V8iq5x.js +0 -1
  613. package/core/built/admin/assets/portal-modal-B5OOR9ZD.js +0 -1
  614. package/core/built/admin/assets/post-analytics-header-J0WciLx6.js +0 -1
  615. package/core/built/admin/assets/post-analytics-rGb-PgD-.js +0 -1
  616. package/core/built/admin/assets/post-share-modal-D0BbTo4W.js +0 -1
  617. package/core/built/admin/assets/posts-list-screen-CO5jAWoU.js +0 -2
  618. package/core/built/admin/assets/posts-route-DV-CXWK9.js +0 -1
  619. package/core/built/admin/assets/preferences-Tac29oG6.js +0 -5
  620. package/core/built/admin/assets/preview-chrome-C2lQgZBZ.js +0 -1
  621. package/core/built/admin/assets/preview-modal-CjRbBr8U.js +0 -1
  622. package/core/built/admin/assets/profile-yiM1f_Og.js +0 -1
  623. package/core/built/admin/assets/radio-group-CKROWsw4.js +0 -1
  624. package/core/built/admin/assets/router-provider-CU87qxXw.js +0 -1
  625. package/core/built/admin/assets/select-CKaC4ggu.js +0 -1
  626. package/core/built/admin/assets/settings-81kxUa28.js +0 -1
  627. package/core/built/admin/assets/settings-BVXFqBVK.js +0 -4
  628. package/core/built/admin/assets/settings-breadcrumbs-czGRx-iu.js +0 -1
  629. package/core/built/admin/assets/shade-app-CcS3f8MZ-D5BnfHck.js +0 -3
  630. package/core/built/admin/assets/share-modal-BL-16PiB.js +0 -1
  631. package/core/built/admin/assets/skeleton-DwCva0-b.js +0 -1
  632. package/core/built/admin/assets/sort-button-Dquc83jY.js +0 -1
  633. package/core/built/admin/assets/stack-BURz77VS.js +0 -1
  634. package/core/built/admin/assets/stats-view-NDja_g96.js +0 -1
  635. package/core/built/admin/assets/stripe-button-C3cfCAou.js +0 -1
  636. package/core/built/admin/assets/stripe-connect-modal-FyE3Ey2c.js +0 -1
  637. package/core/built/admin/assets/switch-zfUUy9Jh.js +0 -1
  638. package/core/built/admin/assets/table-dE4GTIRT.js +0 -1
  639. package/core/built/admin/assets/tabs-B3XK93sR.js +0 -1
  640. package/core/built/admin/assets/tag-detail-D4P-tZdM.js +0 -2
  641. package/core/built/admin/assets/tag-picker-BNSZ6Qxw.js +0 -1
  642. package/core/built/admin/assets/tags-BsZcaJ6h.js +0 -1
  643. package/core/built/admin/assets/text-DC-ot6u2.js +0 -1
  644. package/core/built/admin/assets/textarea-B4FffFmE.js +0 -1
  645. package/core/built/admin/assets/tier-detail-modal-a77Z2VMH.js +0 -1
  646. package/core/built/admin/assets/toggle-group-D2p4okmJ.js +0 -1
  647. package/core/built/admin/assets/transistor-modal-C8RMkhOD.js +0 -1
  648. package/core/built/admin/assets/trend-badge-B9v7kMF8.js +0 -1
  649. package/core/built/admin/assets/types-uYQ1HgqL.js +0 -1
  650. package/core/built/admin/assets/use-analytics-data-ChHqiZXv.js +0 -1
  651. package/core/built/admin/assets/use-availability-hPdeG76y.js +0 -1
  652. package/core/built/admin/assets/use-filter-params-BSFigDIn.js +0 -1
  653. package/core/built/admin/assets/use-growth-stats-CqqdnESN.js +0 -1
  654. package/core/built/admin/assets/use-limiter-DBGjYqu7.js +0 -19
  655. package/core/built/admin/assets/use-reply-chain-data-DmD2yX5D.js +0 -1
  656. package/core/built/admin/assets/use-sending-eta-CQeG6OP_.js +0 -1
  657. package/core/built/admin/assets/use-setting-group-Dza6bQ7W.js +0 -1
  658. package/core/built/admin/assets/use-settings-navigation-BIjI5mL3.js +0 -1
  659. package/core/built/admin/assets/use-simple-pagination-DwVxe-Lo.js +0 -1
  660. package/core/built/admin/assets/use-staff-users-i_Mq9OGR.js +0 -1
  661. package/core/built/admin/assets/use-tinybird-query-DXoF74NM.js +0 -1
  662. package/core/built/admin/assets/user-detail-modal-BU4QCHE7.js +0 -1
  663. package/core/built/admin/assets/virtual-list-DScLNuU8.js +0 -1
  664. package/core/built/admin/assets/web-BZS-t4H0.js +0 -1
  665. package/core/built/admin/assets/web-DxAUxnK3.js +0 -2
  666. package/core/frontend/services/sitemap/utils.js +0 -17
  667. package/core/server/services/automations/get-scheduler-idempotency-key.js +0 -13
  668. package/core/server/web/api/testmode/index.js +0 -1
  669. package/core/server/web/api/testmode/jobs/cpu-hog.js +0 -15
  670. package/core/server/web/api/testmode/jobs/graceful-job.js +0 -50
  671. package/core/server/web/api/testmode/jobs/say-hello.js +0 -17
  672. package/core/server/web/api/testmode/routes.js +0 -120
@@ -13,9 +13,7 @@ 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.',
17
16
  cannotCommentOnPost: 'You do not have permission to comment on this post.',
18
- cannotReadComment: 'You do not have permission to read comments on this post',
19
17
  cannotEditComment: 'You do not have permission to edit comments',
20
18
  cannotPinReply: 'Replies cannot be pinned',
21
19
  cannotPinDeletedComment: 'Deleted comments cannot be pinned',
@@ -41,7 +39,8 @@ const COMMENT_STATUSES_IN_REPLY_TO = [COMMENT_STATUS_PUBLISHED, COMMENT_STATUS_H
41
39
  // new `comment.get(...)` call has one obvious place to register its column.
42
40
  const REPLY_PARENT_REQUIRED_COLUMNS = ['parent_id', 'post_id'];
43
41
  const IN_REPLY_TO_REQUIRED_COLUMNS = ['parent_id'];
44
- const OWNERSHIP_REQUIRED_COLUMNS = ['member_id', 'post_id'];
42
+ const OWNERSHIP_REQUIRED_COLUMNS = ['member_id'];
43
+ const VOTE_REQUIRED_COLUMNS = ['post_id'];
45
44
  const REPORT_REQUIRED_COLUMNS = ['post_id', 'member_id', 'html', 'created_at'];
46
45
 
47
46
  function getColumnList(columns) {
@@ -169,14 +168,11 @@ class CommentsService {
169
168
  }
170
169
 
171
170
  /** @private */
172
- checkPostAccess(postModel, memberModel, { action = 'comment' } = {}) {
173
- const access = this.contentGating.checkPostAccess(
174
- postModel.toJSON(),
175
- memberModel ? memberModel.toJSON() : null,
176
- );
171
+ checkPostAccess(postModel, memberModel) {
172
+ const access = this.contentGating.checkPostAccess(postModel.toJSON(), memberModel.toJSON());
177
173
  if (access === this.contentGating.BLOCK_ACCESS) {
178
174
  throw new errors.NoPermissionError({
179
- message: tpl(action === 'read' ? messages.cannotReadComment : messages.cannotCommentOnPost),
175
+ message: tpl(messages.cannotCommentOnPost),
180
176
  });
181
177
  }
182
178
  }
@@ -194,32 +190,6 @@ class CommentsService {
194
190
  });
195
191
  }
196
192
 
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
-
223
193
  /**
224
194
  * Primary comment lookup: a single keyed fetch with the allowed statuses
225
195
  * applied in the query (`WHERE id = ? AND status IN (...)`), optionally locked
@@ -385,9 +355,27 @@ class CommentsService {
385
355
  this.checkCommentAccess(memberModel);
386
356
 
387
357
  return await this.#withTransaction(options, async (transactionOptions) => {
388
- await this.#getPublishedCommentForAction(commentId, transactionOptions, [], {
389
- forUpdate: true,
390
- });
358
+ const comment = await this.#getPublishedCommentForAction(
359
+ commentId,
360
+ transactionOptions,
361
+ VOTE_REQUIRED_COLUMNS,
362
+ {
363
+ forUpdate: true,
364
+ },
365
+ );
366
+
367
+ const postModel = await this.models.Post.findOne(
368
+ {
369
+ id: comment.get('post_id'),
370
+ },
371
+ {
372
+ require: true,
373
+ ...transactionOptions,
374
+ withRelated: ['tiers'],
375
+ },
376
+ );
377
+
378
+ this.checkPostAccess(postModel, memberModel);
391
379
 
392
380
  const votes = await this.#getMemberCommentVotes(
393
381
  {
@@ -551,7 +539,6 @@ class CommentsService {
551
539
  */
552
540
  async getComments(options) {
553
541
  this.checkEnabled();
554
- await this.#checkPostAccessForRead(options.post_id, options);
555
542
  const page = await this.models.Comment.findPage(
556
543
  withPinnedSelect({ ...options, parentId: null, pinnedFirst: true }),
557
544
  );
@@ -691,17 +678,6 @@ class CommentsService {
691
678
  */
692
679
  async getReplies(id, options, { includeHidden = false } = {}) {
693
680
  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
-
705
681
  const page = await this.models.Comment.findPage(
706
682
  withPinnedSelect({ ...options, parentId: id }, { includeHidden }),
707
683
  );
@@ -783,9 +759,7 @@ class CommentsService {
783
759
  async getCommentByID(id, options = {}) {
784
760
  this.checkEnabled();
785
761
 
786
- const model = await this.#getReadableCommentByID(id, options, ['post_id']);
787
- await this.#checkPostAccessForRead(model.get('post_id'), options);
788
- return model;
762
+ return await this.#getReadableCommentByID(id, options);
789
763
  }
790
764
 
791
765
  /**
@@ -953,9 +927,6 @@ class CommentsService {
953
927
  });
954
928
  }
955
929
 
956
- // Mutation responses include replies, so they require the same post access as reads.
957
- await this.#checkPostAccessForRead(existingComment.get('post_id'), options);
958
-
959
930
  const model = await this.models.Comment.edit(
960
931
  {
961
932
  status: COMMENT_STATUS_DELETED,
@@ -991,8 +962,6 @@ class CommentsService {
991
962
  });
992
963
  }
993
964
 
994
- await this.#checkPostAccessForRead(existingComment.get('post_id'), options);
995
-
996
965
  if (!comment) {
997
966
  return existingComment;
998
967
  }
@@ -37,7 +37,7 @@ module.exports = class CommentsStatsService {
37
37
  .groupBy('post_id');
38
38
 
39
39
  /** @type Object<string, number> */
40
- let counts = {};
40
+ const counts = {};
41
41
 
42
42
  for (const row of results) {
43
43
  counts[row.post_id] = row.count;
@@ -5,25 +5,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createImportFileStager = createImportFileStager;
7
7
  const node_crypto_1 = __importDefault(require("node:crypto"));
8
- const node_os_1 = __importDefault(require("node:os"));
9
8
  const node_path_1 = __importDefault(require("node:path"));
10
- const fs_extra_1 = __importDefault(require("fs-extra"));
11
- function createImportFileStager() {
9
+ // Stages uploads at the root of the imports storage adapter. The job reads the staged
10
+ // file from its path, so the adapter is the local store storage:imports defaults to.
11
+ function createImportFileStager(getStorage) {
12
12
  return {
13
13
  async stage({ filePath, fileName }) {
14
- const stagedPath = node_path_1.default.join(node_os_1.default.tmpdir(), `content-csv-import-${node_crypto_1.default.randomUUID()}`);
14
+ const storage = getStorage();
15
+ const name = `content-csv-import-${node_crypto_1.default.randomUUID()}`;
15
16
  try {
16
- await fs_extra_1.default.copyFile(filePath, stagedPath, fs_extra_1.default.constants.COPYFILE_EXCL);
17
- await fs_extra_1.default.chmod(stagedPath, 0o600);
17
+ const url = await storage.save({ name, path: filePath }, storage.storagePath);
18
+ return { path: node_path_1.default.join(storage.storagePath, storage.urlToPath(url)), name: fileName };
18
19
  }
19
20
  catch (error) {
20
- await fs_extra_1.default.remove(stagedPath).catch(() => { });
21
+ await storage.delete(name).catch(() => { });
21
22
  throw error;
22
23
  }
23
- return { path: stagedPath, name: fileName };
24
24
  },
25
25
  async remove(file) {
26
- await fs_extra_1.default.remove(file.path);
26
+ await getStorage().delete(node_path_1.default.basename(file.path));
27
27
  },
28
28
  };
29
29
  }
@@ -78,7 +78,7 @@ function makeImporter() {
78
78
  }),
79
79
  email,
80
80
  dispatchJob: (job) => (0, jobs_service_1.getInstance)().dispatch(job),
81
- fileStager: (0, staged_file_1.createImportFileStager)(),
81
+ fileStager: (0, staged_file_1.createImportFileStager)(() => require('../adapter-manager').default.getAdapter('storage:imports')),
82
82
  report,
83
83
  store: new store_1.ImportRunStore(),
84
84
  urlForPost: (post) => (0, post_link_1.urlForImportedPost)(post, {
@@ -16,7 +16,7 @@ const messages = {
16
16
  * @param {import('@tryghost/adapter-base-redirects').RedirectConfig[]} redirects
17
17
  */
18
18
  const validate = (redirects) => {
19
- if (!_.isArray(redirects)) {
19
+ if (!Array.isArray(redirects)) {
20
20
  throw new errors.ValidationError({
21
21
  message: tpl(messages.redirectsWrongFormat),
22
22
  help: tpl(messages.redirectsHelp),
@@ -4,12 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.EmailAnalyticsServiceWrapper = void 0;
7
- const errors_1 = __importDefault(require("@tryghost/errors"));
8
7
  const logging_1 = __importDefault(require("@tryghost/logging"));
9
8
  const email_analytics_service_1 = require("./email-analytics-service");
10
9
  const fetch_mailgun_events_1 = require("./fetch-mailgun-events");
11
10
  class EmailAnalyticsServiceWrapper {
12
11
  #logName;
12
+ #jobType;
13
+ #completionEvent;
13
14
  #config;
14
15
  #metrics;
15
16
  #service;
@@ -19,25 +20,10 @@ class EmailAnalyticsServiceWrapper {
19
20
  get #logPrefix() {
20
21
  return `[EmailAnalytics:${this.#logName}]`;
21
22
  }
22
- get #backgroundJobName() {
23
- switch (this.#logName) {
24
- case 'newsletters':
25
- return 'email-analytics-fetch-latest';
26
- case 'automations':
27
- return 'email-analytics-automation-fetch-latest';
28
- case 'gifts':
29
- return 'email-analytics-gift-fetch-latest';
30
- default:
31
- return `email-analytics-${this.#logName}-fetch-latest`;
32
- }
33
- }
34
- constructor({ logName }) {
23
+ constructor({ logName, jobType, config, queries, mailgunTags, jobNames, cursorSeed, createEventProcessor, metrics, settingsCache, }) {
35
24
  this.#logName = logName;
36
- }
37
- init({ config, domainEvents, event, queries, mailgunTags, jobNames, cursorSeed, createEventProcessor, metrics, settingsCache, }) {
38
- if (this.#service) {
39
- return;
40
- }
25
+ this.#jobType = jobType;
26
+ this.#completionEvent = `${jobType.replaceAll('-', '_')}.completed`;
41
27
  this.#config = config;
42
28
  this.#metrics = metrics;
43
29
  this.#fetchOpenedEvents = Boolean(cursorSeed.eventColumns.opened);
@@ -51,32 +37,12 @@ class EmailAnalyticsServiceWrapper {
51
37
  // Log the processing mode on initialization
52
38
  const batchProcessingEnabled = this.#config.get('emailAnalytics:batchProcessing');
53
39
  logging_1.default.info(`${this.#logPrefix} Initialized with ${batchProcessingEnabled ? 'BATCHED' : 'SEQUENTIAL'} processing mode`);
54
- // We currently cannot trigger a non-offloaded job from the job manager
55
- // So the email analytics jobs simply emits an event.
56
- domainEvents.subscribe(event, async () => {
57
- await this.startFetch();
58
- });
59
40
  }
60
41
  get service() {
61
- const result = this.#service;
62
- if (!result) {
63
- throw new errors_1.default.InternalServerError({
64
- message: 'EmailAnalyticsServiceWrapper is not initialized with service',
65
- });
66
- }
67
- return result;
68
- }
69
- #getConfig() {
70
- const result = this.#config;
71
- if (!result) {
72
- throw new errors_1.default.InternalServerError({
73
- message: 'EmailAnalyticsServiceWrapper is not initialized with config',
74
- });
75
- }
76
- return result;
42
+ return this.#service;
77
43
  }
78
44
  _logJobCompletion(jobType, fetchResult, totalDurationMs, lagSeconds = null) {
79
- const config = this.#getConfig();
45
+ const config = this.#config;
80
46
  const { eventCount, apiPollingTimeMs, processingTimeMs, aggregationTimeMs, emailAggregationTimeMs, memberAggregationTimeMs, result, } = fetchResult;
81
47
  if (eventCount === 0) {
82
48
  return;
@@ -87,7 +53,7 @@ class EmailAnalyticsServiceWrapper {
87
53
  const aggregationPercent = totalDurationMs > 0 ? Math.round((aggregationTimeMs / totalDurationMs) * 100) : 0;
88
54
  const batchMode = config.get('emailAnalytics:batchProcessing') ? 'BATCHED' : 'SEQUENTIAL';
89
55
  const logMessage = [
90
- `[Background Job] ${this.#backgroundJobName} processed ${jobType} | ${this.#logPrefix}`,
56
+ `[Background Job] ${this.#jobType} processed ${jobType} | ${this.#logPrefix}`,
91
57
  `${eventCount} events in ${(totalDurationMs / 1000).toFixed(1)}s (${throughput.toFixed(2)} events/s)`,
92
58
  ...(lagSeconds === null ? [] : [`Lag: ${(lagSeconds / 60).toFixed(1)}m`]),
93
59
  `Mode: ${batchMode}`,
@@ -97,7 +63,7 @@ class EmailAnalyticsServiceWrapper {
97
63
  logging_1.default.info({
98
64
  system: {
99
65
  event: 'job.completed',
100
- job_type: this.#backgroundJobName,
66
+ job_type: this.#jobType,
101
67
  task: jobType,
102
68
  event_count: eventCount,
103
69
  duration_ms: totalDurationMs,
@@ -112,13 +78,7 @@ class EmailAnalyticsServiceWrapper {
112
78
  const metricName = this.#logName === 'newsletters'
113
79
  ? 'email-analytics-open-throughput'
114
80
  : `email-${this.#logName}-analytics-open-throughput`;
115
- const metrics = this.#metrics;
116
- if (!metrics) {
117
- throw new errors_1.default.InternalServerError({
118
- message: 'EmailAnalyticsServiceWrapper is not initialized with metrics',
119
- });
120
- }
121
- metrics.metric(metricName, {
81
+ this.#metrics.metric(metricName, {
122
82
  value: throughput,
123
83
  events: eventCount,
124
84
  duration: totalDurationMs,
@@ -159,12 +119,12 @@ class EmailAnalyticsServiceWrapper {
159
119
  await this.service.restoreScheduled();
160
120
  }
161
121
  catch (e) {
162
- logging_1.default.error(e, `[Background Job] ${this.#backgroundJobName} failed while restoring scheduled events after ${Date.now() - startedAt}ms`);
122
+ logging_1.default.error(e, `[Background Job] ${this.#jobType} failed while restoring scheduled events after ${Date.now() - startedAt}ms`);
163
123
  throw e;
164
124
  }
165
125
  }
166
126
  if (this.#fetching) {
167
- logging_1.default.info(`[Background Job] ${this.#backgroundJobName} skipped because a fetch is already running`);
127
+ logging_1.default.info(`[Background Job] ${this.#jobType} skipped because a fetch is already running`);
168
128
  return;
169
129
  }
170
130
  this.#fetching = true;
@@ -194,11 +154,19 @@ class EmailAnalyticsServiceWrapper {
194
154
  this._restartFetch('scheduled backfill');
195
155
  return;
196
156
  }
197
- logging_1.default.info(`[Background Job] ${this.#backgroundJobName} completed in ${Date.now() - startedAt}ms with ${c1 + c2 + c3 + c4} events | ${this.#logPrefix}`);
157
+ // The message is unchanged so existing log queries keep matching; the
158
+ // structured fields are additive.
159
+ logging_1.default.info({
160
+ system: {
161
+ event: this.#completionEvent,
162
+ event_count: c1 + c2 + c3 + c4,
163
+ duration_ms: Date.now() - startedAt,
164
+ },
165
+ }, `[Background Job] ${this.#jobType} completed in ${Date.now() - startedAt}ms with ${c1 + c2 + c3 + c4} events | ${this.#logPrefix}`);
198
166
  this.#fetching = false;
199
167
  }
200
168
  catch (e) {
201
- logging_1.default.error(e, `[Background Job] ${this.#backgroundJobName} failed after ${Date.now() - startedAt}ms`);
169
+ logging_1.default.error(e, `[Background Job] ${this.#jobType} failed after ${Date.now() - startedAt}ms`);
202
170
  // Log again only the error, otherwise we lose the stack trace
203
171
  logging_1.default.error(e);
204
172
  }
@@ -206,7 +174,7 @@ class EmailAnalyticsServiceWrapper {
206
174
  }
207
175
  _restartFetch(reason) {
208
176
  this.#fetching = false;
209
- logging_1.default.info(`[Background Job] ${this.#backgroundJobName} continuing due to ${reason}`);
177
+ logging_1.default.info(`[Background Job] ${this.#jobType} continuing due to ${reason}`);
210
178
  this.startFetch();
211
179
  }
212
180
  }
@@ -3,7 +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.init = exports.gifts = exports.automations = exports.newsletters = void 0;
6
+ exports.init = void 0;
7
+ exports.getNewsletters = getNewsletters;
8
+ exports.getAutomations = getAutomations;
9
+ exports.getGifts = getGifts;
10
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
11
  const email_analytics_service_wrapper_1 = require("./email-analytics-service-wrapper");
8
12
  // @ts-expect-error This module lacks type definitions.
9
13
  const newsletter_email_analytics_batch_processor_1 = require("./newsletter-email-analytics-batch-processor");
@@ -21,16 +25,25 @@ const automation_email_analytics_batch_processor_1 = require("./automation-email
21
25
  const gift_email_analytics_batch_processor_1 = require("./gift-email-analytics-batch-processor");
22
26
  const start_gift_email_analytics_job_event_1 = require("./events/start-gift-email-analytics-job-event");
23
27
  const constants_2 = require("../gifts/constants");
24
- exports.newsletters = new email_analytics_service_wrapper_1.EmailAnalyticsServiceWrapper({
25
- logName: 'newsletters',
26
- });
27
- exports.automations = new email_analytics_service_wrapper_1.EmailAnalyticsServiceWrapper({
28
- logName: 'automations',
29
- });
30
- exports.gifts = new email_analytics_service_wrapper_1.EmailAnalyticsServiceWrapper({
31
- logName: 'gifts',
32
- });
28
+ let newsletters;
29
+ let automations;
30
+ let gifts;
31
+ function getNewsletters() {
32
+ (0, strict_1.default)(newsletters, 'Newsletter email analytics should be initialized');
33
+ return newsletters;
34
+ }
35
+ function getAutomations() {
36
+ (0, strict_1.default)(automations, 'Automation email analytics should be initialized');
37
+ return automations;
38
+ }
39
+ function getGifts() {
40
+ (0, strict_1.default)(gifts, 'Gift email analytics should be initialized');
41
+ return gifts;
42
+ }
33
43
  const init = ({ automationsApi, config, db, domainEvents, emailSuppressionList, giftDeliveryService, membersRepository, models: { Email, EmailRecipientFailure, EmailSpamComplaintEvent }, metrics, prometheusClient, settingsCache, }) => {
44
+ if (newsletters) {
45
+ return;
46
+ }
34
47
  const queries = new queries_1.Queries(db.knex);
35
48
  const newsletterEmailEventProcessor = new email_event_processor_1.default({
36
49
  domainEvents,
@@ -62,10 +75,10 @@ const init = ({ automationsApi, config, db, domainEvents, emailSuppressionList,
62
75
  name: newsletter_email_analytics_batch_processor_1.AGGREGATE_MEMBER_STATS_METRIC_NAME,
63
76
  help: 'Count of member stats aggregations',
64
77
  });
65
- exports.newsletters.init({
78
+ newsletters = new email_analytics_service_wrapper_1.EmailAnalyticsServiceWrapper({
79
+ logName: 'newsletters',
80
+ jobType: 'email-analytics-fetch-latest',
66
81
  config,
67
- domainEvents,
68
- event: start_email_analytics_job_event_1.StartEmailAnalyticsJobEvent,
69
82
  queries,
70
83
  mailgunTags: newsletterMailgunTags,
71
84
  jobNames: {
@@ -91,10 +104,10 @@ const init = ({ automationsApi, config, db, domainEvents, emailSuppressionList,
91
104
  queries,
92
105
  }),
93
106
  });
94
- exports.automations.init({
107
+ automations = new email_analytics_service_wrapper_1.EmailAnalyticsServiceWrapper({
108
+ logName: 'automations',
109
+ jobType: 'email-analytics-automation-fetch-latest',
95
110
  config,
96
- domainEvents,
97
- event: start_automation_email_analytics_job_event_1.StartAutomationEmailAnalyticsJobEvent,
98
111
  queries,
99
112
  mailgunTags: automationMailgunTags,
100
113
  jobNames: {
@@ -116,10 +129,10 @@ const init = ({ automationsApi, config, db, domainEvents, emailSuppressionList,
116
129
  automationsApi,
117
130
  }),
118
131
  });
119
- exports.gifts.init({
132
+ gifts = new email_analytics_service_wrapper_1.EmailAnalyticsServiceWrapper({
133
+ logName: 'gifts',
134
+ jobType: 'email-analytics-gift-fetch-latest',
120
135
  config,
121
- domainEvents,
122
- event: start_gift_email_analytics_job_event_1.StartGiftEmailAnalyticsJobEvent,
123
136
  queries,
124
137
  mailgunTags: giftMailgunTags,
125
138
  jobNames: {
@@ -139,5 +152,8 @@ const init = ({ automationsApi, config, db, domainEvents, emailSuppressionList,
139
152
  settingsCache,
140
153
  createEventProcessor: () => new gift_email_analytics_batch_processor_1.GiftEmailAnalyticsBatchProcessor({ giftDeliveryService }),
141
154
  });
155
+ domainEvents.subscribe(start_email_analytics_job_event_1.StartEmailAnalyticsJobEvent, () => newsletters.startFetch());
156
+ domainEvents.subscribe(start_automation_email_analytics_job_event_1.StartAutomationEmailAnalyticsJobEvent, () => automations.startFetch());
157
+ domainEvents.subscribe(start_gift_email_analytics_job_event_1.StartGiftEmailAnalyticsJobEvent, () => gifts.startFetch());
142
158
  };
143
159
  exports.init = init;
@@ -47,10 +47,11 @@ function randomFiveMinuteCron() {
47
47
  const minutes = Math.floor(Math.random() * 5); // 0-4
48
48
  return `${seconds} ${minutes}/5 * * * *`;
49
49
  }
50
+ function thirtyDaysAgo() {
51
+ return moment_1.default.utc().subtract(30, 'days').toDate();
52
+ }
50
53
  class EmailAnalyticsJobScheduler {
51
- #hasScheduledNewslettersJob = false;
52
- #hasScheduledAutomationsJob = false;
53
- #hasScheduledGiftDeliveriesJob = false;
54
+ #scheduledJobNames = new Set();
54
55
  #models;
55
56
  #config;
56
57
  #jobManager;
@@ -64,76 +65,46 @@ class EmailAnalyticsJobScheduler {
64
65
  this.#config.get('backgroundJobs:emailAnalytics'));
65
66
  }
66
67
  async scheduleRecurringNewslettersJob(skipNewsletterEmailCheck = false) {
67
- if (this.#hasScheduledNewslettersJob) {
68
- return;
69
- }
70
- if (!this.#isConfigured()) {
71
- return;
72
- }
73
68
  // Don't register email analytics job if we have no emails,
74
69
  // processor usage from many sites spinning up threads can be high.
75
70
  // Mega service will re-run this scheduling task when an email is sent
76
- const emailCount = skipNewsletterEmailCheck
77
- ? 1
78
- : Number(await this.#models.Email.where('created_at', '>', moment_1.default.utc().subtract(30, 'days').toDate())
79
- .where('status', '<>', 'failed')
80
- .count());
81
- if (emailCount > 0 && !this.#hasScheduledNewslettersJob) {
82
- const at = randomFiveMinuteCron();
83
- logging.info(`[Background Job] email-analytics-fetch-latest scheduled at ${at}`);
84
- this.#jobManager.addJob({
85
- at,
86
- job: path.resolve(__dirname, 'fetch-latest/index.js'),
87
- name: 'email-analytics-fetch-latest',
88
- });
89
- this.#hasScheduledNewslettersJob = true;
90
- }
71
+ await this.#scheduleOnce({
72
+ name: 'email-analytics-fetch-latest',
73
+ workerPath: path.resolve(__dirname, 'fetch-latest/index.js'),
74
+ }, skipNewsletterEmailCheck, async () => Number(await this.#models.Email.where('created_at', '>', thirtyDaysAgo())
75
+ .where('status', '<>', 'failed')
76
+ .count()) > 0);
91
77
  }
92
78
  async scheduleRecurringAutomationsJob(skipAutomationEmailCheck = false) {
93
- if (this.#hasScheduledAutomationsJob) {
94
- return;
95
- }
96
- if (!this.#isConfigured()) {
97
- return;
98
- }
99
- const hasAutomatedEmailRecipient = skipAutomationEmailCheck ||
100
- Boolean(await this.#models.AutomatedEmailRecipient.query()
101
- .where('created_at', '>', moment_1.default.utc().subtract(30, 'days').toDate())
102
- .whereNotNull('mailgun_message_id')
103
- .first('id'));
104
- if (!hasAutomatedEmailRecipient || this.#hasScheduledAutomationsJob) {
105
- return;
106
- }
107
- const at = randomFiveMinuteCron();
108
- logging.info(`[Background Job] email-analytics-automation-fetch-latest scheduled at ${at}`);
109
- this.#jobManager.addJob({
110
- at,
111
- job: path.resolve(__dirname, 'automation-fetch-latest/index.js'),
79
+ await this.#scheduleOnce({
112
80
  name: 'email-analytics-automation-fetch-latest',
113
- });
114
- this.#hasScheduledAutomationsJob = true;
81
+ workerPath: path.resolve(__dirname, 'automation-fetch-latest/index.js'),
82
+ }, skipAutomationEmailCheck, async () => Boolean(await this.#models.AutomatedEmailRecipient.query()
83
+ .where('created_at', '>', thirtyDaysAgo())
84
+ .whereNotNull('mailgun_message_id')
85
+ .first('id')));
115
86
  }
116
87
  async scheduleRecurringGiftDeliveriesJob(skipGiftDeliveryCheck = false) {
117
- if (this.#hasScheduledGiftDeliveriesJob || !this.#isConfigured()) {
88
+ await this.#scheduleOnce({
89
+ name: 'email-analytics-gift-fetch-latest',
90
+ workerPath: path.resolve(__dirname, 'gift-fetch-latest/index.js'),
91
+ }, skipGiftDeliveryCheck, async () => Boolean(await this.#models.GiftDelivery.query()
92
+ .where('email_sent_at', '>', thirtyDaysAgo())
93
+ .whereNotNull('email_provider_message_id')
94
+ .first('id')));
95
+ }
96
+ async #scheduleOnce(job, skipRecentSendsCheck, hasRecentSends) {
97
+ if (this.#scheduledJobNames.has(job.name) || !this.#isConfigured()) {
118
98
  return;
119
99
  }
120
- const hasGiftDelivery = skipGiftDeliveryCheck ||
121
- Boolean(this.#models.GiftDelivery &&
122
- (await this.#models.GiftDelivery.query()
123
- .where('email_sent_at', '>', moment_1.default.utc().subtract(30, 'days').toDate())
124
- .whereNotNull('email_provider_message_id')
125
- .first('id')));
126
- if (!hasGiftDelivery || this.#hasScheduledGiftDeliveriesJob) {
100
+ const shouldSchedule = skipRecentSendsCheck || (await hasRecentSends());
101
+ if (!shouldSchedule || this.#scheduledJobNames.has(job.name)) {
127
102
  return;
128
103
  }
129
104
  const at = randomFiveMinuteCron();
130
- logging.info(`[Background Job] email-analytics-gift-fetch-latest scheduled at ${at}`);
131
- this.#jobManager.addJob({
132
- at,
133
- job: path.resolve(__dirname, 'gift-fetch-latest/index.js'),
134
- name: 'email-analytics-gift-fetch-latest',
135
- });
136
- this.#hasScheduledGiftDeliveriesJob = true;
105
+ logging.info(`[Background Job] ${job.name} scheduled at ${at}`);
106
+ this.#jobManager.addJob({ at, job: job.workerPath, name: job.name });
107
+ this.#scheduledJobNames.add(job.name);
137
108
  }
138
109
  }
139
110
  exports.EmailAnalyticsJobScheduler = EmailAnalyticsJobScheduler;
@@ -4,6 +4,41 @@ Renders newsletter emails, splits them into recipient batches, and submits the
4
4
  batches to the configured email provider. Domain terms live in
5
5
  [CONTEXT.md](CONTEXT.md).
6
6
 
7
+ ## Job lifecycle
8
+
9
+ New sends, retries, and boot recovery dispatch a data-only `SendEmailJob`
10
+ containing the email ID through the class-based jobs service. Boot injects
11
+ that service and registers `EmailService.handleSendEmailJob`, which delegates
12
+ to `BatchSendingService.emailJob`. The batch sender refetches the email and
13
+ acquires its status lock before preparing or submitting batches. See the
14
+ [jobs guide](../../../../../../docs/codebase/jobs.md#queues) for queue isolation
15
+ and concurrency limits.
16
+
17
+ `scheduleEmail()` waits for dispatch to complete, not for submission. The
18
+ current in-memory backend provides no durable acceptance guarantee and drops
19
+ dispatches after shutdown starts without rejecting them. Email status records
20
+ the sending outcome; a job handler returning does not imply submission, since
21
+ it may have skipped the send, recorded a failure, or stopped for shutdown.
22
+
23
+ Shutdown first stops workers from claiming new batches. The batch sender's
24
+ separate cleanup task waits for active batch preparation and submission even
25
+ if the jobs backend's shutdown wait times out. This tracking currently ends
26
+ before the final email status write. On boot, recovery reschedules eligible
27
+ interrupted sends within `bulkEmail:resumeMaxAgeMs` and skips batches already
28
+ submitted.
29
+
30
+ ## Testing
31
+
32
+ Tests that publish or retry a newsletter should mock the email provider and
33
+ await `waitForEmailStatus(emailId)` from
34
+ [`test/utils/batch-email-utils.js`](../../../../test/utils/batch-email-utils.js)
35
+ before restoring mocks or deleting fixtures. The helper returns on either
36
+ `submitted` or `failed`, so assert the expected status explicitly.
37
+
38
+ A terminal email status describes the send's outcome; it does not prove that
39
+ every competing retry or job attempting the status lock has finished. Tests
40
+ which create competing attempts must also wait for those attempts to settle.
41
+
7
42
  ## Sending status
8
43
 
9
44
  The sending status served by the Admin API's `emails/:id/status` endpoint is