ghost 6.61.0 → 6.63.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 (619) 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-i18n-0.0.0.tgz +0 -0
  11. package/components/tryghost-kg-card-factory-5.2.4.tgz +0 -0
  12. package/components/tryghost-kg-clean-basic-html-4.3.4.tgz +0 -0
  13. package/components/tryghost-kg-converters-1.2.5.tgz +0 -0
  14. package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
  15. package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
  16. package/components/tryghost-kg-default-transforms-1.3.4.tgz +0 -0
  17. package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
  18. package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
  19. package/components/tryghost-kg-markdown-html-renderer-7.2.4.tgz +0 -0
  20. package/components/tryghost-kg-utils-1.1.4.tgz +0 -0
  21. package/components/tryghost-limit-service-0.0.0.tgz +0 -0
  22. package/components/tryghost-metafield-types-0.0.0.tgz +0 -0
  23. package/components/tryghost-nql-string-0.0.0.tgz +0 -0
  24. package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
  25. package/content/settings/README.md +1 -1
  26. package/content/themes/casper/.gitignore +28 -0
  27. package/content/themes/casper/assets/built/casper.js +1 -1
  28. package/content/themes/casper/assets/built/screen.css +1 -1
  29. package/content/themes/casper/assets/css/screen.css +2 -1
  30. package/content/themes/casper/assets/js/lightbox.js +63 -46
  31. package/content/themes/casper/package.json +6 -6
  32. package/content/themes/casper/page.hbs +1 -0
  33. package/content/themes/casper/post.hbs +1 -0
  34. package/content/themes/source/.gitignore +28 -0
  35. package/content/themes/source/assets/built/screen.css +1 -1
  36. package/content/themes/source/assets/built/source.js +1 -1
  37. package/content/themes/source/assets/css/screen.css +2 -1
  38. package/content/themes/source/assets/js/lightbox.js +62 -45
  39. package/content/themes/source/assets/js/main.js +2 -2
  40. package/content/themes/source/package.json +4 -4
  41. package/content/themes/source/partials/feature-image.hbs +1 -0
  42. package/content/themes/source/partials/post-card.hbs +1 -1
  43. package/core/boot.js +61 -27
  44. package/core/built/admin/assets/Combination-B0l4MKVh.js +41 -0
  45. package/core/built/admin/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
  46. package/core/built/admin/assets/InterVariable-Italic-FCBEiFp6.woff2 +0 -0
  47. package/core/built/admin/assets/{about-Bve7IJS2.js → about-C1C3s5-g.js} +1 -1
  48. package/core/built/admin/assets/accordion-CxGsDKwa.js +1 -0
  49. package/core/built/admin/assets/account-migration-CbUhW6gk.js +1 -0
  50. package/core/built/admin/assets/activitypub/{account-migration-C-aej4x_.js → account-migration-KA6Jjf9L.js} +16 -16
  51. package/core/built/admin/assets/activitypub/activitypub.js +9 -9
  52. package/core/built/admin/assets/activitypub/{avatar-DLPL3Abs.js → avatar-DVJF5bxP.js} +2 -2
  53. package/core/built/admin/assets/activitypub/{avatar-flipboard-C9iDY-QV.js → avatar-flipboard-csQaNeYK.js} +2 -2
  54. package/core/built/admin/assets/activitypub/{bluesky-sharing-BXkA5mqV.js → bluesky-sharing-C7nTDMvw.js} +37 -37
  55. package/core/built/admin/assets/activitypub/{content-formatters-CHcyMFk4.js → content-formatters-CLcjaBwV.js} +4 -4
  56. package/core/built/admin/assets/activitypub/{copy-DIAOQoCZ.js → copy-DcOh8kXw.js} +2 -2
  57. package/core/built/admin/assets/activitypub/{domain-B3ihkPde.js → domain-fZ-X8i4-.js} +121 -121
  58. package/core/built/admin/assets/activitypub/{edit-profile-DsZM3rTX.js → edit-profile-BqMLQV88.js} +40 -40
  59. package/core/built/admin/assets/activitypub/{explore-BodNrZgR.js → explore-B4yPoP8E.js} +27 -27
  60. package/core/built/admin/assets/activitypub/{feed-PwH1iJ84.js → feed-BRC_mvAe.js} +51 -51
  61. package/core/built/admin/assets/activitypub/{field-D06-kmOJ.js → field-COacNgOt.js} +3 -3
  62. package/core/built/admin/assets/activitypub/{hash-Bm3WxYN4.js → hash-C7u-irQQ.js} +2 -2
  63. package/core/built/admin/assets/activitypub/inbox-BW-yvUoN.js +1284 -0
  64. package/core/built/admin/assets/activitypub/{inbox-d8oJRTf4.js → inbox-CbTTdDQ3.js} +2 -2
  65. package/core/built/admin/assets/activitypub/label-kPMmYI7l.js +16 -0
  66. package/core/built/admin/assets/activitypub/layout-BL4_jtuV.js +1 -0
  67. package/core/built/admin/assets/activitypub/{moderation-D1Yapsod.js → moderation-CuidJzc0.js} +91 -91
  68. package/core/built/admin/assets/activitypub/{note-C5zjqq5C.js → note-CAMRRSqD.js} +24 -24
  69. package/core/built/admin/assets/activitypub/{notifications-B9p8eCHD.js → notifications-BmNlXGgp.js} +51 -51
  70. package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-Bqg7fh_L.js} +2 -2
  71. package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-Dmun9jr_.js} +2 -2
  72. package/core/built/admin/assets/activitypub/{preferences-BCqUdC3v.js → preferences--oH19wf9.js} +1519 -1519
  73. package/core/built/admin/assets/activitypub/{profile-BRCWoFem.js → profile-DH_tQx2D.js} +185 -185
  74. package/core/built/admin/assets/activitypub/{reply-DYK5vVqb.js → reply-Cap9PxSH.js} +2 -2
  75. package/core/built/admin/assets/activitypub/{routes-BSXT992i.js → routes-DdyY9uFF.js} +744 -735
  76. package/core/built/admin/assets/activitypub/{separator-BbQqTm-p.js → separator-CAxxu8VV.js} +3 -3
  77. package/core/built/admin/assets/activitypub/settings-B6EEcVkW.js +315 -0
  78. package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-BYps63oh.js} +2 -2
  79. package/core/built/admin/assets/activitypub/{step-1-B-YfsVeO.js → step-1-CKjR2KAm.js} +6 -6
  80. package/core/built/admin/assets/activitypub/{step-2-DtPQzlTH.js → step-2-B6PKfOUQ.js} +6 -6
  81. package/core/built/admin/assets/activitypub/{step-3-D6BFMXL_.js → step-3-C-qBbcUo.js} +11 -11
  82. package/core/built/admin/assets/activitypub/{tabs-GpNecvfB.js → tabs-DLhZtVde.js} +306 -306
  83. package/core/built/admin/assets/activitypub/{topic-filter-BPDeQQys.js → topic-filter-DsUOuu0k.js} +3 -3
  84. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-BoVOxXkV.js → use-activity-pub-queries-CX9snsLs.js} +3 -3
  85. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Bmk5h4lW.js → use-navigate-with-base-path-DsJTGDSS.js} +988 -959
  86. package/core/built/admin/assets/activitypub/{use-reply-chain-data-wVBX7swM.js → use-reply-chain-data-AJi9zkzm.js} +30 -30
  87. package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-inweyKL5.js} +192 -164
  88. package/core/built/admin/assets/activitypub/{x-DbQZOLiI.js → x-DR8AT3-4.js} +2 -2
  89. package/core/built/admin/assets/add-integration-modal-BT_onDJy.js +1 -0
  90. package/core/built/admin/assets/add-newsletter-modal-Cx1kQpiY.js +1 -0
  91. package/core/built/admin/assets/add-recommendation-modal-B5nvAhvr.js +1 -0
  92. package/core/built/admin/assets/analytics-DjoJWPI7.js +1 -0
  93. package/core/built/admin/assets/{announcement-bar-modal-DM3cYOpo.js → announcement-bar-modal-Dwd0EGFP.js} +1 -1
  94. package/core/built/admin/assets/{api-keys-3-0vJC3Y.js → api-keys-BGPzLHzA.js} +1 -1
  95. package/core/built/admin/assets/{api-keys-BLm2NDBh.js → api-keys-BoeacM-s.js} +1 -1
  96. package/core/built/admin/assets/{audience-9mwU5TW6.js → audience-ceV3XVHq.js} +1 -1
  97. package/core/built/admin/assets/automated-emails-BLesE41L.js +1 -0
  98. package/core/built/admin/assets/{automations-sAcJ1334.js → automations-BN4u3GR8.js} +1 -1
  99. package/core/built/admin/assets/automations-C-ZTUwW3.js +1 -0
  100. package/core/built/admin/assets/bluesky-sharing-vzh-oPXL.js +1 -0
  101. package/core/built/admin/assets/{breadcrumb-DLiqCyFc.js → breadcrumb-CaLk2b7D.js} +1 -1
  102. package/core/built/admin/assets/{button-B2jcu6bk.js → button-Dvcv1QSR.js} +1 -1
  103. package/core/built/admin/assets/calendar-Bl9RLcZX.js +1 -0
  104. package/core/built/admin/assets/{chart-helpers-Fo3bUL3K.js → chart-helpers-FHywU0pj.js} +1 -1
  105. package/core/built/admin/assets/{checkbox-BfKktMph.js → checkbox-BtayFtjg.js} +1 -1
  106. package/core/built/admin/assets/chunk.254.035b85ec456ebbd7336b.js +440 -0
  107. package/core/built/admin/assets/{chunk.524.60ca4692d91c6022042f.js → chunk.524.e6975095fccdf22d90f8.js} +5 -5
  108. package/core/built/admin/assets/{chunk.582.525c7617c2d9e94c940a.js → chunk.582.98b485f9b2802f540897.js} +6 -6
  109. package/core/built/admin/assets/{chunk.492.f24d855d7e3f3aad261c.js → chunk.901.4ccc639821020230bcca.js} +9949 -7921
  110. package/core/built/admin/assets/{code-editor-view-DCQJxsfU.js → code-editor-view-C3ZfoF1X.js} +1 -1
  111. package/core/built/admin/assets/{code-editor-view-CYVu4EW6.js → code-editor-view-CAyRWy1s.js} +1 -1
  112. package/core/built/admin/assets/color-picker-G4kGR7rp.js +3 -0
  113. package/core/built/admin/assets/color-picker-field-DQFVTNnT.js +1 -0
  114. package/core/built/admin/assets/combobox-BnYzgEB4.js +1 -0
  115. package/core/built/admin/assets/command-C_vyTikI.js +1 -0
  116. package/core/built/admin/assets/comments-aBrxfnZf.js +1 -0
  117. package/core/built/admin/assets/{config-DOMQDZGZ.js → config-kSHvwdTG.js} +1 -1
  118. package/core/built/admin/assets/confirmation-context-DwXX_Y5h.js +1 -0
  119. package/core/built/admin/assets/{content-api-modal-CyQEC3fr.js → content-api-modal-D2G0nJP6.js} +1 -1
  120. package/core/built/admin/assets/context-menu-DOVB6yaz.js +1 -0
  121. package/core/built/admin/assets/{copy-field-B3M1s78L.js → copy-field-DCJwh9qf.js} +1 -1
  122. package/core/built/admin/assets/create-ghost-browse-value-source-5C53jJaX.js +1 -0
  123. package/core/built/admin/assets/custom-field-type-option-BAuW0F-E.js +1 -0
  124. package/core/built/admin/assets/custom-integration-modal-AbJGVyKc.js +1 -0
  125. package/core/built/admin/assets/{date-range-select-DD2RKkgB.js → date-range-select-BY3K-ukj.js} +1 -1
  126. package/core/built/admin/assets/design-and-theme-modal-BvEy4_pC.js +2 -0
  127. package/core/built/admin/assets/dirty-confirm-dialog-DVPuGz3U.js +1 -0
  128. package/core/built/admin/assets/{disabled-sources-indicator-Cvy47bE2.js → disabled-sources-indicator-Cy7Zp4c8.js} +1 -1
  129. package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
  130. package/core/built/admin/assets/domain-Dl61QGuk.js +1 -0
  131. package/core/built/admin/assets/dropzone-Dtz5Rmjt.js +5 -0
  132. package/core/built/admin/assets/edit-profile-DNJSMDwm.js +1 -0
  133. package/core/built/admin/assets/editor-DbAen9zf.js +8 -0
  134. package/core/built/admin/assets/editor-screen-BFWThIai.js +26 -0
  135. package/core/built/admin/assets/email-sending-status-context-CWDOD1FN.js +1 -0
  136. package/core/built/admin/assets/email-sending-status-provider-DCPkDICt.js +1 -0
  137. package/core/built/admin/assets/emails-vFMk4yYl.js +1 -0
  138. package/core/built/admin/assets/{embed-signup-form-modal-DeBMLxlL.js → embed-signup-form-modal-DGqsORxS.js} +1 -1
  139. package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
  140. package/core/built/admin/assets/explore-nnRr1Fja.js +1 -0
  141. package/core/built/admin/assets/feature-flag-overrides-context-DQjdJFAk.js +1 -0
  142. package/core/built/admin/assets/feature-image-placeholder-BrIHmPs8.js +1 -0
  143. package/core/built/admin/assets/feed-BNUcNu-W.js +1 -0
  144. package/core/built/admin/assets/feedback-DJ4Zb9rZ.js +1 -0
  145. package/core/built/admin/assets/{field-Cj8lmDOo.js → field-C93_Mg6j.js} +1 -1
  146. package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
  147. package/core/built/admin/assets/filter-sources-CGJb4C5r.js +1 -0
  148. package/core/built/admin/assets/filters--kKP-EC8.js +1 -0
  149. package/core/built/admin/assets/filters-DxA_a4FP.js +1 -0
  150. package/core/built/admin/assets/first-promoter-modal-BYDtrz2S.js +1 -0
  151. package/core/built/admin/assets/focus-koenig-editor-on-bottom-click-BbSnGOtK.js +1 -0
  152. package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8fd5bb799356bbefb254210ba7e1236d.css} +1 -1
  153. package/core/built/admin/assets/{ghost-3894eedcc6968f658578c0abfe942aab.js → ghost-b4e8a403baba61905cd7560e30b9732d.js} +63 -44
  154. package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-cac0cb2d5bb78e9bd14d8d1c2768ed45.css} +1 -1
  155. package/core/built/admin/assets/gift-link-modal-B7u5bD4e.js +1 -0
  156. package/core/built/admin/assets/{gift-links-DLDS7ljO.js → gift-links-CfLSnst2.js} +1 -1
  157. package/core/built/admin/assets/{growth-D6mhcx3q.js → growth-Cd1uO9d2.js} +1 -1
  158. package/core/built/admin/assets/growth-aG32xfdE.js +3 -0
  159. package/core/built/admin/assets/history-modal-Df8lW8h-.js +1 -0
  160. package/core/built/admin/assets/hooks-Cy_-oZ4o.js +2 -0
  161. package/core/built/admin/assets/{html-field-C8qVGGC1.js → html-field-DA4eU7eq.js} +1 -1
  162. package/core/built/admin/assets/{images-h8VZEQ9k.js → images-KXmyO3Ss.js} +1 -1
  163. package/core/built/admin/assets/{inbox-BYd1M06Q.js → inbox-gJHG7_xd.js} +14 -14
  164. package/core/built/admin/assets/index-BHHXtR5C.css +2 -0
  165. package/core/built/admin/assets/index-CgMCwsxN.js +4 -0
  166. package/core/built/admin/assets/index.es-CY6-yuw9.js +1 -0
  167. package/core/built/admin/assets/{input-group-D8sCXRF5.js → input-group-BE8rM2y1.js} +1 -1
  168. package/core/built/admin/assets/{integrations-Bjbu86Z0.js → integrations-B4kuRBFY.js} +1 -1
  169. package/core/built/admin/assets/invite-user-modal-B4CuNcx4.js +1 -0
  170. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
  171. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
  172. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  173. package/core/built/admin/assets/{koenig-lexical-_-IsVI7E.js → koenig-lexical-CGXb0F8o.js} +3 -3
  174. package/core/built/admin/assets/koenig-loader-BeM5rFPX.js +2 -0
  175. package/core/built/admin/assets/{kpi-card-DZQk_0W8.js → kpi-card-B21aToe8.js} +1 -1
  176. package/core/built/admin/assets/{kpi-card-DW_2y3ug.js → kpi-card-pz6Wv4Ae.js} +1 -1
  177. package/core/built/admin/assets/{kpi-helpers-PueTKuA6.js → kpi-helpers-Dq5jelmP.js} +1 -1
  178. package/core/built/admin/assets/{kpi-tabs-CojDs-Qz.js → kpi-tabs-DEZHpKUt.js} +1 -1
  179. package/core/built/admin/assets/{label-DjbT91GM.js → label-OLCzze8N.js} +1 -1
  180. package/core/built/admin/assets/label-picker-BigOvMPV.js +1 -0
  181. package/core/built/admin/assets/{labels-CH3Kn8RV.js → labels-Dr0SgUQD.js} +1 -1
  182. package/core/built/admin/assets/layout-DUTL8SH5.js +1 -0
  183. package/core/built/admin/assets/lib-7QPTI0FS.js +1 -0
  184. package/core/built/admin/assets/link-helpers-BRAg9SCj.js +1 -0
  185. package/core/built/admin/assets/links-BDHPTlyj.js +1 -0
  186. package/core/built/admin/assets/member-custom-fields-TRTHCAz9.js +1 -0
  187. package/core/built/admin/assets/member-detail-b6dRwc3C.js +1 -0
  188. package/core/built/admin/assets/members-Czt5lJSc.js +4 -0
  189. package/core/built/admin/assets/moderation-ZWefD9uH.js +1 -0
  190. package/core/built/admin/assets/{multi-select-combobox-B6LiRzDO.js → multi-select-combobox-CT13MTo-.js} +1 -1
  191. package/core/built/admin/assets/navigation-modal-C8FEhBK5.js +1 -0
  192. package/core/built/admin/assets/newsletter-5VYW4RyJ.js +1 -0
  193. package/core/built/admin/assets/newsletter-detail-modal-ChjC0ZqH.js +1 -0
  194. package/core/built/admin/assets/{newsletter-emails-CFeLlt4z.js → newsletter-emails-DZH6I-PY.js} +1 -1
  195. package/core/built/admin/assets/newsletters-DOC9KBcX.js +1 -0
  196. package/core/built/admin/assets/newsletters-Rq1M3GD-.js +1 -0
  197. package/core/built/admin/assets/note-DIV-Pojr.js +1 -0
  198. package/core/built/admin/assets/notifications-s20-H49V.js +1 -0
  199. package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
  200. package/core/built/admin/assets/{offers-9J1CSiLy.js → offers--e2nGvkW.js} +1 -1
  201. package/core/built/admin/assets/offers-container-modal-BmG5M5Tv.js +1 -0
  202. package/core/built/admin/assets/onboarding-CUuy9unR.js +1 -0
  203. package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-pXyct0Jm.js} +1 -1
  204. package/core/built/admin/assets/{onboarding-route-Dmc4IPm3.js → onboarding-route-CK4pcXoR.js} +1 -1
  205. package/core/built/admin/assets/overview-CaPsciMs.js +1 -0
  206. package/core/built/admin/assets/overview-a8GfcsKX.js +1 -0
  207. package/core/built/admin/assets/{page-header-BR_nbIPp.js → page-header-DM_KyoFI.js} +1 -1
  208. package/core/built/admin/assets/pagemenu-vgZVUVKR.js +1 -0
  209. package/core/built/admin/assets/pages-CjDY2CBI.js +1 -0
  210. package/core/built/admin/assets/pages-route-BzKZYdV5.js +1 -0
  211. package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
  212. package/core/built/admin/assets/{pintura-modal-BR9hEvS8.js → pintura-modal-DExCF1ii.js} +1 -1
  213. package/core/built/admin/assets/portal-frame-Cqanidq4.js +1 -0
  214. package/core/built/admin/assets/portal-modal-oinBgA27.js +1 -0
  215. package/core/built/admin/assets/post-analytics-C5oJ1dWV.js +1 -0
  216. package/core/built/admin/assets/post-analytics-header-OATo3X_r.js +1 -0
  217. package/core/built/admin/assets/post-analytics-provider-tOpIVGT5.js +1 -0
  218. package/core/built/admin/assets/post-helpers-C88JBa4D.js +1 -0
  219. package/core/built/admin/assets/post-share-modal-DvhC1XgV.js +1 -0
  220. package/core/built/admin/assets/post-utils-DKF4mfuo.js +1 -0
  221. package/core/built/admin/assets/posts-list-screen-o4ZjbgS3.js +2 -0
  222. package/core/built/admin/assets/posts-pCPrhQeR.js +1 -0
  223. package/core/built/admin/assets/posts-route-9F--xdIb.js +1 -0
  224. package/core/built/admin/assets/preferences--vNubsqD.js +5 -0
  225. package/core/built/admin/assets/{preview-modal-C-BL-F9k.js → preview-modal-YYbzlYdO.js} +1 -1
  226. package/core/built/admin/assets/profile-BllKV3dR.js +1 -0
  227. package/core/built/admin/assets/{radio-group-Bgz60i81.js → radio-group-DL8GI8rt.js} +1 -1
  228. package/core/built/admin/assets/{referrers-CnhCMWCs.js → referrers-D8oHPmDB.js} +1 -1
  229. package/core/built/admin/assets/router-provider-BSvTXgZY.js +1 -0
  230. package/core/built/admin/assets/schemas-BoYdB6YU.js +64 -0
  231. package/core/built/admin/assets/select-v5YbA3Mw.js +1 -0
  232. package/core/built/admin/assets/settings-PEsZupw1.js +4 -0
  233. package/core/built/admin/assets/{settings-breadcrumbs-CyP_9zTo.js → settings-breadcrumbs-NwPnCTC7.js} +1 -1
  234. package/core/built/admin/assets/settings-u_s1CRkr.js +1 -0
  235. package/core/built/admin/assets/share-modal-SskCmVGL.js +1 -0
  236. package/core/built/admin/assets/slack-modal-XxSJiYgo.js +1 -0
  237. package/core/built/admin/assets/{sort-button-Cc-Z96sA.js → sort-button-Cx1KtINE.js} +1 -1
  238. package/core/built/admin/assets/{source-icon-v6PUnmyM.js → source-icon-Bdp9Im_5.js} +1 -1
  239. package/core/built/admin/assets/stats-D9PDLS3x.js +1 -0
  240. package/core/built/admin/assets/stats-view-W2g6Jsd-.js +1 -0
  241. package/core/built/admin/assets/{step-1-DSRp2vBj.js → step-1-BQYzvBzr.js} +1 -1
  242. package/core/built/admin/assets/{step-2-COqv2g0u.js → step-2-xES32xJV.js} +1 -1
  243. package/core/built/admin/assets/{step-3-6W1NMVQc.js → step-3-DA_XK5kW.js} +2 -2
  244. package/core/built/admin/assets/{stripe-button-D2K42Uty.js → stripe-button-CVsLHelt.js} +1 -1
  245. package/core/built/admin/assets/stripe-connect-modal-ClmLOMGS.js +1 -0
  246. package/core/built/admin/assets/style-Wd9nQubI.css +1 -0
  247. package/core/built/admin/assets/{table-B2pIKjVh.js → table-BenqVupI.js} +1 -1
  248. package/core/built/admin/assets/{tabs-SaW_UT-Q.js → tabs-eBBlxPp8.js} +1 -1
  249. package/core/built/admin/assets/tag-detail-Ce8Se2qd.js +2 -0
  250. package/core/built/admin/assets/tag-picker-C3UR-uJ-.js +1 -0
  251. package/core/built/admin/assets/tags-B-kJxCs7.js +1 -0
  252. package/core/built/admin/assets/{tags-zTFiKRpb.js → tags-ChfdwJyS.js} +1 -1
  253. package/core/built/admin/assets/testimonials-modal-9Q6fT06V.js +1 -0
  254. package/core/built/admin/assets/tier-detail-modal-CDyYdqK7.js +1 -0
  255. package/core/built/admin/assets/tiers-BCpIOGQr.js +1 -0
  256. package/core/built/admin/assets/{toggle-group-EM9WpESu.js → toggle-group-CviIkyok.js} +1 -1
  257. package/core/built/admin/assets/{topic-filter-DY4gNHn2.js → topic-filter-I2jCBGxm.js} +1 -1
  258. package/core/built/admin/assets/{transistor-modal-CpyPG-MH.js → transistor-modal-p53u3W8y.js} +1 -1
  259. package/core/built/admin/assets/{trend-badge-ByMkuAuH.js → trend-badge-CideVzQd.js} +1 -1
  260. package/core/built/admin/assets/{unsplash-modal-Cv2Q6GtY.js → unsplash-modal-DY8UcKcE.js} +1 -1
  261. package/core/built/admin/assets/{use-analytics-data-CHvjMYuT.js → use-analytics-data-DAIGcr2f.js} +1 -1
  262. package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
  263. package/core/built/admin/assets/{use-check-theme-limit-error-Qv4SVXqw.js → use-check-theme-limit-error-DRUjK4YM.js} +1 -1
  264. package/core/built/admin/assets/use-filter-params-JkZhIS8L.js +1 -0
  265. package/core/built/admin/assets/{use-filterable-api-CzXcpUh8.js → use-filterable-api-BVEVMrhZ.js} +1 -1
  266. package/core/built/admin/assets/use-growth-stats-937CUj6j.js +1 -0
  267. package/core/built/admin/assets/use-host-limits-D0Dv3tKA.js +1 -0
  268. package/core/built/admin/assets/{use-limiter-cwJvsNBo.js → use-limiter-CohWfzvK.js} +1 -1
  269. package/core/built/admin/assets/{use-navigate-with-base-path-BHPA228f.js → use-navigate-with-base-path-BkxcPj5l.js} +1 -1
  270. package/core/built/admin/assets/use-pintura-config-xgytjU35.js +1 -0
  271. package/core/built/admin/assets/{use-pintura-editor-BDBXWUYq.js → use-pintura-editor-CaV1mbfO.js} +1 -1
  272. package/core/built/admin/assets/{use-post-referrers-DbY-mzci.js → use-post-referrers-BCQI7fDg.js} +1 -1
  273. package/core/built/admin/assets/use-reply-chain-data-CYRhoaxY.js +1 -0
  274. package/core/built/admin/assets/{use-router-history-entry-Bg6BhBQQ.js → use-router-history-entry-NOKcd--l.js} +1 -1
  275. package/core/built/admin/assets/{use-setting-group-VM7FQwMY.js → use-setting-group-bLKMwoBT.js} +1 -1
  276. package/core/built/admin/assets/use-settings-navigation-B-qrriKD.js +1 -0
  277. package/core/built/admin/assets/{use-simple-pagination-Dum6Irbs.js → use-simple-pagination-CNPd6Rf6.js} +1 -1
  278. package/core/built/admin/assets/use-staff-users-pRIMIyiW.js +1 -0
  279. package/core/built/admin/assets/use-tinybird-query-CmdbCS9X.js +1 -0
  280. package/core/built/admin/assets/use-tinybird-token-KLne235s.js +1 -0
  281. package/core/built/admin/assets/{use-unsaved-changes-guard-BAy0RANR.js → use-unsaved-changes-guard-7-ug0JdH.js} +1 -1
  282. package/core/built/admin/assets/use-upgrade-route-Dm_qqKr0.js +1 -0
  283. package/core/built/admin/assets/{use-url-input-Df5QzNa7.js → use-url-input-fvp-TpPx.js} +1 -1
  284. package/core/built/admin/assets/user-detail-modal-D3KlGYv-.js +1 -0
  285. package/core/built/admin/assets/users-DVNWrqg9.js +1 -0
  286. package/core/built/admin/assets/{vendor-5753232c7d6ffb3c44e1eb0a02133953.js → vendor-2dd263291938d407802568d3357ec69e.js} +19 -17
  287. package/core/built/admin/assets/{virtual-list-DEx8WgiO.js → virtual-list-CZ3RK2Yf.js} +1 -1
  288. package/core/built/admin/assets/web-ClEJsCAj.js +2 -0
  289. package/core/built/admin/assets/web-X9rdnrtq.js +1 -0
  290. package/core/built/admin/assets/{zapier-modal-Cw3BTBUu.js → zapier-modal-DfVhV17j.js} +1 -1
  291. package/core/built/admin/index.html +23 -27
  292. package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
  293. package/core/frontend/helpers/cancel_link.js +2 -2
  294. package/core/frontend/helpers/pagination.js +2 -2
  295. package/core/frontend/helpers/social_accounts.js +2 -2
  296. package/core/frontend/public/ghost.css +1 -1
  297. package/core/frontend/public/ghost.min.css +1 -1
  298. package/core/frontend/services/sitemap/user-map-generator.js +9 -2
  299. package/core/server/adapters/jobs/InMemoryJobsBackend.js +74 -29
  300. package/core/server/api/endpoints/authentication.js +1 -2
  301. package/core/server/api/endpoints/authors-public.js +15 -5
  302. package/core/server/api/endpoints/emails.js +13 -0
  303. package/core/server/api/endpoints/index.js +10 -2
  304. package/core/server/api/endpoints/mail.js +1 -1
  305. package/core/server/api/endpoints/member-metafields-members.js +23 -0
  306. package/core/server/api/endpoints/member-metafields.js +102 -0
  307. package/core/server/api/endpoints/members-account.js +42 -0
  308. package/core/server/api/endpoints/members.js +4 -4
  309. package/core/server/api/endpoints/newsletters-public.js +10 -1
  310. package/core/server/api/endpoints/pages-public.js +15 -5
  311. package/core/server/api/endpoints/posts-public.js +15 -5
  312. package/core/server/api/endpoints/posts.js +3 -3
  313. package/core/server/api/endpoints/tags-public.js +22 -3
  314. package/core/server/api/endpoints/tiers-checkout-config.js +2 -2
  315. package/core/server/api/endpoints/tiers-public.js +38 -1
  316. package/core/server/api/endpoints/users.js +2 -2
  317. package/core/server/api/endpoints/utils/api-filter-utils.js +170 -3
  318. package/core/server/api/endpoints/utils/public-cache-keys.js +3 -0
  319. package/core/server/api/endpoints/utils/serializers/input/authors.js +2 -0
  320. package/core/server/api/endpoints/utils/serializers/input/members.js +20 -9
  321. package/core/server/api/endpoints/utils/serializers/input/pages.js +2 -0
  322. package/core/server/api/endpoints/utils/serializers/input/posts.js +2 -0
  323. package/core/server/api/endpoints/utils/serializers/input/tags.js +2 -0
  324. package/core/server/api/endpoints/utils/serializers/output/emails.js +7 -0
  325. package/core/server/api/endpoints/utils/serializers/output/index.js +6 -2
  326. package/core/server/api/endpoints/utils/serializers/output/member-metafields.js +18 -0
  327. package/core/server/api/endpoints/utils/serializers/output/members-account.js +19 -0
  328. package/core/server/api/endpoints/utils/serializers/output/members-csv-transform.js +1 -1
  329. package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
  330. package/core/server/api/endpoints/utils/serializers/output/tiers.js +10 -2
  331. package/core/server/api/endpoints/utils/serializers/output/users.js +0 -10
  332. package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
  333. package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
  334. package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
  335. package/core/server/data/exporter/table-lists.js +3 -3
  336. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  337. package/core/server/data/migrations/utils/migrations.js +1 -1
  338. package/core/server/data/migrations/versions/6.53/2026-07-15-20-22-53-add-members-custom-field-values.js +1 -1
  339. package/core/server/data/migrations/versions/6.57/2026-08-04-18-00-00-store-custom-field-values-as-leaf-rows.js +10 -1
  340. package/core/server/data/migrations/versions/6.63/2026-09-03-10-07-03-rename-custom-field-tables-to-metafields.js +169 -0
  341. package/core/server/data/migrations/versions/6.63/2026-09-03-11-03-31-remove-member-custom-field-read-permissions.js +30 -0
  342. package/core/server/data/schema/fixtures/fixtures.json +0 -11
  343. package/core/server/data/schema/lib/default-index-name.js +8 -11
  344. package/core/server/data/schema/schema.js +18 -18
  345. package/core/server/data/seeders/README.md +48 -0
  346. package/core/server/data/tinybird/pipes/mv_hits.pipe +86 -50
  347. package/core/server/lib/db-types/count.js +16 -0
  348. package/core/server/lib/image/image-size.js +24 -0
  349. package/core/server/lib/package-json/parse.js +2 -2
  350. package/core/server/lib/validate-password.js +81 -120
  351. package/core/server/models/action.js +4 -4
  352. package/core/server/models/base/plugins/filtered-collection.js +16 -0
  353. package/core/server/models/member.js +10 -21
  354. package/core/server/models/post.js +2 -2
  355. package/core/server/models/relations/authors.js +2 -16
  356. package/core/server/models/user.js +10 -3
  357. package/core/server/services/auth/passwordreset.js +13 -0
  358. package/core/server/services/automations/automations-api.js +1 -1
  359. package/core/server/services/automations/database-automations-repository.js +11 -4
  360. package/core/server/services/comments/comments-controller.js +30 -9
  361. package/core/server/services/comments/comments-service.js +55 -5
  362. package/core/server/services/content-import/csv/formula.js +12 -0
  363. package/core/server/services/content-import/csv/index.js +6 -1
  364. package/core/server/services/content-import/csv/parse.js +27 -6
  365. package/core/server/services/content-import/csv/serialize.js +13 -0
  366. package/core/server/services/content-import/import/completion-email.js +164 -0
  367. package/core/server/services/content-import/import/errors-file.js +36 -0
  368. package/core/server/services/content-import/import/importer.js +160 -53
  369. package/core/server/services/content-import/import/local-media-url.js +63 -0
  370. package/core/server/services/content-import/import/media.js +254 -0
  371. package/core/server/services/content-import/import/post-data.js +0 -1
  372. package/core/server/services/content-import/import/post-link.js +11 -0
  373. package/core/server/services/content-import/import/post-repository.js +25 -3
  374. package/core/server/services/content-import/import/reader.js +9 -2
  375. package/core/server/services/content-import/import/report.js +34 -0
  376. package/core/server/services/content-import/import/row.js +0 -2
  377. package/core/server/services/content-import/import/schema.js +1 -0
  378. package/core/server/services/content-import/import/staged-file.js +29 -0
  379. package/core/server/services/content-import/import/store.js +25 -2
  380. package/core/server/services/content-import/index.js +52 -6
  381. package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
  382. package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
  383. package/core/server/services/custom-redirects/redirects-service.js +1 -1
  384. package/core/server/services/custom-redirects/validation.js +1 -1
  385. package/core/server/services/email-address/email-address-parser.js +30 -38
  386. package/core/server/services/email-address/email-address-service.js +37 -4
  387. package/core/server/services/email-analytics/index.js +2 -7
  388. package/core/server/services/email-service/CONTEXT.md +37 -0
  389. package/core/server/services/email-service/README.md +42 -0
  390. package/core/server/services/email-service/batch-sending-service.js +2 -4
  391. package/core/server/services/email-service/email-controller.js +18 -2
  392. package/core/server/services/email-service/email-renderer.js +14 -4
  393. package/core/server/services/email-service/email-service-wrapper.js +3 -9
  394. package/core/server/services/email-service/mailgun-email-provider.js +20 -9
  395. package/core/server/services/email-service/sending-status-schema.js +21 -0
  396. package/core/server/services/email-service/sending-status-serializers.js +33 -0
  397. package/core/server/services/email-service/sending-status-service.js +47 -0
  398. package/core/server/services/email-service/sending-status.js +111 -0
  399. package/core/server/services/email-suppression-list/email-suppression-list.js +0 -33
  400. package/core/server/services/email-suppression-list/mailgun-email-suppression-list.js +6 -7
  401. package/core/server/services/gifts/README.md +2 -2
  402. package/core/server/services/gifts/constants.js +1 -1
  403. package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
  404. package/core/server/services/gifts/gift-email-service.js +0 -1
  405. package/core/server/services/gifts/gift-service.js +19 -57
  406. package/core/server/services/gifts/index.js +3 -5
  407. package/core/server/services/gifts/jobs/index.js +4 -4
  408. package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
  409. package/core/server/services/invitations/accept.js +4 -2
  410. package/core/server/services/jobs/job-service.js +0 -9
  411. package/core/server/services/jobs-service/index.js +8 -0
  412. package/core/server/services/jobs-service/jobs-service.js +52 -3
  413. package/core/server/services/jobs-service/register-job-handlers.js +32 -11
  414. package/core/server/services/mail/ghost-mailer.js +4 -4
  415. package/core/server/services/member-welcome-emails/service.js +7 -7
  416. package/core/server/services/members/account-service.js +98 -0
  417. package/core/server/services/members/api.js +4 -3
  418. package/core/server/services/members/import-export/csv/parse.js +0 -7
  419. package/core/server/services/members/import-export/export/exporter.js +20 -20
  420. package/core/server/services/members/import-export/import/completion-email.js +8 -11
  421. package/core/server/services/members/import-export/import/importer.js +13 -13
  422. package/core/server/services/members/import-export/import/row.js +0 -3
  423. package/core/server/services/members/import-export/index.js +10 -17
  424. package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
  425. package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
  426. package/core/server/services/members/jobs/index.js +48 -24
  427. package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
  428. package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
  429. package/core/server/services/members/members-api/members-api.js +26 -8
  430. package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
  431. package/core/server/services/members/members-api/repositories/member-repository.js +4 -4
  432. package/core/server/services/members/members-api/services/member-bread-service.js +62 -84
  433. package/core/server/services/members/members-api/services/payments-service.js +1 -1
  434. package/core/server/services/members/members-ssr.js +18 -0
  435. package/core/server/services/members/middleware.js +95 -81
  436. package/core/server/services/members/service.js +71 -47
  437. package/core/server/services/members/utils.js +9 -0
  438. package/core/server/services/members-metafields/access.js +28 -0
  439. package/core/server/services/{members-custom-fields → members-metafields}/actions.js +5 -5
  440. package/core/server/services/members-metafields/bindings-service.js +147 -0
  441. package/core/server/services/members-metafields/codec.js +14 -0
  442. package/core/server/services/{members-custom-fields → members-metafields}/config.js +1 -1
  443. package/core/server/services/{members-custom-fields → members-metafields}/definitions-service.js +68 -22
  444. package/core/server/services/members-metafields/filter.js +181 -0
  445. package/core/server/services/{members-custom-fields → members-metafields}/index.js +16 -7
  446. package/core/server/services/{members-custom-fields → members-metafields}/key.js +2 -1
  447. package/core/server/services/{members-custom-fields → members-metafields}/models.js +5 -5
  448. package/core/server/services/members-metafields/namespaces.js +34 -0
  449. package/core/server/services/{members-custom-fields → members-metafields}/queries.js +1 -1
  450. package/core/server/services/{members-custom-fields → members-metafields}/schema.js +16 -12
  451. package/core/server/services/members-metafields/serializers.js +22 -0
  452. package/core/server/services/{members-custom-fields → members-metafields}/values-service.js +80 -48
  453. package/core/server/services/mentions/mention-controller.js +23 -21
  454. package/core/server/services/mentions/mention-sending-service.js +26 -9
  455. package/core/server/services/mentions/process-webmention-job.js +16 -0
  456. package/core/server/services/mentions/send-webmentions-job.js +18 -0
  457. package/core/server/services/mentions/service.js +7 -33
  458. package/core/server/services/route-settings/validation-errors.js +1 -1
  459. package/core/server/services/route-settings/yaml-parser.js +1 -1
  460. package/core/server/services/settings/settings-service.js +1 -8
  461. package/core/server/services/settings-helpers/settings-helpers.js +4 -6
  462. package/core/server/services/slack-ping/slack-ping-service.js +1 -1
  463. package/core/server/services/staff/staff-service-emails.js +2 -2
  464. package/core/server/services/stripe/config.js +14 -8
  465. package/core/server/services/stripe/service.js +10 -1
  466. package/core/server/services/stripe/services/checkout/completed-session.js +2 -2
  467. package/core/server/services/stripe/services/checkout/session-options.js +18 -15
  468. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +28 -7
  469. package/core/server/services/stripe/stripe-api.js +2 -0
  470. package/core/server/services/stripe/stripe-service.js +24 -14
  471. package/core/server/services/stripe/webhook-controller.js +10 -0
  472. package/core/server/services/tier-checkout-config/codec.js +11 -7
  473. package/core/server/services/tier-checkout-config/index.js +2 -1
  474. package/core/server/services/tier-checkout-config/models.js +11 -5
  475. package/core/server/services/tier-checkout-config/queries.js +12 -12
  476. package/core/server/services/tier-checkout-config/serializers.js +73 -10
  477. package/core/server/services/tier-checkout-config/service.js +14 -13
  478. package/core/server/services/tiers/service.js +3 -3
  479. package/core/server/services/update-check/index.js +13 -13
  480. package/core/server/services/update-check/jobs/update-check-job.js +7 -0
  481. package/core/server/services/update-check/update-check-service.js +2 -2
  482. package/core/server/services/url/router-filter.js +8 -10
  483. package/core/server/services/users.js +1 -19
  484. package/core/server/web/admin/controller.js +1 -1
  485. package/core/server/web/api/endpoints/admin/routes.js +20 -16
  486. package/core/server/web/members/account/index.js +2 -0
  487. package/core/server/web/members/account/routes.js +46 -0
  488. package/core/server/web/members/app.js +4 -18
  489. package/core/shared/config/defaults.json +1 -1
  490. package/core/shared/config/env/config.testing-mysql.json +1 -1
  491. package/core/shared/labs.js +7 -2
  492. package/package.json +42 -41
  493. package/pnpm-lock.yaml +1159 -582
  494. package/pnpm-workspace.yaml +18 -15
  495. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  496. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  497. package/core/built/admin/assets/Combination-5fYEzgbs.js +0 -41
  498. package/core/built/admin/assets/account-migration-DRhAehfw.js +0 -1
  499. package/core/built/admin/assets/activitypub/inbox-BluD2ucT.js +0 -1284
  500. package/core/built/admin/assets/activitypub/label-FHSh6ZAw.js +0 -16
  501. package/core/built/admin/assets/activitypub/layout-Cq4NG0Xr.js +0 -1
  502. package/core/built/admin/assets/activitypub/settings-DQDkr06X.js +0 -315
  503. package/core/built/admin/assets/add-integration-modal-BC0jExDZ.js +0 -1
  504. package/core/built/admin/assets/add-newsletter-modal-DchTkA7l.js +0 -1
  505. package/core/built/admin/assets/add-recommendation-modal-DMvaJZKp.js +0 -1
  506. package/core/built/admin/assets/alert-dialog-QhXzdHfc.js +0 -1
  507. package/core/built/admin/assets/analytics-No1DDY3A.js +0 -1
  508. package/core/built/admin/assets/automated-emails-te1D5kq-.js +0 -1
  509. package/core/built/admin/assets/automations-DpUNUdcZ.js +0 -1
  510. package/core/built/admin/assets/bluesky-sharing-Cjrv_f62.js +0 -1
  511. package/core/built/admin/assets/chunk.896.435fe0637944d4a69810.js +0 -366
  512. package/core/built/admin/assets/color-picker-BTY_NdEm.js +0 -3
  513. package/core/built/admin/assets/color-picker-field-CPlkzOH0.js +0 -1
  514. package/core/built/admin/assets/combobox-DrMtv_4P.js +0 -1
  515. package/core/built/admin/assets/command-ZdgYJpoI.js +0 -1
  516. package/core/built/admin/assets/comments-kidj60-h.js +0 -1
  517. package/core/built/admin/assets/confirmation-context-BhbmQQEl.js +0 -1
  518. package/core/built/admin/assets/custom-field-type-option-CsGIZk1J.js +0 -10
  519. package/core/built/admin/assets/custom-integration-modal-BY37O_9X.js +0 -1
  520. package/core/built/admin/assets/design-and-theme-modal-DUSKM4uC.js +0 -22
  521. package/core/built/admin/assets/dialog-B44iRwlc.js +0 -1
  522. package/core/built/admin/assets/dirty-confirm-dialog-BxgQgQ6H.js +0 -1
  523. package/core/built/admin/assets/dist-Cy8tfrp_.js +0 -1
  524. package/core/built/admin/assets/domain-Ca6KhoQt.js +0 -1
  525. package/core/built/admin/assets/dropzone-Bb-5zQTk.js +0 -5
  526. package/core/built/admin/assets/edit-profile-BdupLlus.js +0 -1
  527. package/core/built/admin/assets/editor-BP883Lpn.js +0 -8
  528. package/core/built/admin/assets/explore-FB-CimXw.js +0 -1
  529. package/core/built/admin/assets/feed-C1GxsmI2.js +0 -1
  530. package/core/built/admin/assets/filter-sources-D5n5bFA2.js +0 -1
  531. package/core/built/admin/assets/filters-DJEzkMUK.js +0 -1
  532. package/core/built/admin/assets/filters-MZXvdH5D.js +0 -1
  533. package/core/built/admin/assets/first-promoter-modal-CGTGLCr5.js +0 -1
  534. package/core/built/admin/assets/gift-link-modal-B6v0tnRN.js +0 -1
  535. package/core/built/admin/assets/growth-BGAJD1rs.js +0 -3
  536. package/core/built/admin/assets/history-modal-iKwUY3XR.js +0 -1
  537. package/core/built/admin/assets/hooks-CuEZV2-q.js +0 -2
  538. package/core/built/admin/assets/index-DjQe-e5s.js +0 -4
  539. package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
  540. package/core/built/admin/assets/index.es-VihPwfeH.js +0 -1
  541. package/core/built/admin/assets/input--W-rCTrX.js +0 -1
  542. package/core/built/admin/assets/invite-user-modal-MdImLCaJ.js +0 -1
  543. package/core/built/admin/assets/koenig-loader-DYZpm6El.js +0 -2
  544. package/core/built/admin/assets/label-picker-cB51xl1r.js +0 -1
  545. package/core/built/admin/assets/layout-c_B_1hax.js +0 -1
  546. package/core/built/admin/assets/link-helpers-MVDdnFCY.js +0 -1
  547. package/core/built/admin/assets/loading-indicator-BpFWTVgh.js +0 -1
  548. package/core/built/admin/assets/member-custom-fields-qs0dIkxM.js +0 -1
  549. package/core/built/admin/assets/member-detail-B6uec2a6.js +0 -1
  550. package/core/built/admin/assets/members-BQF3CqhI.js +0 -2
  551. package/core/built/admin/assets/moderation-DY4wF1Q3.js +0 -1
  552. package/core/built/admin/assets/navigation-modal-DX-gNF3X.js +0 -1
  553. package/core/built/admin/assets/newsletter-CyQA7m3m.js +0 -1
  554. package/core/built/admin/assets/newsletter-detail-modal-BDrptuxn.js +0 -1
  555. package/core/built/admin/assets/newsletters-DXuNmC42.js +0 -1
  556. package/core/built/admin/assets/newsletters-DhNigJUh.js +0 -1
  557. package/core/built/admin/assets/note-Cgo2LCJ6.js +0 -1
  558. package/core/built/admin/assets/notifications-BC50AMku.js +0 -1
  559. package/core/built/admin/assets/offers-container-modal-DWycIMzT.js +0 -1
  560. package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
  561. package/core/built/admin/assets/overview-CVbFtn-k.js +0 -1
  562. package/core/built/admin/assets/overview-YKj7SZaK.js +0 -1
  563. package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
  564. package/core/built/admin/assets/popover-CCy0h5rq.js +0 -1
  565. package/core/built/admin/assets/portal-frame-dc4XKr0e.js +0 -1
  566. package/core/built/admin/assets/portal-modal-BvvdF_B9.js +0 -1
  567. package/core/built/admin/assets/post-analytics-DX470WRG.js +0 -1
  568. package/core/built/admin/assets/post-analytics-header-CXpJmdDv.js +0 -1
  569. package/core/built/admin/assets/post-analytics-provider-CLfKGWZy.js +0 -1
  570. package/core/built/admin/assets/post-helpers-C5OQMBoi.js +0 -1
  571. package/core/built/admin/assets/post-share-modal-Cl0NXRJr.js +0 -1
  572. package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
  573. package/core/built/admin/assets/preferences-DO0UUWFp.js +0 -5
  574. package/core/built/admin/assets/profile-CxT-0l4d.js +0 -1
  575. package/core/built/admin/assets/router-provider-B0gZyiGJ.js +0 -1
  576. package/core/built/admin/assets/schemas-4UPic-oD.js +0 -64
  577. package/core/built/admin/assets/select-DuDUFdPq.js +0 -1
  578. package/core/built/admin/assets/settings-BjCii7BM.js +0 -1
  579. package/core/built/admin/assets/settings-b8kNzZSQ.js +0 -4
  580. package/core/built/admin/assets/share-modal-BV70mr9k.js +0 -1
  581. package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
  582. package/core/built/admin/assets/slack-modal-Be2_KK-z.js +0 -1
  583. package/core/built/admin/assets/stats-C4reGh9O.js +0 -1
  584. package/core/built/admin/assets/stats-view-DP9pQ62k.js +0 -1
  585. package/core/built/admin/assets/stripe-connect-modal-Z-UT_BGc.js +0 -1
  586. package/core/built/admin/assets/tag-detail-Dc0nTOtU.js +0 -2
  587. package/core/built/admin/assets/tags-BLaXBwnb.js +0 -1
  588. package/core/built/admin/assets/testimonials-modal-sFwRnNLh.js +0 -1
  589. package/core/built/admin/assets/tier-detail-modal-BCFpWwUS.js +0 -1
  590. package/core/built/admin/assets/tiers-Nd_z4BZY.js +0 -1
  591. package/core/built/admin/assets/use-filter-params-CAvfDvf1.js +0 -1
  592. package/core/built/admin/assets/use-growth-stats-D6mZXGhK.js +0 -1
  593. package/core/built/admin/assets/use-host-limits-DZtR08oa.js +0 -1
  594. package/core/built/admin/assets/use-pintura-config-CzTfnufz.js +0 -1
  595. package/core/built/admin/assets/use-reply-chain-data-BeQwz8oF.js +0 -1
  596. package/core/built/admin/assets/use-settings-navigation-BbrSUVcf.js +0 -1
  597. package/core/built/admin/assets/use-staff-users-cZg4ugOF.js +0 -1
  598. package/core/built/admin/assets/use-tinybird-query-B1IMyAcv.js +0 -39
  599. package/core/built/admin/assets/use-tinybird-token-Bow0Zwn8.js +0 -1
  600. package/core/built/admin/assets/use-upgrade-route-DhRSo7at.js +0 -1
  601. package/core/built/admin/assets/user-detail-modal-yipSoQfv.js +0 -1
  602. package/core/built/admin/assets/users-5msE1WMs.js +0 -1
  603. package/core/built/admin/assets/web-CKcXAu86.js +0 -1
  604. package/core/built/admin/assets/web-DR4TqM3E.js +0 -2
  605. package/core/server/api/endpoints/member-custom-fields.js +0 -90
  606. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +0 -20
  607. package/core/server/services/email-suppression-list/in-memory-email-suppression-list.js +0 -39
  608. package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
  609. package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
  610. package/core/server/services/members-custom-fields/bindings-service.js +0 -119
  611. package/core/server/services/members-custom-fields/codec.js +0 -15
  612. package/core/server/services/members-custom-fields/filter.js +0 -199
  613. package/core/server/services/members-custom-fields/serializers.js +0 -24
  614. package/core/server/services/stripe/services/checkout/allowed-countries.js +0 -267
  615. package/core/server/services/stripe/services/checkout/field-ports.js +0 -34
  616. package/core/server/services/tier-checkout-config/destinations.js +0 -17
  617. package/core/server/services/update-check/run-update-check.js +0 -63
  618. /package/core/built/admin/assets/{chunk.492.f24d855d7e3f3aad261c.js.LICENSE.txt → chunk.901.4ccc639821020230bcca.js.LICENSE.txt} +0 -0
  619. /package/core/server/services/{members-custom-fields → members-metafields}/storage.js +0 -0
@@ -6,8 +6,8 @@ transactions, or Stripe objects.
6
6
 
7
7
  ## Interface
8
8
 
9
- - `startCheckout(input)` owns the `giftSubCustomization` flag, duration
10
- catalogue, Portal plan gate, tier/cadence validation, authoritative price,
9
+ - `startCheckout(input)` owns the duration catalogue, Portal plan gate,
10
+ tier/cadence validation, authoritative price,
11
11
  token, success parameters, metadata, customer, and one-time payment.
12
12
  - `preparePaidContinuation(input)` validates an active gift and returns the
13
13
  stable tier/cadence/trial decision consumed by the normal subscription
@@ -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.tsx) since Portal ships
6
+ // copy (GIFT_MAX_SCHEDULE_DAYS in 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>
@@ -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,
@@ -95,40 +95,22 @@ class GiftService {
95
95
  this.deps = deps;
96
96
  }
97
97
  async startCheckout(input) {
98
- const customizationEnabled = this.deps.labsService.isSet('giftSubCustomization');
99
- const populatedDeliveryFields = [
100
- input.recipientEmail,
101
- input.recipientName,
102
- input.buyerName,
103
- input.personalMessage,
104
- input.deliveryDate,
105
- ].some((value) => value !== undefined && value !== null && value !== '');
106
- if (!customizationEnabled && (input.deliveryMethod === 'email' || populatedDeliveryFields)) {
107
- throw new errors_1.default.BadRequestError({
108
- message: 'Bad Request.',
109
- context: 'Gift email delivery is not available',
110
- });
111
- }
112
98
  const parsedBuyerEmail = CheckoutBuyerEmailSchema.safeParse(input.buyer.email);
113
- if (customizationEnabled && !parsedBuyerEmail.success) {
99
+ if (!parsedBuyerEmail.success) {
114
100
  throw new errors_1.default.BadRequestError({
115
101
  message: 'Bad Request.',
116
102
  context: `Invalid gift buyer email: ${parsedBuyerEmail.error.issues[0].message}`,
117
103
  });
118
104
  }
119
105
  const buyerEmail = parsedBuyerEmail.success ? parsedBuyerEmail.data : input.buyer.email;
120
- const parsedDelivery = GiftCheckoutDeliverySchema.safeParse(customizationEnabled
121
- ? {
122
- deliveryMethod: input.deliveryMethod ?? 'link',
123
- recipientEmail: input.recipientEmail,
124
- recipientName: input.recipientName,
125
- buyerName: input.buyerName,
126
- personalMessage: input.personalMessage,
127
- deliveryDate: input.deliveryDate,
128
- }
129
- : {
130
- deliveryMethod: 'link',
131
- });
106
+ const parsedDelivery = GiftCheckoutDeliverySchema.safeParse({
107
+ deliveryMethod: input.deliveryMethod ?? 'link',
108
+ recipientEmail: input.recipientEmail,
109
+ recipientName: input.recipientName,
110
+ buyerName: input.buyerName,
111
+ personalMessage: input.personalMessage,
112
+ deliveryDate: input.deliveryDate,
113
+ });
132
114
  if (!parsedDelivery.success) {
133
115
  const issue = parsedDelivery.error.issues[0];
134
116
  throw new errors_1.default.BadRequestError({
@@ -150,22 +132,7 @@ class GiftService {
150
132
  context: 'Expected offerId or tierId, received none',
151
133
  });
152
134
  }
153
- let resolvedDuration = null;
154
- let cadence;
155
- if (customizationEnabled) {
156
- resolvedDuration = (0, gift_checkout_offer_1.resolveGiftDuration)(input);
157
- cadence = resolvedDuration.cadence;
158
- }
159
- else {
160
- if (input.cadence !== 'month' && input.cadence !== 'year') {
161
- const receivedCadence = input.cadence ? `"${input.cadence}"` : input.cadence;
162
- throw new errors_1.default.BadRequestError({
163
- message: 'Bad Request.',
164
- context: `Expected cadence to be "month" or "year", received ${receivedCadence}`,
165
- });
166
- }
167
- cadence = input.cadence;
168
- }
135
+ const resolvedDuration = (0, gift_checkout_offer_1.resolveGiftDuration)(input);
169
136
  let tier;
170
137
  try {
171
138
  tier = await this.deps.tiersService.api.read(input.tierId);
@@ -185,20 +152,15 @@ class GiftService {
185
152
  message: 'This tier is archived.',
186
153
  });
187
154
  }
188
- let duration = 1;
189
- let totalMonths;
190
- let amount = tier.getPrice(cadence);
191
- if (resolvedDuration) {
192
- const plan = (0, gift_checkout_offer_1.validateGiftCheckoutOffer)({
193
- tier,
194
- portalPlans: this.deps.settingsCache.get('portal_plans'),
195
- offer: resolvedDuration,
196
- });
197
- cadence = plan.cadence;
198
- duration = plan.duration;
199
- totalMonths = plan.totalMonths;
200
- amount = plan.amount;
201
- }
155
+ const plan = (0, gift_checkout_offer_1.validateGiftCheckoutOffer)({
156
+ tier,
157
+ portalPlans: this.deps.settingsCache.get('portal_plans'),
158
+ offer: resolvedDuration,
159
+ });
160
+ const cadence = plan.cadence;
161
+ const duration = plan.duration;
162
+ const totalMonths = plan.totalMonths;
163
+ const amount = plan.amount;
202
164
  const tierId = typeof tier.id === 'string' ? tier.id : tier.id.toHexString();
203
165
  const token = this.generateToken();
204
166
  const successUrl = new URL(input.successUrl);
@@ -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
  }
@@ -34,10 +34,9 @@ async function init(options) {
34
34
  const MailgunClient = require('../lib/mailgun-client');
35
35
  const config = require('../../../shared/config');
36
36
  const settingsCache = require('../../../shared/settings-cache');
37
- const labsService = require('../../../shared/labs');
38
37
  const urlUtils = require('../../../shared/url-utils').default;
39
38
  const settingsHelpers = require('../settings-helpers');
40
- const EmailAddressParser = require('../email-address/email-address-parser');
39
+ const emailAddressParser = require('../email-address/email-address-parser');
41
40
  const { blogIcon } = require('../../../server/lib/image');
42
41
  const { t } = require('../i18n');
43
42
  const repository = new gift_bookshelf_repository_1.GiftBookshelfRepository({
@@ -57,7 +56,7 @@ async function init(options) {
57
56
  bulkMailer: new MailgunClient({ config, settings: settingsCache }),
58
57
  settingsCache,
59
58
  urlUtils,
60
- getFromAddress: () => EmailAddressParser.stringify(settingsHelpers.getDefaultEmail()),
59
+ getFromAddress: () => emailAddressParser.stringify(settingsHelpers.getDefaultEmail()),
61
60
  getReplyToAddress: () => settingsHelpers.getMembersSupportAddress(),
62
61
  blogIcon,
63
62
  t,
@@ -110,7 +109,6 @@ async function init(options) {
110
109
  },
111
110
  giftReminderScheduler,
112
111
  checkoutAdapter,
113
- labsService,
114
112
  settingsCache,
115
113
  });
116
114
  exports.service = giftService;
@@ -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
  }
@@ -10,6 +10,14 @@ const errors_1 = __importDefault(require("@tryghost/errors"));
10
10
  const jobs_service_1 = require("./jobs-service");
11
11
  let instance;
12
12
  function init() {
13
+ // The instance lives for the whole process: the didInit-guarded mentions
14
+ // service captures it in MentionController and MentionSendingService, so
15
+ // an in-process restart (test harness) must revive the same object rather
16
+ // than strand those references on a stopped queue.
17
+ if (instance) {
18
+ instance.clearHandlers();
19
+ return instance;
20
+ }
13
21
  const adapterManager = require('../adapter-manager').default;
14
22
  const logging = require('@tryghost/logging');
15
23
  const sentry = require('../../../shared/sentry');
@@ -11,12 +11,14 @@ class JobsService {
11
11
  #logging;
12
12
  #sentry;
13
13
  #registry = new Map();
14
+ #queueByType = new Map();
15
+ #queues = new Map();
14
16
  constructor({ backend, logging, sentry }) {
15
17
  this.#backend = backend;
16
18
  this.#logging = logging;
17
19
  this.#sentry = sentry;
18
20
  }
19
- handle(JobClass, handler) {
21
+ handle(JobClass, handler, options) {
20
22
  const type = JobClass.type;
21
23
  if (typeof type !== 'string' || type.length === 0) {
22
24
  throw new errors_1.default.IncorrectUsageError({
@@ -28,14 +30,52 @@ class JobsService {
28
30
  message: `A handler for job type "${type}" is already registered.`,
29
31
  });
30
32
  }
33
+ this.#declareQueue(type, options);
31
34
  this.#registry.set(type, (payload) => handler(new JobClass(JSON.parse(payload))));
32
35
  }
36
+ #declareQueue(type, options) {
37
+ if (!options) {
38
+ return;
39
+ }
40
+ const { queue, concurrency } = options;
41
+ if (typeof queue !== 'string' || queue.length === 0) {
42
+ throw new errors_1.default.IncorrectUsageError({
43
+ message: `Invalid queue for job type "${type}": ${JSON.stringify(queue)}. Expected a non-empty string.`,
44
+ });
45
+ }
46
+ // "default" is the backend's shared lane for types that declare no queue;
47
+ // declaring it would silently re-size that lane for every unrouted type.
48
+ if (queue === 'default') {
49
+ throw new errors_1.default.IncorrectUsageError({
50
+ message: `Queue name "default" is reserved for the shared lane; job type "${type}" must omit options to use it.`,
51
+ });
52
+ }
53
+ if (!Number.isInteger(concurrency) || concurrency < 1) {
54
+ throw new errors_1.default.IncorrectUsageError({
55
+ message: `Invalid concurrency for job type "${type}": ${JSON.stringify(concurrency)}. Expected a positive integer.`,
56
+ });
57
+ }
58
+ const existing = this.#queues.get(queue);
59
+ if (existing && existing.concurrency !== concurrency) {
60
+ throw new errors_1.default.IncorrectUsageError({
61
+ message: `Conflicting concurrency for queue "${queue}": ${existing.concurrency} is already declared, job type "${type}" declares ${concurrency}.`,
62
+ });
63
+ }
64
+ this.#queues.set(queue, { concurrency });
65
+ this.#queueByType.set(type, queue);
66
+ }
67
+ #routingFor(type) {
68
+ const queue = this.#queueByType.get(type);
69
+ return queue === undefined ? undefined : { queue };
70
+ }
33
71
  async dispatch(job) {
34
- await this.#backend.enqueue(this.#buildEnvelope(job));
72
+ const envelope = this.#buildEnvelope(job);
73
+ await this.#backend.enqueue(envelope, this.#routingFor(envelope.type));
35
74
  }
36
75
  async scheduleRecurring(job, schedule) {
37
76
  this.#assertValidCron(schedule.cron);
38
- await this.#backend.scheduleRecurring(this.#buildEnvelope(job), schedule);
77
+ const envelope = this.#buildEnvelope(job);
78
+ await this.#backend.scheduleRecurring(envelope, schedule, this.#routingFor(envelope.type));
39
79
  }
40
80
  // later.parse.cron does not strictly validate: it silently coerces a
41
81
  // malformed expression into a bogus schedule (garbage -> every minute,
@@ -55,11 +95,20 @@ class JobsService {
55
95
  async start() {
56
96
  await this.#backend.start({
57
97
  processor: (envelope) => this.#process(envelope),
98
+ queues: Object.fromEntries(this.#queues),
58
99
  });
59
100
  }
60
101
  async shutdown(options) {
61
102
  await this.#backend.shutdown(options);
62
103
  }
104
+ // An in-process restart (test harness) re-runs handler registration on the
105
+ // same instance, so all registration state resets - handlers and queue
106
+ // declarations alike. The duplicate-type guard still holds within a boot.
107
+ clearHandlers() {
108
+ this.#registry.clear();
109
+ this.#queueByType.clear();
110
+ this.#queues.clear();
111
+ }
63
112
  #buildEnvelope(job) {
64
113
  return { type: this.#typeOf(job), payload: JSON.stringify(job) };
65
114
  }
@@ -37,25 +37,46 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.default = registerJobHandlers;
40
- const errors_1 = __importDefault(require("@tryghost/errors"));
41
40
  const clean_tokens_job_1 = __importDefault(require("../members/jobs/clean-tokens-job"));
42
- const clean_tokens_task_1 = __importDefault(require("../members/jobs/clean-tokens-task"));
43
- const gifts = __importStar(require("../gifts"));
41
+ const clean_expired_comped_job_1 = __importDefault(require("../members/jobs/clean-expired-comped-job"));
44
42
  const clean_gifts_job_1 = __importDefault(require("../gifts/jobs/clean-gifts-job"));
45
43
  const external_media_inliner_job_1 = __importDefault(require("../media-inliner/external-media-inliner-job"));
46
- function registerJobHandlers({ jobsService, db, logging, mediaInliner, }) {
44
+ const content_csv_import_job_1 = __importDefault(require("../content-import/jobs/content-csv-import-job"));
45
+ const contentImport = __importStar(require("../content-import"));
46
+ const update_check_job_1 = __importDefault(require("../update-check/jobs/update-check-job"));
47
+ const process_webmention_job_1 = __importDefault(require("../mentions/process-webmention-job"));
48
+ const send_webmentions_job_1 = __importDefault(require("../mentions/send-webmentions-job"));
49
+ const updateCheck = require('../update-check');
50
+ // Webmention processing fetches external pages and is triggered by
51
+ // unauthenticated requests, so webmention jobs run in their own lane where a
52
+ // flood cannot occupy the shared workers. The concurrency matches the old
53
+ // dedicated mentions job queue. Every webmention job type must register with
54
+ // this shared declaration so none can declare the queue with a different
55
+ // concurrency.
56
+ const WEBMENTIONS_QUEUE = { queue: 'webmentions', concurrency: 3 };
57
+ function registerJobHandlers({ jobsService, memberJobs, giftService, mediaInliner, mentionsController, mentionsSendingService, }) {
47
58
  jobsService.handle(clean_tokens_job_1.default, async () => {
48
- await (0, clean_tokens_task_1.default)({ db, logging });
59
+ await memberJobs.cleanTokens();
60
+ });
61
+ jobsService.handle(clean_expired_comped_job_1.default, async () => {
62
+ await memberJobs.cleanExpiredComped();
49
63
  });
50
64
  jobsService.handle(clean_gifts_job_1.default, async () => {
51
- if (!gifts.service) {
52
- throw new errors_1.default.IncorrectUsageError({
53
- message: 'clean-gifts ran before the gifts service was initialised',
54
- });
55
- }
56
- await gifts.service.cleanup();
65
+ await giftService.cleanup();
57
66
  });
58
67
  jobsService.handle(external_media_inliner_job_1.default, async (job) => {
59
68
  await mediaInliner.inline(job.domains);
60
69
  });
70
+ jobsService.handle(content_csv_import_job_1.default, async (job) => {
71
+ await contentImport.handleJob(job);
72
+ });
73
+ jobsService.handle(update_check_job_1.default, async () => {
74
+ await updateCheck({ rethrowErrors: true });
75
+ });
76
+ jobsService.handle(process_webmention_job_1.default, async (job) => {
77
+ await mentionsController.processWebmention(job);
78
+ }, WEBMENTIONS_QUEUE);
79
+ jobsService.handle(send_webmentions_job_1.default, async (job) => {
80
+ await mentionsSendingService.sendWebmentions(job);
81
+ }, WEBMENTIONS_QUEUE);
61
82
  }
@@ -17,7 +17,7 @@ const messages = {
17
17
  reason: ' Reason: {reason}.',
18
18
  messageSent: 'Message sent. Double check inbox and spam folder!',
19
19
  };
20
- const EmailAddressParser = require('../email-address/email-address-parser');
20
+ const emailAddressParser = require('../email-address/email-address-parser');
21
21
  const DEFAULT_TAGS = ['ghost-email', 'transactional-email'];
22
22
  const MAX_MAILGUN_TAGS = 10;
23
23
 
@@ -54,8 +54,8 @@ function getFromAddress(requestedFromAddress, requestedReplyToAddress) {
54
54
  }
55
55
 
56
56
  return {
57
- from: EmailAddressParser.stringify(addresses.from),
58
- replyTo: addresses.replyTo ? EmailAddressParser.stringify(addresses.replyTo) : null,
57
+ from: emailAddressParser.stringify(addresses.from),
58
+ replyTo: addresses.replyTo ? emailAddressParser.stringify(addresses.replyTo) : null,
59
59
  };
60
60
  }
61
61
 
@@ -100,7 +100,7 @@ function createMessage(message) {
100
100
  */
101
101
  function createMailError({ message, err, ignoreDefaultMessage } = { message: '' }) {
102
102
  const helpMessage = tpl(messages.checkEmailConfigInstructions, {
103
- url: 'https://ghost.org/docs/config/#mail',
103
+ url: 'https://docs.ghost.org/config/#mail',
104
104
  });
105
105
  const defaultErrorMessage = tpl(messages.failedSendingEmailError);
106
106
 
@@ -7,7 +7,7 @@ const MagicLink = require('../lib/magic-link/magic-link');
7
7
  const sentry = require('../../../shared/sentry');
8
8
  const emailAddressService = require('../email-address');
9
9
  const settingsHelpers = require('../settings-helpers');
10
- const EmailAddressParser = require('../email-address/email-address-parser');
10
+ const emailAddressParser = require('../email-address/email-address-parser');
11
11
  const mail = require('../mail');
12
12
  const MailgunClient = require('../lib/mailgun-client');
13
13
  const config = require('../../../shared/config');
@@ -152,7 +152,7 @@ class MemberWelcomeEmailService {
152
152
  },
153
153
  });
154
154
 
155
- const from = EmailAddressParser.stringify(fromAddresses.from);
155
+ const from = emailAddressParser.stringify(fromAddresses.from);
156
156
  const replyToSetting = newsletter.get('sender_reply_to');
157
157
  let replyTo = null;
158
158
 
@@ -173,7 +173,7 @@ class MemberWelcomeEmailService {
173
173
  });
174
174
 
175
175
  if (addresses.replyTo) {
176
- replyTo = EmailAddressParser.stringify(addresses.replyTo);
176
+ replyTo = emailAddressParser.stringify(addresses.replyTo);
177
177
  }
178
178
  }
179
179
 
@@ -199,10 +199,10 @@ class MemberWelcomeEmailService {
199
199
  async #getEffectiveSenderOptions(automatedSender = {}) {
200
200
  const defaultOptions = await this.#getSenderOptions();
201
201
  const defaultFrom =
202
- EmailAddressParser.parse(defaultOptions.from || '') ||
202
+ emailAddressParser.parse(defaultOptions.from || '') ||
203
203
  emailAddressService.service.defaultFromEmail;
204
204
  const defaultReplyTo = defaultOptions.replyTo
205
- ? EmailAddressParser.parse(defaultOptions.replyTo)
205
+ ? emailAddressParser.parse(defaultOptions.replyTo)
206
206
  : undefined;
207
207
 
208
208
  const senderName = trimValue(automatedSender.senderName) || defaultFrom?.name || undefined;
@@ -218,10 +218,10 @@ class MemberWelcomeEmailService {
218
218
  });
219
219
 
220
220
  return {
221
- from: EmailAddressParser.stringify(addresses.from),
221
+ from: emailAddressParser.stringify(addresses.from),
222
222
  ...(addresses.replyTo
223
223
  ? {
224
- replyTo: EmailAddressParser.stringify(addresses.replyTo),
224
+ replyTo: emailAddressParser.stringify(addresses.replyTo),
225
225
  }
226
226
  : {}),
227
227
  };
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MemberAccountService = void 0;
7
+ const lodash_1 = __importDefault(require("lodash"));
8
+ const members_metafields_1 = require("../members-metafields");
9
+ /**
10
+ * A member's own account: what they are shown about themselves, and what they may
11
+ * change.
12
+ *
13
+ * Separate from the request handlers that used to hold this, because none of it is
14
+ * a question about HTTP. Which fields a member may set is a fact about members, and
15
+ * the answer is the same whoever is asking.
16
+ *
17
+ * Takes a member id rather than a member. Everything here either writes or reads
18
+ * afresh, and a record loaded before a write is stale by the time the answer is
19
+ * built, so there is nothing a caller could usefully hand over.
20
+ */
21
+ /** What a member is allowed to change about themselves. */
22
+ const WRITABLE_FIELDS = [
23
+ 'name',
24
+ 'expertise',
25
+ 'subscribed',
26
+ 'newsletters',
27
+ 'enable_comment_notifications',
28
+ 'enable_updates_and_announcements',
29
+ ];
30
+ /**
31
+ * The relations a write needs loaded to work out what it is changing.
32
+ *
33
+ * Newsletters because the older `subscribed` flag is stored as a list of them, and
34
+ * the subscription chain because changing what a member is entitled to has to
35
+ * reconcile against what they are paying for.
36
+ */
37
+ const WRITE_RELATIONS = [
38
+ 'stripeSubscriptions',
39
+ 'stripeSubscriptions.customer',
40
+ 'stripeSubscriptions.stripePrice',
41
+ 'newsletters',
42
+ ];
43
+ class MemberAccountService {
44
+ #memberBREADService;
45
+ #members;
46
+ #emailSuppressionList;
47
+ #metafieldValues;
48
+ constructor({ memberBREADService, members, emailSuppressionList, metafieldValues, }) {
49
+ this.#memberBREADService = memberBREADService;
50
+ this.#members = members;
51
+ this.#emailSuppressionList = emailSuppressionList;
52
+ this.#metafieldValues = metafieldValues;
53
+ }
54
+ /** Everything a member is shown about themselves. */
55
+ async read(memberId) {
56
+ // As the member rather than as staff: how much of the extra fields a publisher
57
+ // defines is answered depends on which side of Ghost is asking.
58
+ return this.#memberBREADService.read({ id: memberId }, { metafieldsFor: members_metafields_1.MEMBERS });
59
+ }
60
+ /** Apply what a member asked to change about themselves, and say what they now hold. */
61
+ async edit(data, memberId) {
62
+ // Worked out before the member is touched, so a value the catalog refuses fails
63
+ // the whole request rather than leaving a member renamed with their answers
64
+ // rejected. The write below reconciles subscriptions with Stripe and sends
65
+ // events, none of which giving up halfway could undo.
66
+ const plannedMetafields = data.metafields === undefined
67
+ ? null
68
+ : await this.#metafieldValues.planWrite(this.#metafieldValues.unwrapWire(data.metafields), members_metafields_1.MEMBERS);
69
+ await this.#members.update(lodash_1.default.pick(data, WRITABLE_FIELDS), {
70
+ id: memberId,
71
+ withRelated: WRITE_RELATIONS,
72
+ });
73
+ if (plannedMetafields) {
74
+ // A member is recorded as the author of their own answers, and is the one
75
+ // writer whose changes leave nothing in the staff action log: that log
76
+ // records what staff did.
77
+ await this.#metafieldValues.applyWrite(memberId, plannedMetafields, {
78
+ writtenBy: { type: 'member', id: memberId },
79
+ });
80
+ }
81
+ // Read back rather than returning what was written: a member is told what
82
+ // Ghost now holds, which is not always what they sent. Setting the older
83
+ // `subscribed` flag, for one, is stored as a list of newsletters.
84
+ return this.read(memberId);
85
+ }
86
+ /**
87
+ * Let Ghost email this member again.
88
+ *
89
+ * Two records rather than one: the address is on a list the email provider also
90
+ * writes to, and the member carries a flag of their own. A member asking to hear
91
+ * from a site again means both.
92
+ */
93
+ async allowEmail(memberId, email) {
94
+ await this.#emailSuppressionList.removeEmail(email);
95
+ await this.#members.update({ email_disabled: false }, { id: memberId });
96
+ }
97
+ }
98
+ exports.MemberAccountService = MemberAccountService;