ghost 6.61.0 → 6.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (472) hide show
  1. package/components/ghost-storage-base-3.0.0.tgz +0 -0
  2. package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
  3. package/components/tryghost-adapter-base-jobs-0.0.0.tgz +0 -0
  4. package/components/tryghost-adapter-base-redirects-0.0.0.tgz +0 -0
  5. package/components/tryghost-adapter-base-route-settings-0.0.0.tgz +0 -0
  6. package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
  7. package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
  8. package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
  9. package/components/tryghost-checkout-0.0.0.tgz +0 -0
  10. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  11. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  12. package/components/tryghost-kg-card-factory-5.2.4.tgz +0 -0
  13. package/components/tryghost-kg-clean-basic-html-4.3.4.tgz +0 -0
  14. package/components/tryghost-kg-converters-1.2.5.tgz +0 -0
  15. package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
  16. package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
  17. package/components/tryghost-kg-default-transforms-1.3.4.tgz +0 -0
  18. package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
  19. package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
  20. package/components/tryghost-kg-markdown-html-renderer-7.2.4.tgz +0 -0
  21. package/components/tryghost-kg-utils-1.1.4.tgz +0 -0
  22. package/components/tryghost-nql-string-0.0.0.tgz +0 -0
  23. package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
  24. package/content/settings/README.md +1 -1
  25. package/content/themes/casper/.gitignore +28 -0
  26. package/content/themes/casper/assets/built/casper.js +1 -1
  27. package/content/themes/casper/assets/built/screen.css +1 -1
  28. package/content/themes/casper/assets/css/screen.css +2 -1
  29. package/content/themes/casper/assets/js/lightbox.js +63 -46
  30. package/content/themes/casper/package.json +6 -6
  31. package/content/themes/casper/page.hbs +1 -0
  32. package/content/themes/casper/post.hbs +1 -0
  33. package/content/themes/source/.gitignore +28 -0
  34. package/content/themes/source/assets/built/screen.css +1 -1
  35. package/content/themes/source/assets/built/source.js +1 -1
  36. package/content/themes/source/assets/css/screen.css +2 -1
  37. package/content/themes/source/assets/js/lightbox.js +62 -45
  38. package/content/themes/source/assets/js/main.js +2 -2
  39. package/content/themes/source/package.json +4 -4
  40. package/content/themes/source/partials/feature-image.hbs +1 -0
  41. package/core/boot.js +54 -22
  42. package/core/built/admin/assets/Combination-B0l4MKVh.js +41 -0
  43. package/core/built/admin/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
  44. package/core/built/admin/assets/InterVariable-Italic-FCBEiFp6.woff2 +0 -0
  45. package/core/built/admin/assets/{about-Bve7IJS2.js → about-Dyae_UT6.js} +1 -1
  46. package/core/built/admin/assets/account-migration-CESa0mnX.js +1 -0
  47. package/core/built/admin/assets/activitypub/{account-migration-C-aej4x_.js → account-migration-By69CgCp.js} +16 -16
  48. package/core/built/admin/assets/activitypub/activitypub.js +9 -9
  49. package/core/built/admin/assets/activitypub/{bluesky-sharing-BXkA5mqV.js → bluesky-sharing-BJcPMrDd.js} +36 -36
  50. package/core/built/admin/assets/activitypub/{content-formatters-CHcyMFk4.js → content-formatters-3rTHg3mp.js} +3 -3
  51. package/core/built/admin/assets/activitypub/{domain-B3ihkPde.js → domain-DUR4xSkV.js} +121 -121
  52. package/core/built/admin/assets/activitypub/{edit-profile-DsZM3rTX.js → edit-profile-BqtfzxCp.js} +40 -40
  53. package/core/built/admin/assets/activitypub/{explore-BodNrZgR.js → explore-BxuJd-J4.js} +26 -26
  54. package/core/built/admin/assets/activitypub/{feed-PwH1iJ84.js → feed-BM1TcksA.js} +48 -48
  55. package/core/built/admin/assets/activitypub/{field-D06-kmOJ.js → field-Dn7HHx2-.js} +2 -2
  56. package/core/built/admin/assets/activitypub/inbox-CCjkuow2.js +1284 -0
  57. package/core/built/admin/assets/activitypub/label-1AA_s9Fa.js +16 -0
  58. package/core/built/admin/assets/activitypub/layout-2-0bw6HN.js +1 -0
  59. package/core/built/admin/assets/activitypub/{moderation-D1Yapsod.js → moderation-CnmxEB8w.js} +91 -91
  60. package/core/built/admin/assets/activitypub/{note-C5zjqq5C.js → note-ZKc_Bnba.js} +23 -23
  61. package/core/built/admin/assets/activitypub/{notifications-B9p8eCHD.js → notifications-CB2tJZau.js} +48 -48
  62. package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-BsJ9E5qf.js} +2 -2
  63. package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-CSUJJIlh.js} +2 -2
  64. package/core/built/admin/assets/activitypub/{preferences-BCqUdC3v.js → preferences-0-JZnUkI.js} +1519 -1519
  65. package/core/built/admin/assets/activitypub/{profile-BRCWoFem.js → profile-C35cFIhM.js} +183 -183
  66. package/core/built/admin/assets/activitypub/{routes-BSXT992i.js → routes-BD4vscyc.js} +740 -731
  67. package/core/built/admin/assets/activitypub/settings-BsMROdqh.js +315 -0
  68. package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-O0RL9YCN.js} +2 -2
  69. package/core/built/admin/assets/activitypub/{step-1-B-YfsVeO.js → step-1-BMSx7c_X.js} +4 -4
  70. package/core/built/admin/assets/activitypub/{step-3-D6BFMXL_.js → step-3-CLlOZTyt.js} +3 -3
  71. package/core/built/admin/assets/activitypub/{tabs-GpNecvfB.js → tabs-Dxk-b9M-.js} +306 -306
  72. package/core/built/admin/assets/activitypub/{topic-filter-BPDeQQys.js → topic-filter-5yZH6tId.js} +2 -2
  73. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-BoVOxXkV.js → use-activity-pub-queries-CV50qe03.js} +2 -2
  74. package/core/built/admin/assets/activitypub/{use-reply-chain-data-wVBX7swM.js → use-reply-chain-data-Cbvzgjzd.js} +30 -30
  75. package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-BjcoP_HC.js} +7 -5
  76. package/core/built/admin/assets/add-integration-modal-BlF6rs_f.js +1 -0
  77. package/core/built/admin/assets/add-newsletter-modal-CglVQqah.js +1 -0
  78. package/core/built/admin/assets/add-recommendation-modal-wz7BsuaG.js +1 -0
  79. package/core/built/admin/assets/analytics-C4HE1gBg.js +1 -0
  80. package/core/built/admin/assets/{announcement-bar-modal-DM3cYOpo.js → announcement-bar-modal-Ci4zz8jO.js} +1 -1
  81. package/core/built/admin/assets/{api-keys-BLm2NDBh.js → api-keys-Ck-Yteiv.js} +1 -1
  82. package/core/built/admin/assets/{audience-9mwU5TW6.js → audience-CtbA54Sn.js} +1 -1
  83. package/core/built/admin/assets/{automated-emails-te1D5kq-.js → automated-emails-D5VVMND9.js} +1 -1
  84. package/core/built/admin/assets/automations-CzKt5fb8.js +1 -0
  85. package/core/built/admin/assets/bluesky-sharing-BEtJ_gL_.js +1 -0
  86. package/core/built/admin/assets/{breadcrumb-DLiqCyFc.js → breadcrumb-zUrZrBtW.js} +1 -1
  87. package/core/built/admin/assets/{button-B2jcu6bk.js → button-eNMKQWXr.js} +1 -1
  88. package/core/built/admin/assets/{chart-helpers-Fo3bUL3K.js → chart-helpers-CfBKt0vT.js} +1 -1
  89. package/core/built/admin/assets/{checkbox-BfKktMph.js → checkbox-CgOn_tKW.js} +1 -1
  90. package/core/built/admin/assets/{chunk.524.60ca4692d91c6022042f.js → chunk.524.a697dee88db67fdf6021.js} +4 -4
  91. package/core/built/admin/assets/{chunk.582.525c7617c2d9e94c940a.js → chunk.582.5ed5d124cfca9c259b9c.js} +6 -6
  92. package/core/built/admin/assets/{chunk.896.435fe0637944d4a69810.js → chunk.598.7e056fabb47ce7dbd73f.js} +14 -14
  93. package/core/built/admin/assets/{code-editor-view-CYVu4EW6.js → code-editor-view-BYNoAoNV.js} +1 -1
  94. package/core/built/admin/assets/{code-editor-view-DCQJxsfU.js → code-editor-view-K2wI-I5f.js} +1 -1
  95. package/core/built/admin/assets/color-picker-Ddw80xX6.js +3 -0
  96. package/core/built/admin/assets/color-picker-field-D9nUhvA7.js +1 -0
  97. package/core/built/admin/assets/combobox-w9j8PPQT.js +1 -0
  98. package/core/built/admin/assets/command-BfpHORBv.js +1 -0
  99. package/core/built/admin/assets/comments-BLmCmyCs.js +1 -0
  100. package/core/built/admin/assets/confirmation-context-CBM8G0Vj.js +1 -0
  101. package/core/built/admin/assets/{content-api-modal-CyQEC3fr.js → content-api-modal-TXRz3U7S.js} +1 -1
  102. package/core/built/admin/assets/context-menu-_QMdd3kp.js +1 -0
  103. package/core/built/admin/assets/{copy-field-B3M1s78L.js → copy-field-6N01S07E.js} +1 -1
  104. package/core/built/admin/assets/create-ghost-browse-value-source-qIBymvvf.js +1 -0
  105. package/core/built/admin/assets/custom-field-type-option-BddFlJFa.js +1 -0
  106. package/core/built/admin/assets/custom-integration-modal-DmNquxUV.js +1 -0
  107. package/core/built/admin/assets/{date-range-select-DD2RKkgB.js → date-range-select-uvz_DtPh.js} +1 -1
  108. package/core/built/admin/assets/design-and-theme-modal-BSmo12Op.js +2 -0
  109. package/core/built/admin/assets/dirty-confirm-dialog-BZ1iytEd.js +1 -0
  110. package/core/built/admin/assets/{disabled-sources-indicator-Cvy47bE2.js → disabled-sources-indicator-DMRrxsiJ.js} +1 -1
  111. package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
  112. package/core/built/admin/assets/domain-BNYrt0aD.js +1 -0
  113. package/core/built/admin/assets/dropzone-D7nFdAe5.js +5 -0
  114. package/core/built/admin/assets/edit-profile-C5Asm4LA.js +1 -0
  115. package/core/built/admin/assets/editor-REokrzci.js +8 -0
  116. package/core/built/admin/assets/{embed-signup-form-modal-DeBMLxlL.js → embed-signup-form-modal-Ds6mPEi5.js} +1 -1
  117. package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
  118. package/core/built/admin/assets/explore-UY10Egsp.js +1 -0
  119. package/core/built/admin/assets/feature-image-placeholder-D1iF_8bc.js +1 -0
  120. package/core/built/admin/assets/feed-81C8mJWR.js +1 -0
  121. package/core/built/admin/assets/{field-Cj8lmDOo.js → field-Dihp5p18.js} +1 -1
  122. package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
  123. package/core/built/admin/assets/filter-sources-BO9xUPj7.js +1 -0
  124. package/core/built/admin/assets/filters-CRUWecfY.js +1 -0
  125. package/core/built/admin/assets/filters-DirqNXjH.js +1 -0
  126. package/core/built/admin/assets/first-promoter-modal-CT6MxYZb.js +1 -0
  127. package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8eabfc1ece81b03cf7b90780d31487e8.css} +1 -1
  128. package/core/built/admin/assets/{ghost-3894eedcc6968f658578c0abfe942aab.js → ghost-c2848508292937415f20f5a830eea59e.js} +31 -28
  129. package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-a7bebe2c561f55369dcf29f4c820f7ff.css} +1 -1
  130. package/core/built/admin/assets/gift-link-modal-CQVAye17.js +1 -0
  131. package/core/built/admin/assets/growth-BWIu-6xj.js +3 -0
  132. package/core/built/admin/assets/growth-DU29oxeA.js +1 -0
  133. package/core/built/admin/assets/history-modal-CFd1Hvx6.js +1 -0
  134. package/core/built/admin/assets/{html-field-C8qVGGC1.js → html-field-CJBCLTvv.js} +1 -1
  135. package/core/built/admin/assets/{images-h8VZEQ9k.js → images-scfkWZiK.js} +1 -1
  136. package/core/built/admin/assets/{inbox-BYd1M06Q.js → inbox-Mcp4DXZN.js} +14 -14
  137. package/core/built/admin/assets/index-6MkPdCtr.js +4 -0
  138. package/core/built/admin/assets/index-Bn7QhcZu.css +2 -0
  139. package/core/built/admin/assets/index.es-CNnuNH0d.js +1 -0
  140. package/core/built/admin/assets/{input-group-D8sCXRF5.js → input-group-CMhe2DvY.js} +1 -1
  141. package/core/built/admin/assets/invite-user-modal-DfheMXs0.js +1 -0
  142. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
  143. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
  144. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  145. package/core/built/admin/assets/{koenig-lexical-_-IsVI7E.js → koenig-lexical-DBSqAuiI.js} +3 -3
  146. package/core/built/admin/assets/koenig-loader-aFQNlJlD.js +2 -0
  147. package/core/built/admin/assets/{kpi-card-DZQk_0W8.js → kpi-card-DBRMfGOW.js} +1 -1
  148. package/core/built/admin/assets/{kpi-card-DW_2y3ug.js → kpi-card-DFafD1qq.js} +1 -1
  149. package/core/built/admin/assets/{kpi-helpers-PueTKuA6.js → kpi-helpers-Cv8i8hns.js} +1 -1
  150. package/core/built/admin/assets/{kpi-tabs-CojDs-Qz.js → kpi-tabs-BJItvLYm.js} +1 -1
  151. package/core/built/admin/assets/{label-DjbT91GM.js → label-BnSCvffu.js} +1 -1
  152. package/core/built/admin/assets/label-picker-KVoo91sh.js +1 -0
  153. package/core/built/admin/assets/layout-Bjv2Ll-5.js +1 -0
  154. package/core/built/admin/assets/member-custom-fields-DDQV6QeG.js +1 -0
  155. package/core/built/admin/assets/member-detail-CdJF6Agw.js +1 -0
  156. package/core/built/admin/assets/members-DjQbq9Z2.js +4 -0
  157. package/core/built/admin/assets/moderation-AgCIEso4.js +1 -0
  158. package/core/built/admin/assets/{multi-select-combobox-B6LiRzDO.js → multi-select-combobox-BcITkUVr.js} +1 -1
  159. package/core/built/admin/assets/navigation-modal-BkT7b1M2.js +1 -0
  160. package/core/built/admin/assets/newsletter-BMMAuvgq.js +1 -0
  161. package/core/built/admin/assets/newsletter-detail-modal-0SCJ7Zpm.js +1 -0
  162. package/core/built/admin/assets/{newsletter-emails-CFeLlt4z.js → newsletter-emails-DKzwafuh.js} +1 -1
  163. package/core/built/admin/assets/newsletters-BRBb_uQC.js +1 -0
  164. package/core/built/admin/assets/note-DyGHtS9a.js +1 -0
  165. package/core/built/admin/assets/notifications-ZgWniKna.js +1 -0
  166. package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
  167. package/core/built/admin/assets/offers-container-modal-B-E8TIWr.js +1 -0
  168. package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-CzIsre-d.js} +1 -1
  169. package/core/built/admin/assets/onboarding-qg8Akovm.js +1 -0
  170. package/core/built/admin/assets/{onboarding-route-Dmc4IPm3.js → onboarding-route-CaavZulg.js} +1 -1
  171. package/core/built/admin/assets/overview-BW8GLeYi.js +1 -0
  172. package/core/built/admin/assets/overview-BkXZNzaZ.js +1 -0
  173. package/core/built/admin/assets/{page-header-BR_nbIPp.js → page-header-De0VzKBi.js} +1 -1
  174. package/core/built/admin/assets/pagemenu-B5KKCpbA.js +1 -0
  175. package/core/built/admin/assets/pages-jgaFm69d.js +1 -0
  176. package/core/built/admin/assets/pages-route-CIUAQxtY.js +1 -0
  177. package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
  178. package/core/built/admin/assets/{pintura-modal-BR9hEvS8.js → pintura-modal-BZ2J9w3n.js} +1 -1
  179. package/core/built/admin/assets/portal-frame-B6Hr9wHc.js +1 -0
  180. package/core/built/admin/assets/portal-modal-D4ceei3t.js +1 -0
  181. package/core/built/admin/assets/post-analytics-header-BYCsT0GP.js +1 -0
  182. package/core/built/admin/assets/post-analytics-ot7f6pih.js +1 -0
  183. package/core/built/admin/assets/{post-analytics-provider-CLfKGWZy.js → post-analytics-provider-Bo1gmYaP.js} +1 -1
  184. package/core/built/admin/assets/{post-share-modal-Cl0NXRJr.js → post-share-modal-C-PaYZ_e.js} +1 -1
  185. package/core/built/admin/assets/posts-DuGazgTb.js +1 -0
  186. package/core/built/admin/assets/posts-list-screen-CBGGgjjj.js +2 -0
  187. package/core/built/admin/assets/posts-route-D6xmS7Vf.js +1 -0
  188. package/core/built/admin/assets/preferences-C5YJLp74.js +5 -0
  189. package/core/built/admin/assets/{preview-modal-C-BL-F9k.js → preview-modal-BfeFqi5y.js} +1 -1
  190. package/core/built/admin/assets/profile-B8mx2yAu.js +1 -0
  191. package/core/built/admin/assets/radio-group-DczlLKOn.js +1 -0
  192. package/core/built/admin/assets/{schemas-4UPic-oD.js → schemas-DppqmpeJ.js} +1 -1
  193. package/core/built/admin/assets/select-cb0t_TAJ.js +1 -0
  194. package/core/built/admin/assets/settings-DZqxR0Da.js +1 -0
  195. package/core/built/admin/assets/settings-DvfTNdHQ.js +4 -0
  196. package/core/built/admin/assets/{settings-breadcrumbs-CyP_9zTo.js → settings-breadcrumbs-DLzbRRSt.js} +1 -1
  197. package/core/built/admin/assets/share-modal-D2-Bz1_I.js +1 -0
  198. package/core/built/admin/assets/slack-modal-DYDTUria.js +1 -0
  199. package/core/built/admin/assets/{sort-button-Cc-Z96sA.js → sort-button-VVeQjjbu.js} +1 -1
  200. package/core/built/admin/assets/{source-icon-v6PUnmyM.js → source-icon-Ck5_5Kgq.js} +1 -1
  201. package/core/built/admin/assets/stats-Rjmk5owg.js +1 -0
  202. package/core/built/admin/assets/stats-view-BGGmkmgv.js +1 -0
  203. package/core/built/admin/assets/{step-1-DSRp2vBj.js → step-1-CsaBjeN4.js} +1 -1
  204. package/core/built/admin/assets/{step-2-COqv2g0u.js → step-2-D2vnxOOM.js} +1 -1
  205. package/core/built/admin/assets/{step-3-6W1NMVQc.js → step-3-wBoLdGEb.js} +2 -2
  206. package/core/built/admin/assets/{stripe-button-D2K42Uty.js → stripe-button-CDgLz0S0.js} +1 -1
  207. package/core/built/admin/assets/stripe-connect-modal-CSjMJetP.js +1 -0
  208. package/core/built/admin/assets/{table-B2pIKjVh.js → table-Do6iQ83Q.js} +1 -1
  209. package/core/built/admin/assets/{tabs-SaW_UT-Q.js → tabs-D2yWLMp_.js} +1 -1
  210. package/core/built/admin/assets/tag-detail-BhXlOsCa.js +2 -0
  211. package/core/built/admin/assets/tags-ldukRApe.js +1 -0
  212. package/core/built/admin/assets/testimonials-modal-CtnZBJKl.js +1 -0
  213. package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +1 -0
  214. package/core/built/admin/assets/{toggle-group-EM9WpESu.js → toggle-group-ByUJsxwD.js} +1 -1
  215. package/core/built/admin/assets/{topic-filter-DY4gNHn2.js → topic-filter-BgC3g5_v.js} +1 -1
  216. package/core/built/admin/assets/{transistor-modal-CpyPG-MH.js → transistor-modal-Drr0SNfo.js} +1 -1
  217. package/core/built/admin/assets/{trend-badge-ByMkuAuH.js → trend-badge-6ye93YAW.js} +1 -1
  218. package/core/built/admin/assets/{unsplash-modal-Cv2Q6GtY.js → unsplash-modal-p6AoQoWp.js} +1 -1
  219. package/core/built/admin/assets/{use-analytics-data-CHvjMYuT.js → use-analytics-data-CWCMAESo.js} +1 -1
  220. package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
  221. package/core/built/admin/assets/{use-check-theme-limit-error-Qv4SVXqw.js → use-check-theme-limit-error-Cw3WQHy8.js} +1 -1
  222. package/core/built/admin/assets/use-filter-params-BIni9taJ.js +1 -0
  223. package/core/built/admin/assets/use-growth-stats-DCVG3s9w.js +1 -0
  224. package/core/built/admin/assets/{use-limiter-cwJvsNBo.js → use-limiter-D2WRRx0H.js} +1 -1
  225. package/core/built/admin/assets/{use-pintura-config-CzTfnufz.js → use-pintura-config-h-J0Lvta.js} +1 -1
  226. package/core/built/admin/assets/{use-pintura-editor-BDBXWUYq.js → use-pintura-editor-BfN1UwzH.js} +1 -1
  227. package/core/built/admin/assets/use-post-referrers-Czg47m8s.js +1 -0
  228. package/core/built/admin/assets/use-reply-chain-data-ns0caK8k.js +1 -0
  229. package/core/built/admin/assets/{use-router-history-entry-Bg6BhBQQ.js → use-router-history-entry-uldn7zJO.js} +1 -1
  230. package/core/built/admin/assets/{use-setting-group-VM7FQwMY.js → use-setting-group-DpcuCUDg.js} +1 -1
  231. package/core/built/admin/assets/use-settings-navigation-CZjGrhsp.js +1 -0
  232. package/core/built/admin/assets/{use-simple-pagination-Dum6Irbs.js → use-simple-pagination-DzJWobPR.js} +1 -1
  233. package/core/built/admin/assets/{use-staff-users-cZg4ugOF.js → use-staff-users-Csipb-O0.js} +1 -1
  234. package/core/built/admin/assets/use-tinybird-query-CSnGXzZh.js +1 -0
  235. package/core/built/admin/assets/use-tinybird-token-DTOKRR7e.js +1 -0
  236. package/core/built/admin/assets/{use-unsaved-changes-guard-BAy0RANR.js → use-unsaved-changes-guard-CBzs-KPi.js} +1 -1
  237. package/core/built/admin/assets/{use-url-input-Df5QzNa7.js → use-url-input-DFr8lCbS.js} +1 -1
  238. package/core/built/admin/assets/user-detail-modal-B_iUClI6.js +1 -0
  239. package/core/built/admin/assets/users-Cg-OeGzC.js +1 -0
  240. package/core/built/admin/assets/{virtual-list-DEx8WgiO.js → virtual-list-BW-padMe.js} +1 -1
  241. package/core/built/admin/assets/web-C1v33ehA.js +2 -0
  242. package/core/built/admin/assets/web-C4BKzn2T.js +1 -0
  243. package/core/built/admin/assets/{zapier-modal-Cw3BTBUu.js → zapier-modal-BBFfI6Ml.js} +1 -1
  244. package/core/built/admin/index.html +17 -22
  245. package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
  246. package/core/frontend/helpers/cancel_link.js +2 -2
  247. package/core/frontend/helpers/pagination.js +2 -2
  248. package/core/frontend/helpers/social_accounts.js +2 -2
  249. package/core/frontend/public/ghost.css +1 -1
  250. package/core/frontend/public/ghost.min.css +1 -1
  251. package/core/frontend/services/sitemap/user-map-generator.js +9 -2
  252. package/core/server/api/endpoints/index.js +2 -2
  253. package/core/server/api/endpoints/mail.js +1 -1
  254. package/core/server/api/endpoints/{member-custom-fields.js → member-metafields.js} +27 -28
  255. package/core/server/api/endpoints/members.js +4 -4
  256. package/core/server/api/endpoints/posts.js +3 -3
  257. package/core/server/api/endpoints/utils/serializers/input/members.js +4 -7
  258. package/core/server/api/endpoints/utils/serializers/output/index.js +2 -2
  259. package/core/server/api/endpoints/utils/serializers/output/{member-custom-fields.js → member-metafields.js} +2 -4
  260. package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
  261. package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
  262. package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
  263. package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
  264. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  265. package/core/server/data/migrations/utils/migrations.js +1 -1
  266. package/core/server/lib/image/image-size.js +24 -0
  267. package/core/server/lib/package-json/parse.js +2 -2
  268. package/core/server/models/member.js +6 -17
  269. package/core/server/models/post.js +2 -2
  270. package/core/server/models/relations/authors.js +2 -16
  271. package/core/server/models/user.js +9 -2
  272. package/core/server/services/auth/passwordreset.js +13 -0
  273. package/core/server/services/comments/comments-controller.js +30 -9
  274. package/core/server/services/comments/comments-service.js +55 -5
  275. package/core/server/services/content-import/csv/formula.js +12 -0
  276. package/core/server/services/content-import/csv/index.js +6 -1
  277. package/core/server/services/content-import/csv/parse.js +27 -6
  278. package/core/server/services/content-import/csv/serialize.js +13 -0
  279. package/core/server/services/content-import/import/completion-email.js +164 -0
  280. package/core/server/services/content-import/import/errors-file.js +36 -0
  281. package/core/server/services/content-import/import/importer.js +160 -53
  282. package/core/server/services/content-import/import/local-media-url.js +63 -0
  283. package/core/server/services/content-import/import/media.js +254 -0
  284. package/core/server/services/content-import/import/post-data.js +0 -1
  285. package/core/server/services/content-import/import/post-link.js +11 -0
  286. package/core/server/services/content-import/import/post-repository.js +25 -3
  287. package/core/server/services/content-import/import/reader.js +9 -2
  288. package/core/server/services/content-import/import/report.js +34 -0
  289. package/core/server/services/content-import/import/row.js +0 -2
  290. package/core/server/services/content-import/import/schema.js +1 -0
  291. package/core/server/services/content-import/import/staged-file.js +29 -0
  292. package/core/server/services/content-import/import/store.js +25 -2
  293. package/core/server/services/content-import/index.js +52 -6
  294. package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
  295. package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
  296. package/core/server/services/custom-redirects/redirects-service.js +1 -1
  297. package/core/server/services/custom-redirects/validation.js +1 -1
  298. package/core/server/services/email-address/email-address-parser.js +30 -38
  299. package/core/server/services/email-address/email-address-service.js +37 -4
  300. package/core/server/services/email-analytics/index.js +2 -7
  301. package/core/server/services/email-service/batch-sending-service.js +0 -4
  302. package/core/server/services/email-service/email-renderer.js +14 -4
  303. package/core/server/services/email-service/email-service-wrapper.js +0 -9
  304. package/core/server/services/email-service/mailgun-email-provider.js +20 -9
  305. package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
  306. package/core/server/services/gifts/gift-email-service.js +0 -1
  307. package/core/server/services/gifts/index.js +3 -3
  308. package/core/server/services/gifts/jobs/index.js +4 -4
  309. package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
  310. package/core/server/services/invitations/accept.js +4 -2
  311. package/core/server/services/jobs/job-service.js +0 -9
  312. package/core/server/services/jobs-service/register-job-handlers.js +21 -11
  313. package/core/server/services/mail/ghost-mailer.js +4 -4
  314. package/core/server/services/member-welcome-emails/service.js +7 -7
  315. package/core/server/services/members/api.js +1 -0
  316. package/core/server/services/members/import-export/csv/parse.js +0 -7
  317. package/core/server/services/members/import-export/import/completion-email.js +2 -5
  318. package/core/server/services/members/import-export/import/row.js +0 -3
  319. package/core/server/services/members/import-export/index.js +4 -11
  320. package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
  321. package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
  322. package/core/server/services/members/jobs/index.js +48 -24
  323. package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
  324. package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
  325. package/core/server/services/members/members-api/members-api.js +4 -6
  326. package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
  327. package/core/server/services/members/members-api/services/member-bread-service.js +34 -62
  328. package/core/server/services/members/members-api/services/payments-service.js +1 -1
  329. package/core/server/services/members/service.js +1 -5
  330. package/core/server/services/members-custom-fields/bindings-service.js +2 -1
  331. package/core/server/services/members-custom-fields/codec.js +3 -4
  332. package/core/server/services/members-custom-fields/definitions-service.js +62 -10
  333. package/core/server/services/members-custom-fields/filter.js +75 -93
  334. package/core/server/services/members-custom-fields/key.js +2 -1
  335. package/core/server/services/members-custom-fields/models.js +1 -1
  336. package/core/server/services/members-custom-fields/serializers.js +3 -5
  337. package/core/server/services/members-custom-fields/values-service.js +50 -28
  338. package/core/server/services/mentions/mention-controller.js +23 -21
  339. package/core/server/services/mentions/process-webmention-job.js +16 -0
  340. package/core/server/services/mentions/service.js +8 -4
  341. package/core/server/services/route-settings/validation-errors.js +1 -1
  342. package/core/server/services/route-settings/yaml-parser.js +1 -1
  343. package/core/server/services/settings/settings-service.js +1 -8
  344. package/core/server/services/settings-helpers/settings-helpers.js +4 -6
  345. package/core/server/services/slack-ping/slack-ping-service.js +1 -1
  346. package/core/server/services/staff/staff-service-emails.js +2 -2
  347. package/core/server/services/stripe/config.js +14 -8
  348. package/core/server/services/stripe/service.js +10 -1
  349. package/core/server/services/stripe/services/checkout/completed-session.js +2 -2
  350. package/core/server/services/stripe/services/checkout/session-options.js +18 -15
  351. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +26 -5
  352. package/core/server/services/stripe/stripe-api.js +2 -0
  353. package/core/server/services/stripe/stripe-service.js +20 -10
  354. package/core/server/services/stripe/webhook-controller.js +10 -0
  355. package/core/server/services/tier-checkout-config/codec.js +9 -5
  356. package/core/server/services/tier-checkout-config/models.js +9 -3
  357. package/core/server/services/tier-checkout-config/queries.js +4 -4
  358. package/core/server/services/tier-checkout-config/serializers.js +16 -10
  359. package/core/server/services/tier-checkout-config/service.js +13 -12
  360. package/core/server/services/update-check/index.js +13 -13
  361. package/core/server/services/update-check/jobs/update-check-job.js +7 -0
  362. package/core/server/services/update-check/update-check-service.js +2 -2
  363. package/core/server/web/admin/controller.js +1 -1
  364. package/core/server/web/api/endpoints/admin/routes.js +19 -16
  365. package/core/shared/config/env/config.testing-mysql.json +1 -1
  366. package/core/shared/labs.js +5 -2
  367. package/package.json +24 -23
  368. package/pnpm-lock.yaml +704 -69
  369. package/pnpm-workspace.yaml +8 -5
  370. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  371. package/core/built/admin/assets/Combination-5fYEzgbs.js +0 -41
  372. package/core/built/admin/assets/account-migration-DRhAehfw.js +0 -1
  373. package/core/built/admin/assets/activitypub/inbox-BluD2ucT.js +0 -1284
  374. package/core/built/admin/assets/activitypub/label-FHSh6ZAw.js +0 -16
  375. package/core/built/admin/assets/activitypub/layout-Cq4NG0Xr.js +0 -1
  376. package/core/built/admin/assets/activitypub/settings-DQDkr06X.js +0 -315
  377. package/core/built/admin/assets/add-integration-modal-BC0jExDZ.js +0 -1
  378. package/core/built/admin/assets/add-newsletter-modal-DchTkA7l.js +0 -1
  379. package/core/built/admin/assets/add-recommendation-modal-DMvaJZKp.js +0 -1
  380. package/core/built/admin/assets/alert-dialog-QhXzdHfc.js +0 -1
  381. package/core/built/admin/assets/analytics-No1DDY3A.js +0 -1
  382. package/core/built/admin/assets/automations-DpUNUdcZ.js +0 -1
  383. package/core/built/admin/assets/bluesky-sharing-Cjrv_f62.js +0 -1
  384. package/core/built/admin/assets/color-picker-BTY_NdEm.js +0 -3
  385. package/core/built/admin/assets/color-picker-field-CPlkzOH0.js +0 -1
  386. package/core/built/admin/assets/combobox-DrMtv_4P.js +0 -1
  387. package/core/built/admin/assets/command-ZdgYJpoI.js +0 -1
  388. package/core/built/admin/assets/comments-kidj60-h.js +0 -1
  389. package/core/built/admin/assets/confirmation-context-BhbmQQEl.js +0 -1
  390. package/core/built/admin/assets/custom-field-type-option-CsGIZk1J.js +0 -10
  391. package/core/built/admin/assets/custom-integration-modal-BY37O_9X.js +0 -1
  392. package/core/built/admin/assets/design-and-theme-modal-DUSKM4uC.js +0 -22
  393. package/core/built/admin/assets/dialog-B44iRwlc.js +0 -1
  394. package/core/built/admin/assets/dirty-confirm-dialog-BxgQgQ6H.js +0 -1
  395. package/core/built/admin/assets/dist-Cy8tfrp_.js +0 -1
  396. package/core/built/admin/assets/domain-Ca6KhoQt.js +0 -1
  397. package/core/built/admin/assets/dropzone-Bb-5zQTk.js +0 -5
  398. package/core/built/admin/assets/edit-profile-BdupLlus.js +0 -1
  399. package/core/built/admin/assets/editor-BP883Lpn.js +0 -8
  400. package/core/built/admin/assets/explore-FB-CimXw.js +0 -1
  401. package/core/built/admin/assets/feed-C1GxsmI2.js +0 -1
  402. package/core/built/admin/assets/filter-sources-D5n5bFA2.js +0 -1
  403. package/core/built/admin/assets/filters-DJEzkMUK.js +0 -1
  404. package/core/built/admin/assets/filters-MZXvdH5D.js +0 -1
  405. package/core/built/admin/assets/first-promoter-modal-CGTGLCr5.js +0 -1
  406. package/core/built/admin/assets/gift-link-modal-B6v0tnRN.js +0 -1
  407. package/core/built/admin/assets/growth-BGAJD1rs.js +0 -3
  408. package/core/built/admin/assets/growth-D6mhcx3q.js +0 -1
  409. package/core/built/admin/assets/history-modal-iKwUY3XR.js +0 -1
  410. package/core/built/admin/assets/index-DjQe-e5s.js +0 -4
  411. package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
  412. package/core/built/admin/assets/index.es-VihPwfeH.js +0 -1
  413. package/core/built/admin/assets/input--W-rCTrX.js +0 -1
  414. package/core/built/admin/assets/invite-user-modal-MdImLCaJ.js +0 -1
  415. package/core/built/admin/assets/koenig-loader-DYZpm6El.js +0 -2
  416. package/core/built/admin/assets/label-picker-cB51xl1r.js +0 -1
  417. package/core/built/admin/assets/layout-c_B_1hax.js +0 -1
  418. package/core/built/admin/assets/loading-indicator-BpFWTVgh.js +0 -1
  419. package/core/built/admin/assets/member-custom-fields-qs0dIkxM.js +0 -1
  420. package/core/built/admin/assets/member-detail-B6uec2a6.js +0 -1
  421. package/core/built/admin/assets/members-BQF3CqhI.js +0 -2
  422. package/core/built/admin/assets/moderation-DY4wF1Q3.js +0 -1
  423. package/core/built/admin/assets/navigation-modal-DX-gNF3X.js +0 -1
  424. package/core/built/admin/assets/newsletter-CyQA7m3m.js +0 -1
  425. package/core/built/admin/assets/newsletter-detail-modal-BDrptuxn.js +0 -1
  426. package/core/built/admin/assets/newsletters-DXuNmC42.js +0 -1
  427. package/core/built/admin/assets/note-Cgo2LCJ6.js +0 -1
  428. package/core/built/admin/assets/notifications-BC50AMku.js +0 -1
  429. package/core/built/admin/assets/offers-container-modal-DWycIMzT.js +0 -1
  430. package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
  431. package/core/built/admin/assets/overview-CVbFtn-k.js +0 -1
  432. package/core/built/admin/assets/overview-YKj7SZaK.js +0 -1
  433. package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
  434. package/core/built/admin/assets/popover-CCy0h5rq.js +0 -1
  435. package/core/built/admin/assets/portal-frame-dc4XKr0e.js +0 -1
  436. package/core/built/admin/assets/portal-modal-BvvdF_B9.js +0 -1
  437. package/core/built/admin/assets/post-analytics-DX470WRG.js +0 -1
  438. package/core/built/admin/assets/post-analytics-header-CXpJmdDv.js +0 -1
  439. package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
  440. package/core/built/admin/assets/preferences-DO0UUWFp.js +0 -5
  441. package/core/built/admin/assets/profile-CxT-0l4d.js +0 -1
  442. package/core/built/admin/assets/radio-group-Bgz60i81.js +0 -1
  443. package/core/built/admin/assets/select-DuDUFdPq.js +0 -1
  444. package/core/built/admin/assets/settings-BjCii7BM.js +0 -1
  445. package/core/built/admin/assets/settings-b8kNzZSQ.js +0 -4
  446. package/core/built/admin/assets/share-modal-BV70mr9k.js +0 -1
  447. package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
  448. package/core/built/admin/assets/slack-modal-Be2_KK-z.js +0 -1
  449. package/core/built/admin/assets/stats-C4reGh9O.js +0 -1
  450. package/core/built/admin/assets/stats-view-DP9pQ62k.js +0 -1
  451. package/core/built/admin/assets/stripe-connect-modal-Z-UT_BGc.js +0 -1
  452. package/core/built/admin/assets/tag-detail-Dc0nTOtU.js +0 -2
  453. package/core/built/admin/assets/tags-BLaXBwnb.js +0 -1
  454. package/core/built/admin/assets/testimonials-modal-sFwRnNLh.js +0 -1
  455. package/core/built/admin/assets/tier-detail-modal-BCFpWwUS.js +0 -1
  456. package/core/built/admin/assets/use-filter-params-CAvfDvf1.js +0 -1
  457. package/core/built/admin/assets/use-growth-stats-D6mZXGhK.js +0 -1
  458. package/core/built/admin/assets/use-post-referrers-DbY-mzci.js +0 -1
  459. package/core/built/admin/assets/use-reply-chain-data-BeQwz8oF.js +0 -1
  460. package/core/built/admin/assets/use-settings-navigation-BbrSUVcf.js +0 -1
  461. package/core/built/admin/assets/use-tinybird-query-B1IMyAcv.js +0 -39
  462. package/core/built/admin/assets/use-tinybird-token-Bow0Zwn8.js +0 -1
  463. package/core/built/admin/assets/user-detail-modal-yipSoQfv.js +0 -1
  464. package/core/built/admin/assets/users-5msE1WMs.js +0 -1
  465. package/core/built/admin/assets/web-CKcXAu86.js +0 -1
  466. package/core/built/admin/assets/web-DR4TqM3E.js +0 -2
  467. package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
  468. package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
  469. package/core/server/services/stripe/services/checkout/allowed-countries.js +0 -267
  470. package/core/server/services/stripe/services/checkout/field-ports.js +0 -34
  471. package/core/server/services/tier-checkout-config/destinations.js +0 -17
  472. package/core/server/services/update-check/run-update-check.js +0 -63
@@ -1,4 +1,5 @@
1
1
  const logging = require('@tryghost/logging');
2
+ const ProcessWebmentionJob = require('./process-webmention-job').default;
2
3
 
3
4
  /**
4
5
  * @typedef {import('./mentions-api')} MentionsAPI
@@ -22,11 +23,6 @@ const logging = require('@tryghost/logging');
22
23
  * @prop {Resource} resource
23
24
  */
24
25
 
25
- /**
26
- * @typedef {object} IJobService
27
- * @prop {(name: string, fn: Function) => void} addJob
28
- */
29
-
30
26
  /**
31
27
  * @typedef {object} IMentionResourceService
32
28
  * @prop {(id: import('bson-objectid').default) => Promise<MentionResource>} getByID
@@ -36,8 +32,8 @@ module.exports = class MentionController {
36
32
  /** @type {import('./mentions-api')} */
37
33
  #api;
38
34
 
39
- /** @type {IJobService} */
40
- #jobService;
35
+ /** @type {import('../jobs-service/jobs-service').JobsService} */
36
+ #jobsService;
41
37
 
42
38
  /** @type {IMentionResourceService} */
43
39
  #mentionResourceService;
@@ -45,12 +41,12 @@ module.exports = class MentionController {
45
41
  /**
46
42
  * @param {object} deps
47
43
  * @param {import('./mentions-api')} deps.api
48
- * @param {IJobService} deps.jobService
44
+ * @param {import('../jobs-service/jobs-service').JobsService} deps.jobsService
49
45
  * @param {IMentionResourceService} deps.mentionResourceService
50
46
  */
51
47
  async init(deps) {
52
48
  this.#api = deps.api;
53
- this.#jobService = deps.jobService;
49
+ this.#jobsService = deps.jobsService;
54
50
  this.#mentionResourceService = deps.mentionResourceService;
55
51
  }
56
52
 
@@ -127,17 +123,23 @@ module.exports = class MentionController {
127
123
  */
128
124
  async receive(frame) {
129
125
  logging.info('[Webmention] ' + JSON.stringify(frame.data));
130
- this.#jobService.addJob('processWebmention', async () => {
131
- const { source, target, ...payload } = frame.data;
132
- try {
133
- await this.#api.processWebmention({
134
- source: new URL(source),
135
- target: new URL(target),
136
- payload,
137
- });
138
- } catch (err) {
139
- logging.error(err, '[Webmention] Failed processing webmention');
140
- }
141
- });
126
+ const { source, target, ...payload } = frame.data;
127
+ await this.#jobsService.dispatch(new ProcessWebmentionJob({ source, target, payload }));
128
+ }
129
+
130
+ /**
131
+ * @param {import('./process-webmention-job').default} job
132
+ * @returns {Promise<void>}
133
+ */
134
+ async processWebmention({ source, target, payload }) {
135
+ try {
136
+ await this.#api.processWebmention({
137
+ source: new URL(source),
138
+ target: new URL(target),
139
+ payload,
140
+ });
141
+ } catch (err) {
142
+ logging.error(err, '[Webmention] Failed processing webmention');
143
+ }
142
144
  }
143
145
  };
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const job_1 = require("../jobs-service/job");
4
+ class ProcessWebmentionJob extends job_1.Job {
5
+ static type = 'process-webmention';
6
+ source;
7
+ target;
8
+ payload;
9
+ constructor({ source, target, payload, }) {
10
+ super();
11
+ this.source = source;
12
+ this.target = target;
13
+ this.payload = payload;
14
+ }
15
+ }
16
+ exports.default = ProcessWebmentionJob;
@@ -15,7 +15,7 @@ const urlService = require('../url');
15
15
  const settingsCache = require('../../../shared/settings-cache');
16
16
  const DomainEvents = require('@tryghost/domain-events');
17
17
  const logging = require('@tryghost/logging');
18
- const jobsService = require('../mentions-jobs');
18
+ const mentionsJobService = require('../mentions-jobs');
19
19
 
20
20
  // Serializes a post model to the data the URL service needs, loading the
21
21
  // relations it reads for filtered collections (event-emitted models don't
@@ -45,7 +45,7 @@ function makeLoggingJobService() {
45
45
  return {
46
46
  async addJob(name, fn) {
47
47
  logging.info(`[Background Job] ${name} queued`);
48
- jobsService.addJob({
48
+ mentionsJobService.addJob({
49
49
  name,
50
50
  job: async () => {
51
51
  const startedAt = Date.now();
@@ -75,7 +75,11 @@ module.exports = {
75
75
  /** @type {import('./mention-sending-service')} */
76
76
  sendingService: null,
77
77
  didInit: false,
78
- async init() {
78
+ /**
79
+ * @param {object} deps
80
+ * @param {import('../jobs-service/jobs-service').JobsService} deps.jobsService
81
+ */
82
+ async init({ jobsService }) {
79
83
  if (this.didInit) {
80
84
  return;
81
85
  }
@@ -110,7 +114,7 @@ module.exports = {
110
114
 
111
115
  this.controller.init({
112
116
  api,
113
- jobService: makeLoggingJobService(),
117
+ jobsService,
114
118
  mentionResourceService: {
115
119
  async getByID(id) {
116
120
  if (!id) {
@@ -14,7 +14,7 @@ const tpl_1 = __importDefault(require("@tryghost/tpl"));
14
14
  const messages = {
15
15
  validationError: 'The following definition "{at}" is invalid: {reason}',
16
16
  };
17
- const DOCS_URL = 'https://ghost.org/docs/themes/routing/';
17
+ const DOCS_URL = 'https://docs.ghost.org/themes/routing/';
18
18
  const MAX_SHOWN_LENGTH = 40;
19
19
  /**
20
20
  * Stable, machine-readable codes describing the class of a routes.yaml failure.
@@ -9,7 +9,7 @@ const messages = {
9
9
  },
10
10
  invalidYamlFormat: {
11
11
  message: 'YAML input cannot be a plain string. Check the format of your YAML file.',
12
- help: 'https://ghost.org/docs/themes/routing/',
12
+ help: 'https://docs.ghost.org/themes/routing/',
13
13
  },
14
14
  };
15
15
 
@@ -200,14 +200,7 @@ module.exports = {
200
200
  type: 'boolean',
201
201
  group: 'members',
202
202
  fn: settingsHelpers.allowSelfSignup.bind(settingsHelpers),
203
- dependents: [
204
- 'members_signup_access',
205
- 'portal_plans',
206
- 'stripe_secret_key',
207
- 'stripe_publishable_key',
208
- 'stripe_connect_secret_key',
209
- 'stripe_connect_publishable_key',
210
- ],
203
+ dependents: ['members_signup_access'],
211
204
  }),
212
205
  );
213
206
  fields.push(
@@ -1,7 +1,7 @@
1
1
  const net = require('net');
2
2
  const tpl = require('@tryghost/tpl');
3
3
  const errors = require('@tryghost/errors');
4
- const EmailAddressParser = require('../email-address/email-address-parser');
4
+ const emailAddressParser = require('../email-address/email-address-parser');
5
5
  const logging = require('@tryghost/logging');
6
6
  const crypto = require('crypto');
7
7
  const debug = require('@tryghost/debug')('services:settings-helpers');
@@ -130,11 +130,9 @@ class SettingsHelpers {
130
130
  if (!supportAddress) {
131
131
  // In the new flow, we make a difference between an empty setting (= use default) and a 'noreply' setting (=use noreply @ domain)
132
132
  // Also keep the name of the default email!
133
- return EmailAddressParser.stringify(this.getDefaultEmail());
133
+ return emailAddressParser.stringify(this.getDefaultEmail());
134
134
  }
135
135
 
136
- supportAddress = supportAddress || 'noreply';
137
-
138
136
  // Any fromAddress without domain uses site domain, like default setting `noreply`
139
137
  if (supportAddress.indexOf('@') < 0) {
140
138
  return `${supportAddress}@${this.getDefaultEmailDomain()}`;
@@ -143,7 +141,7 @@ class SettingsHelpers {
143
141
  }
144
142
 
145
143
  /**
146
- * @deprecated Use getDefaultEmail().address (without name) or EmailAddressParser.stringify(this.getDefaultEmail()) (with name) instead
144
+ * @deprecated Use getDefaultEmail().address (without name) or emailAddressParser.stringify(this.getDefaultEmail()) (with name) instead
147
145
  */
148
146
  getNoReplyAddress() {
149
147
  return this.getDefaultEmailAddress();
@@ -157,7 +155,7 @@ class SettingsHelpers {
157
155
  // parse the email here and remove the sender name
158
156
  // E.g. when set to "bar" <from@default.com>
159
157
  const configAddress = this.config.get('mail:from');
160
- const parsed = EmailAddressParser.parse(configAddress);
158
+ const parsed = emailAddressParser.parse(configAddress);
161
159
  if (parsed) {
162
160
  return parsed;
163
161
  }
@@ -173,7 +173,7 @@ class SlackPingService {
173
173
  this.logging.error(new errors_1.default.InternalServerError({
174
174
  err: err,
175
175
  context: (0, tpl_1.default)(constants_1.messages.requestFailedError, { service: 'slack' }),
176
- help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://ghost.org/docs/' }),
176
+ help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://docs.ghost.org/' }),
177
177
  }));
178
178
  });
179
179
  }
@@ -2,7 +2,7 @@ const { promises: fs, readFileSync } = require('fs');
2
2
  const path = require('path');
3
3
  const moment = require('moment');
4
4
  const { globSync } = require('glob');
5
- const EmailAddressParser = require('../email-address/email-address-parser');
5
+ const emailAddressParser = require('../email-address/email-address-parser');
6
6
 
7
7
  class StaffServiceEmails {
8
8
  constructor({
@@ -593,7 +593,7 @@ class StaffServiceEmails {
593
593
  }
594
594
 
595
595
  get fromEmailAddress() {
596
- return EmailAddressParser.stringify(this.settingsHelpers.getDefaultEmail());
596
+ return emailAddressParser.stringify(this.settingsHelpers.getDefaultEmail());
597
597
  }
598
598
 
599
599
  extractInitials(name = '') {
@@ -4,7 +4,7 @@ const labs = require('../../../shared/labs');
4
4
 
5
5
  const messages = {
6
6
  remoteWebhooksInDevelopment:
7
- 'Cannot use remote webhooks in development. See https://ghost.org/docs/webhooks/#stripe-webhooks for developing with Stripe.',
7
+ 'Cannot use remote webhooks in development. See https://docs.ghost.org/webhooks/#stripe-webhooks for developing with Stripe.',
8
8
  };
9
9
 
10
10
  // @TODO Refactor to a class w/ constructor
@@ -62,16 +62,19 @@ module.exports = {
62
62
  }
63
63
 
64
64
  const env = config.get('env');
65
- let webhookSecret = process.env.WEBHOOK_SECRET;
65
+ const remoteWebhooks = env !== 'production' && config.get('stripeRemoteWebhooks') === true;
66
+ let webhookSecret = remoteWebhooks ? undefined : process.env.WEBHOOK_SECRET;
66
67
 
67
- if (env !== 'production') {
68
- if (!webhookSecret) {
69
- webhookSecret = 'DEFAULT_WEBHOOK_SECRET';
70
- logging.warn(tpl(messages.remoteWebhooksInDevelopment));
71
- }
68
+ if (env !== 'production' && !remoteWebhooks && !webhookSecret) {
69
+ webhookSecret = 'DEFAULT_WEBHOOK_SECRET';
70
+ logging.warn(tpl(messages.remoteWebhooksInDevelopment));
72
71
  }
73
72
 
74
- const webhookHandlerUrl = new URL('members/webhooks/stripe/', urlUtils.getSiteUrl());
73
+ // Development can tunnel the webhook URL alone while the site stays on localhost.
74
+ const webhookHandlerUrl = new URL(
75
+ config.get('stripeWebhookUrl') || 'members/webhooks/stripe/',
76
+ urlUtils.getSiteUrl(),
77
+ );
75
78
  const webhookCustomerIgnoreList = parseIgnoreCustomerList(
76
79
  config.get('stripeWebhookCustomerIgnoreList'),
77
80
  );
@@ -88,6 +91,9 @@ module.exports = {
88
91
  },
89
92
  webhookSecret: webhookSecret,
90
93
  webhookHandlerUrl: webhookHandlerUrl.href,
94
+ // A development registration points at a tunnel that closes with the process,
95
+ // so it is removed on shutdown rather than kept for the next boot.
96
+ ephemeralWebhook: remoteWebhooks,
91
97
  webhookCustomerIgnoreList,
92
98
  siteUrl,
93
99
  };
@@ -14,6 +14,12 @@ const giftService = require('../gifts');
14
14
  const staffService = require('../staff');
15
15
  const labs = require('../../../shared/labs');
16
16
  const settingsCache = require('../../../shared/settings-cache');
17
+ const tpl = require('@tryghost/tpl');
18
+
19
+ const messages = {
20
+ remoteWebhooksWithoutStripe:
21
+ 'stripeRemoteWebhooks is set but Stripe is not connected, so no webhook endpoint was registered. Connect Stripe in Ghost Admin under Settings, then restart.',
22
+ };
17
23
 
18
24
  async function configureApi() {
19
25
  const cfg = getConfig({ settingsHelpers, config, urlUtils });
@@ -84,7 +90,10 @@ function stripeSettingsChanged(model) {
84
90
 
85
91
  module.exports.init = async function init() {
86
92
  try {
87
- await configureApi();
93
+ const configured = await configureApi();
94
+ if (!configured && config.get('stripeRemoteWebhooks') === true) {
95
+ logging.warn(tpl(messages.remoteWebhooksWithoutStripe));
96
+ }
88
97
  } catch (err) {
89
98
  logging.error(err);
90
99
  }
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.collectedByPort = exports.CompletedSession = void 0;
4
4
  const zod_1 = require("zod");
5
- const field_ports_1 = require("./field-ports");
5
+ const checkout_1 = require("@tryghost/checkout");
6
6
  /**
7
7
  * What Ghost reads off a completed session.
8
8
  *
@@ -63,6 +63,6 @@ exports.collectedByPort = exports.CompletedSession.transform((session) => {
63
63
  const answers = (session.custom_fields ?? [])
64
64
  .filter((field) => Boolean(field?.key && field.text?.value))
65
65
  .map((field) => ({ port: field.key, value: field.text.value }));
66
- const ports = field_ports_1.STRIPE_PORTS.map((port) => ({ port, value: PORT_VALUES[port](session) })).filter((entry) => entry.value !== undefined);
66
+ const ports = checkout_1.STRIPE_PORTS.map((port) => ({ port, value: PORT_VALUES[port](session) })).filter((entry) => entry.value !== undefined);
67
67
  return [...answers, ...ports];
68
68
  });
@@ -5,13 +5,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.stripeCheckoutCollectionOptions = stripeCheckoutCollectionOptions;
7
7
  const logging_1 = __importDefault(require("@tryghost/logging"));
8
- const field_ports_1 = require("./field-ports");
8
+ const checkout_1 = require("@tryghost/checkout");
9
9
  /** Keyed on the eligible types, so this and the configure-time rule cannot drift apart. */
10
10
  const QUESTION_TYPES = {
11
11
  short_text: 'text',
12
12
  };
13
13
  function askable(question) {
14
- if (!(0, field_ports_1.isCheckoutEligible)(question.type)) {
14
+ if (!(0, checkout_1.isCheckoutEligible)(question.type)) {
15
15
  logging_1.default.warn({
16
16
  event: { name: 'stripe.checkout.question_skipped' },
17
17
  customFieldKey: question.key,
@@ -20,7 +20,7 @@ function askable(question) {
20
20
  }, 'Skipping a Stripe checkout question');
21
21
  return false;
22
22
  }
23
- if (question.prompt.length > field_ports_1.MAX_CHECKOUT_LABEL_LENGTH) {
23
+ if (question.prompt.length > checkout_1.MAX_CHECKOUT_LABEL_LENGTH) {
24
24
  logging_1.default.warn({
25
25
  event: { name: 'stripe.checkout.question_skipped' },
26
26
  customFieldKey: question.key,
@@ -43,7 +43,7 @@ function stripeCheckoutCollectionOptions(checkout) {
43
43
  return options;
44
44
  }
45
45
  const eligible = checkout.customFields.filter(askable);
46
- const questions = eligible.slice(0, field_ports_1.MAX_CHECKOUT_CUSTOM_FIELDS);
46
+ const questions = eligible.slice(0, checkout_1.MAX_CHECKOUT_CUSTOM_FIELDS);
47
47
  if (questions.length < eligible.length) {
48
48
  logging_1.default.warn({
49
49
  event: { name: 'stripe.checkout.questions_trimmed' },
@@ -64,15 +64,20 @@ function stripeCheckoutCollectionOptions(checkout) {
64
64
  }));
65
65
  }
66
66
  if (checkout.shipping) {
67
- // The country list is what makes this reach Stripe at all. An empty
68
- // `shipping_address_collection` form-encodes to nothing, so a request built that
69
- // way carries no parameter and Stripe accepts it precisely because it was never
70
- // asked to collect anything which reads as success and collects no addresses.
67
+ // Ghost stores "everywhere" as no list, because the set of countries moves and a
68
+ // stored copy of it would quietly become a restriction. Stripe has no such sentinel:
69
+ // `allowed_countries` is the only key `shipping_address_collection` has, so a request
70
+ // that omits it carries no parameter at all, and Stripe accepts it precisely because
71
+ // it was never asked to collect anything — a session that succeeds and collects no
72
+ // address. So everywhere is expanded to every country here, at the one point that
73
+ // builds the request.
71
74
  //
72
- // Defended again here rather than trusted from the settings screen: this is the
73
- // checkout path, and a malformed configuration must cost the collection rather than
74
- // throw inside a session build.
75
- if (checkout.shipping.allowedCountries.length === 0) {
75
+ // An empty list is neither everywhere nor a real restriction, and would encode to the
76
+ // same absent parameter. Defended here rather than trusted from the settings screen:
77
+ // this is the checkout path, and a malformed configuration must cost the collection
78
+ // rather than throw inside a session build.
79
+ const allowedCountries = checkout.shipping.allowedCountries ?? [...checkout_1.STRIPE_ALLOWED_COUNTRIES];
80
+ if (allowedCountries.length === 0) {
76
81
  logging_1.default.warn({
77
82
  event: { name: 'stripe.checkout.collection_skipped' },
78
83
  port: 'shipping_address',
@@ -80,9 +85,7 @@ function stripeCheckoutCollectionOptions(checkout) {
80
85
  }, 'Skipping a Stripe checkout collection');
81
86
  }
82
87
  else {
83
- options.shipping_address_collection = {
84
- allowed_countries: checkout.shipping.allowedCountries,
85
- };
88
+ options.shipping_address_collection = { allowed_countries: allowedCountries };
86
89
  }
87
90
  }
88
91
  // Unioned with whatever automatic tax asks for. Both want the same thing, so a site
@@ -1,7 +1,10 @@
1
1
  const _ = require('lodash');
2
2
  const errors = require('@tryghost/errors');
3
3
  const logging = require('@tryghost/logging');
4
- const { canWelcomeEmailReplaceSignupPaidEmail } = require('../../../lib/member-signup-contexts');
4
+ const {
5
+ SIGNUP_CONTEXTS,
6
+ canWelcomeEmailReplaceSignupPaidEmail,
7
+ } = require('../../../lib/member-signup-contexts');
5
8
  const { collectedByPort } = require('../checkout/completed-session');
6
9
  /** @typedef {import('../../../lib/member-signup-contexts').SignupContext} SignupContext */
7
10
 
@@ -335,6 +338,7 @@ module.exports = class CheckoutSessionEventService {
335
338
  email: customer.email,
336
339
  });
337
340
 
341
+ const memberPreexisted = Boolean(member);
338
342
  const checkoutType = _.get(session, 'metadata.checkoutType');
339
343
 
340
344
  if (!member) {
@@ -426,7 +430,7 @@ module.exports = class CheckoutSessionEventService {
426
430
  // After the subscription work, and deliberately not part of it: a value the member
427
431
  // gave us for free must never be able to fail the webhook. A throw here would make
428
432
  // Stripe retry the event and risk doing the payment work twice.
429
- await this.writeCollectedFields(member.id, session);
433
+ await this.writeCollectedFields(member.id, session, { memberPreexisted });
430
434
 
431
435
  if (checkoutType !== 'upgrade') {
432
436
  const ghostSignupContext = /** @type {SignupContext | undefined} */ (
@@ -457,18 +461,35 @@ module.exports = class CheckoutSessionEventService {
457
461
  *
458
462
  * @param {string} memberId
459
463
  * @param {import('stripe').Stripe.Checkout.Session} session
464
+ * @param {object} options
465
+ * @param {boolean} options.memberPreexisted Whether the member's record existed before this event resolved it
460
466
  */
461
- async writeCollectedFields(memberId, session) {
467
+ async writeCollectedFields(memberId, session, { memberPreexisted }) {
462
468
  // Stamped at create time. A session predating this feature carries none. Read
463
469
  // outside the try so a failure below can name the tier whose answers were lost.
464
470
  const tierId = session.metadata?.ghostTierId;
465
471
 
466
472
  try {
467
- if (!this.deps.labsService.isSet('membersCustomFields')) {
473
+ if (!tierId) {
468
474
  return;
469
475
  }
470
476
 
471
- if (!tierId) {
477
+ // A checkout can be started with nothing but an email address, and typing an
478
+ // email is not proof of owning it. Values may land on the member this event just
479
+ // created — that record holds nothing the buyer didn't supply — but a record
480
+ // that existed before the checkout belongs to whoever verified that email, so it
481
+ // is only written when the session was created by a signed-in member.
482
+ const wasAuthenticated =
483
+ session.metadata?.ghostSignupContext === SIGNUP_CONTEXTS.ALREADY_AUTHENTICATED;
484
+ if (memberPreexisted && !wasAuthenticated) {
485
+ logging.warn(
486
+ {
487
+ event: { name: 'stripe_checkout.collected_fields.write_skipped' },
488
+ memberId,
489
+ tierId,
490
+ },
491
+ 'Skipped storing the fields an unverified checkout collected for an existing member',
492
+ );
472
493
  return;
473
494
  }
474
495
 
@@ -62,6 +62,8 @@ const MANAGED_PAYMENTS_DISABLED = { enabled: false };
62
62
  */
63
63
 
64
64
  module.exports = class StripeAPI {
65
+ static API_VERSION = STRIPE_API_VERSION;
66
+
65
67
  /**
66
68
  * StripeAPI
67
69
  * @param {object} deps
@@ -25,6 +25,7 @@ const customFields = require('../members-custom-fields');
25
25
  * @prop {boolean} testEnv Whether this is a test environment
26
26
  * @prop {string} webhookSecret The Stripe webhook secret
27
27
  * @prop {string} webhookHandlerUrl The URL to handle Stripe webhooks
28
+ * @prop {boolean} [ephemeralWebhook] Whether the webhook endpoint is deleted on shutdown
28
29
  * @prop {string[]} webhookCustomerIgnoreList List of customer IDs for customer.subscription.updated webhook bypass
29
30
  * @prop {string} siteUrl The site URL for billing portal return URL
30
31
  */
@@ -134,7 +135,6 @@ module.exports = class StripeService {
134
135
  memberWelcomeEmailService.init();
135
136
  return memberWelcomeEmailService.api.isMemberWelcomeEmailActive('paid');
136
137
  },
137
- labsService: labs,
138
138
  // A getter because the custom field services are built during boot: reading the
139
139
  // binding at construction would capture the empty value it had beforehand.
140
140
  get customFieldBindings() {
@@ -162,6 +162,8 @@ module.exports = class StripeService {
162
162
  this.migrations = migrations;
163
163
  this.webhookController = webhookController;
164
164
  this.billingPortalManager = billingPortalManager;
165
+ /** @private */
166
+ this.ephemeralWebhook = false;
165
167
  }
166
168
 
167
169
  async connect() {
@@ -213,23 +215,31 @@ module.exports = class StripeService {
213
215
  webhookSecret: config.webhookSecret,
214
216
  webhookHandlerUrl: config.webhookHandlerUrl,
215
217
  });
218
+ this.ephemeralWebhook = config.ephemeralWebhook === true;
216
219
 
217
220
  this.billingPortalManager.configure({
218
221
  siteUrl: config.siteUrl,
219
222
  });
220
223
 
221
- // webhookManager.start() already self-guards: configure() above puts it in
222
- // 'local' mode whenever a webhookSecret is set, which is always true outside
223
- // production (config.js defaults it to DEFAULT_WEBHOOK_SECRET), so start()
224
- // returns immediately without touching Stripe. Only billingPortalManager
225
- // needs an explicit test-env skip in the test env there is no real Stripe
226
- // to register against, and the mock returns 500 for billing_portal/
227
- // configurations, so this network-registration call only error-logs on
228
- // every boot. Tests never need a registered portal configuration. Skip it
229
- // under test; prod and dev register exactly as before.
224
+ // webhookManager.start() registers a webhook URL with Stripe only when no webhook
225
+ // secret was supplied. Outside production config.js supplies a placeholder secret
226
+ // unless stripeRemoteWebhooks is set, so start() normally returns without touching
227
+ // Stripe. billingPortalManager has no such guard: in the test environment the mock
228
+ // Stripe answers its registration call with a 500 on every boot, and tests never
229
+ // need a registered portal, so skip it under test only.
230
230
  await this.webhookManager.start();
231
231
  if (!config.testEnv) {
232
232
  await this.billingPortalManager.start();
233
233
  }
234
234
  }
235
+
236
+ /**
237
+ * Removes the webhook registration from Stripe, but only when it was marked ephemeral.
238
+ * A production registration is kept and reused on the next boot.
239
+ */
240
+ async shutdown() {
241
+ if (this.ephemeralWebhook) {
242
+ await this.webhookManager.stop();
243
+ }
244
+ }
235
245
  };
@@ -1,4 +1,5 @@
1
1
  const logging = require('@tryghost/logging');
2
+ const StripeAPI = require('./stripe-api');
2
3
 
3
4
  module.exports = class WebhookController {
4
5
  /**
@@ -89,6 +90,15 @@ module.exports = class WebhookController {
89
90
  return res.end();
90
91
  }
91
92
 
93
+ // Stripe shapes each event for the API version of the URL it was sent to. A different
94
+ // version means this event did not come through the URL Ghost registered, and fields
95
+ // may not be where Ghost reads them.
96
+ if (event.api_version !== StripeAPI.API_VERSION) {
97
+ logging.error(
98
+ `Webhook ${event.type} was rendered at Stripe API version ${event.api_version}, Ghost expects ${StripeAPI.API_VERSION}`,
99
+ );
100
+ }
101
+
92
102
  const customerId = this.getEventCustomerId(event);
93
103
  if (this.shouldIgnoreEvent(event, customerId)) {
94
104
  logging.info(
@@ -8,19 +8,23 @@ const schema_1 = require("./schema");
8
8
  const models_1 = require("./models");
9
9
  const SEPARATOR = ',';
10
10
  exports.optionsCodec = zod_1.z.codec(schema_1.DbCheckoutOptions, models_1.CheckoutOptions, {
11
+ // An absent list is everywhere, so the column is null rather than a copy of every
12
+ // country. An empty list is neither, and stays representable on purpose: nothing writes
13
+ // one, and the session builder refuses to collect against it rather than asking the
14
+ // processor for an address form it would never render.
11
15
  decode: (columns) => ({
12
- shippingAllowedCountries: splitList(columns.shipping_allowed_countries),
16
+ shippingAllowedCountries: columns.shipping_allowed_countries === null
17
+ ? null
18
+ : splitList(columns.shipping_allowed_countries),
13
19
  taxNumber: columns.tax_number_collect,
14
20
  }),
15
21
  encode: (options) => ({
16
- shipping_allowed_countries: options.shippingAllowedCountries.length
17
- ? joinList(options.shippingAllowedCountries)
18
- : null,
22
+ shipping_allowed_countries: options.shippingAllowedCountries === null ? null : joinList(options.shippingAllowedCountries),
19
23
  tax_number_collect: options.taxNumber,
20
24
  }),
21
25
  });
22
26
  function splitList(stored) {
23
- return stored ? stored.split(SEPARATOR).filter(Boolean) : [];
27
+ return stored.split(SEPARATOR).filter(Boolean);
24
28
  }
25
29
  function joinList(values) {
26
30
  return [...new Set(values)].join(SEPARATOR);
@@ -13,8 +13,14 @@ exports.CheckoutQuestion = zod_1.z.object({
13
13
  * under one parameter, but a publisher keeps a name and an address in different fields.
14
14
  */
15
15
  exports.ShippingCollection = zod_1.z.object({
16
- /** ISO 3166-1 alpha-2. A processor will not render an address form without them. */
17
- allowedCountries: zod_1.z.array(zod_1.z.string()),
16
+ /**
17
+ * ISO 3166-1 alpha-2, or null for everywhere the processor ships.
18
+ *
19
+ * Null rather than a stored enumeration of every country, because that list moves: the
20
+ * day the processor adds one, a saved "everywhere" would silently be a restriction that
21
+ * excludes it, and nothing would say so.
22
+ */
23
+ allowedCountries: zod_1.z.array(zod_1.z.string()).nullable(),
18
24
  nameCustomFieldKey: zod_1.z.string(),
19
25
  addressCustomFieldKey: zod_1.z.string(),
20
26
  });
@@ -42,7 +48,7 @@ const emptyCheckoutConfig = (tierId) => ({
42
48
  });
43
49
  exports.emptyCheckoutConfig = emptyCheckoutConfig;
44
50
  exports.CheckoutOptions = zod_1.z.object({
45
- shippingAllowedCountries: zod_1.z.array(zod_1.z.string()),
51
+ shippingAllowedCountries: zod_1.z.array(zod_1.z.string()).nullable(),
46
52
  taxNumber: zod_1.z.boolean(),
47
53
  });
48
54
  exports.ResolvedQuestion = exports.CheckoutQuestion.extend({