ghost 6.58.0 → 6.59.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 (453) hide show
  1. package/components/tryghost-adapter-base-scheduling-0.2.2.tgz +0 -0
  2. package/components/tryghost-adapter-base-sso-0.1.2.tgz +0 -0
  3. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  4. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  5. package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
  6. package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
  7. package/content/themes/casper/.github/workflows/test.yml +11 -1
  8. package/content/themes/casper/AGENTS.md +25 -0
  9. package/content/themes/casper/assets/built/screen.css +1 -1
  10. package/content/themes/casper/assets/css/screen.css +15 -1
  11. package/content/themes/casper/gulpfile.js +3 -0
  12. package/content/themes/casper/package.json +8 -8
  13. package/content/themes/source/.gitattributes +5 -0
  14. package/content/themes/source/.github/workflows/test.yml +39 -0
  15. package/content/themes/source/AGENTS.md +25 -0
  16. package/content/themes/source/README.md +33 -4
  17. package/content/themes/source/assets/built/screen.css +1 -1
  18. package/content/themes/source/assets/css/screen.css +15 -0
  19. package/content/themes/source/gulpfile.js +6 -3
  20. package/content/themes/source/package.json +13 -10
  21. package/content/themes/source/pnpm-workspace.yaml +3 -0
  22. package/core/boot.js +11 -4
  23. package/core/built/admin/assets/Combination-BCm9FL4o.js +41 -0
  24. package/core/built/admin/assets/about-BdSCpjXG.js +1 -0
  25. package/core/built/admin/assets/account-migration-BpKAqo8k.js +1 -0
  26. package/core/built/admin/assets/activitypub/{account-migration-BpDeIF3G.js → account-migration-DVnYS1XG.js} +8 -8
  27. package/core/built/admin/assets/activitypub/activitypub.js +2 -2
  28. package/core/built/admin/assets/activitypub/{bluesky-sharing-aPMtrS3L.js → bluesky-sharing-DLVeE9ii.js} +31 -31
  29. package/core/built/admin/assets/activitypub/{content-formatters-BORfuA9G.js → content-formatters-DCsVic-t.js} +2 -2
  30. package/core/built/admin/assets/activitypub/{dist-ByFmDSNP2.js → dist-ByFmDSNP.js} +1 -1
  31. package/core/built/admin/assets/activitypub/{domain-CPdiB27_.js → domain-rrvDLfnK.js} +8 -8
  32. package/core/built/admin/assets/activitypub/{edit-profile-BY2PawIe.js → edit-profile-VT-piVxq.js} +23 -23
  33. package/core/built/admin/assets/activitypub/{explore-Sp9bgAwq.js → explore-DZg3m48P.js} +14 -14
  34. package/core/built/admin/assets/activitypub/{feed-BjtF4ohL.js → feed-BJqQvDMI.js} +41 -41
  35. package/core/built/admin/assets/activitypub/{field-BDOYVTg6.js → field-BezS4-1J.js} +2 -2
  36. package/core/built/admin/assets/activitypub/inbox-Uf0GVrI_.js +1284 -0
  37. package/core/built/admin/assets/activitypub/{label-1jhN-qhD.js → label-CZ6if4zK.js} +2 -2
  38. package/core/built/admin/assets/activitypub/layout-DNuYT4Gu.js +1 -0
  39. package/core/built/admin/assets/activitypub/moderation-CP6mDVky.js +340 -0
  40. package/core/built/admin/assets/activitypub/{note-nr_m_5yb.js → note-BlFkye2g.js} +16 -16
  41. package/core/built/admin/assets/activitypub/{notifications-BdcyivbT.js → notifications-GGTrGEdu.js} +163 -126
  42. package/core/built/admin/assets/activitypub/{preferences-CNqy1x9C.js → preferences-CjZXrZqr.js} +1550 -1551
  43. package/core/built/admin/assets/activitypub/{profile-DlY4rhbO.js → profile-CcXYxydm.js} +248 -248
  44. package/core/built/admin/assets/activitypub/{routes-CEHdEZzS.js → routes-nHCKlZl-.js} +1971 -1747
  45. package/core/built/admin/assets/activitypub/settings-pDzybcb3.js +315 -0
  46. package/core/built/admin/assets/activitypub/{site-CtBUCPBz.js → site-BZF0F8LN.js} +101 -101
  47. package/core/built/admin/assets/activitypub/{step-1-D9jGWyAy.js → step-1-C-Ns1Tfg.js} +3 -3
  48. package/core/built/admin/assets/activitypub/{step-3-KpUqpGWi.js → step-3-rDMNGmLg.js} +8 -8
  49. package/core/built/admin/assets/activitypub/{tabs-DvlsxTCI.js → tabs-CDjh3_Jp.js} +198 -198
  50. package/core/built/admin/assets/activitypub/{topic-filter-CIN1E2jg.js → topic-filter-CmTc8hpN.js} +2 -2
  51. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-CATFd6YV.js → use-activity-pub-queries-DUDEdSdR.js} +286 -243
  52. package/core/built/admin/assets/activitypub/{use-reply-chain-data-DJ0vhA8V.js → use-reply-chain-data-TunGtmJl.js} +14 -14
  53. package/core/built/admin/assets/add-integration-modal-CXRQi1x0.js +1 -0
  54. package/core/built/admin/assets/add-newsletter-modal-t447KRYz.js +1 -0
  55. package/core/built/admin/assets/add-recommendation-modal-D882MdnR.js +1 -0
  56. package/core/built/admin/assets/{analytics-BC2oR8ay.js → analytics-Dj-WlzPf.js} +1 -1
  57. package/core/built/admin/assets/announcement-bar-modal-CwHKKw-a.js +1 -0
  58. package/core/built/admin/assets/api-keys-Boy5pLbD.js +1 -0
  59. package/core/built/admin/assets/audience-Cc40y7zQ.js +1 -0
  60. package/core/built/admin/assets/automations-DNLK5Udr.js +1 -0
  61. package/core/built/admin/assets/bluesky-sharing-Cm4aFaOl.js +1 -0
  62. package/core/built/admin/assets/breadcrumb-CcFr_ltt.js +1 -0
  63. package/core/built/admin/assets/button-BshWPHvn.js +1 -0
  64. package/core/built/admin/assets/chart-helpers-BsbzoWhK.js +1 -0
  65. package/core/built/admin/assets/{checkbox-LmClhqcS.js → checkbox-1G6KfK2q.js} +1 -1
  66. package/core/built/admin/assets/chunk-KS7C4IRE-DCsL4i4D.js +4 -0
  67. package/core/built/admin/assets/{chunk.408.1a258af360eb8d905508.js → chunk.301.5673a0caf7c49bb00212.js} +3 -3
  68. package/core/built/admin/assets/{chunk.524.4c693c3a00ac91df34fa.js → chunk.524.86db0d945468c852374b.js} +4 -4
  69. package/core/built/admin/assets/{chunk.582.20b600e329e58d12d7c2.js → chunk.582.c2f6216d3c4af303e236.js} +6 -6
  70. package/core/built/admin/assets/{code-editor-view-DqTOUnbM.js → code-editor-view-BVjtWyst.js} +1 -1
  71. package/core/built/admin/assets/{code-editor-view-bA0lfxUL.js → code-editor-view-y_zVfmCa.js} +1 -1
  72. package/core/built/admin/assets/color-picker-XEMPgNJE.js +3 -0
  73. package/core/built/admin/assets/{color-picker-field-Cv9GOJQZ.js → color-picker-field-BhplXcy5.js} +1 -1
  74. package/core/built/admin/assets/combobox-CRMJrvcQ.js +1 -0
  75. package/core/built/admin/assets/command-151T2eRx.js +1 -0
  76. package/core/built/admin/assets/comments-Bjbl9toF.js +1 -0
  77. package/core/built/admin/assets/confirmation-context-QmFxSjWy.js +1 -0
  78. package/core/built/admin/assets/{content-api-modal-BOFWRUkC.js → content-api-modal-CpeABXne.js} +1 -1
  79. package/core/built/admin/assets/{copy-field-8biQvNMD.js → copy-field-CglgRZyG.js} +1 -1
  80. package/core/built/admin/assets/custom-field-type-option-DSyJw4T4.js +1 -0
  81. package/core/built/admin/assets/custom-integration-modal-DWB9bRVp.js +1 -0
  82. package/core/built/admin/assets/date-range-select-kaKtab5O.js +1 -0
  83. package/core/built/admin/assets/design-and-theme-modal-86s2AaZ-.js +23 -0
  84. package/core/built/admin/assets/dirty-confirm-dialog-CTFdXXy7.js +1 -0
  85. package/core/built/admin/assets/disabled-sources-indicator-BFyCxUOx.js +1 -0
  86. package/core/built/admin/assets/dist-C1-Oy3Db.js +1 -0
  87. package/core/built/admin/assets/dist-CJJqYPep.js +1 -0
  88. package/core/built/admin/assets/dist-CNlMj7ML.js +1 -0
  89. package/core/built/admin/assets/dist-Kll2twSG.js +1 -0
  90. package/core/built/admin/assets/domain-BOoMvBG3.js +1 -0
  91. package/core/built/admin/assets/{dropzone-B21Entqz.js → dropzone-B6KWzsrb.js} +2 -2
  92. package/core/built/admin/assets/edit-profile-BagrYOrN.js +1 -0
  93. package/core/built/admin/assets/editor-AaJjqbpk.js +8 -0
  94. package/core/built/admin/assets/embed-signup-form-modal-B8L95KwR.js +8 -0
  95. package/core/built/admin/assets/explore-xbykZTlO.js +1 -0
  96. package/core/built/admin/assets/feed-BAHSipWv.js +1 -0
  97. package/core/built/admin/assets/{field-BQqLTgHM.js → field-kJYZ2T3C.js} +1 -1
  98. package/core/built/admin/assets/{filter-sources-FgqoUIL7.js → filter-sources-QeqFGNRB.js} +1 -1
  99. package/core/built/admin/assets/{filters-D0uIMD8n.js → filters-By5KQeV6.js} +1 -1
  100. package/core/built/admin/assets/filters-DtYpAkDd.js +1 -0
  101. package/core/built/admin/assets/first-promoter-modal-8A02oyjA.js +1 -0
  102. package/core/built/admin/assets/{ghost-ba408063a5922b458b4a8f216cf23251.js → ghost-f110822e67868c9fdf9a6c23754b2559.js} +9 -8
  103. package/core/built/admin/assets/gift-link-modal-DbYCyuhF.js +1 -0
  104. package/core/built/admin/assets/global-data-context-gAMDH9u1.js +1 -0
  105. package/core/built/admin/assets/growth-BSOxJGey.js +3 -0
  106. package/core/built/admin/assets/growth-BZTjURq5.js +1 -0
  107. package/core/built/admin/assets/history-modal-CCgWtlZE.js +1 -0
  108. package/core/built/admin/assets/html-field-BQC7XyLA.js +1 -0
  109. package/core/built/admin/assets/iframe-buffering-DnOlWTD4.js +1 -0
  110. package/core/built/admin/assets/{images-3cQgwfTD.js → images-D5UKr2SG.js} +1 -1
  111. package/core/built/admin/assets/{inbox-Dz_JblyJ.js → inbox-DvN15_YH.js} +45 -39
  112. package/core/built/admin/assets/index-BJz9Zlsc.js +67 -0
  113. package/core/built/admin/assets/index-Dg8cdR8E.css +1 -0
  114. package/core/built/admin/assets/{input-group-DpogNUIt.js → input-group-BPAxETpQ.js} +1 -1
  115. package/core/built/admin/assets/invite-user-modal-jcUaaNkW.js +1 -0
  116. package/core/built/admin/assets/{koenig-lexical-2KuqRwZI.js → koenig-lexical-CfXTYeli.js} +1 -1
  117. package/core/built/admin/assets/koenig-loader-DktFM3Uh.js +1 -0
  118. package/core/built/admin/assets/{kpi-card-Ck3tT2Wg.js → kpi-card-fUHZlzBX.js} +1 -1
  119. package/core/built/admin/assets/{kpi-card-DDIxptaS.js → kpi-card-o0urVtNL.js} +1 -1
  120. package/core/built/admin/assets/kpi-helpers-2FTF4a3-.js +1 -0
  121. package/core/built/admin/assets/kpi-tabs-B8-_k2dQ.js +1 -0
  122. package/core/built/admin/assets/{label-DodDsMzn.js → label-CiRS3i_f.js} +1 -1
  123. package/core/built/admin/assets/label-picker-ao7tuPaK.js +1 -0
  124. package/core/built/admin/assets/layout-DC6QGDaw.js +1 -0
  125. package/core/built/admin/assets/member-custom-fields-BW756-EV.js +1 -0
  126. package/core/built/admin/assets/member-detail-CGGgUTSl.js +1 -0
  127. package/core/built/admin/assets/members-ZcPthwG0.js +11 -0
  128. package/core/built/admin/assets/moderation-24bElWs3.js +1 -0
  129. package/core/built/admin/assets/multi-select-combobox-CZPrgz-Z.js +1 -0
  130. package/core/built/admin/assets/navigation-modal-BiTP4U_J.js +1 -0
  131. package/core/built/admin/assets/newsletter-B3Ihwizp.js +1 -0
  132. package/core/built/admin/assets/newsletter-detail-modal-CYsu4qhl.js +1 -0
  133. package/core/built/admin/assets/newsletter-emails-CDPR4-SP.js +1 -0
  134. package/core/built/admin/assets/newsletters-bJiYLJWl.js +1 -0
  135. package/core/built/admin/assets/note-7f6urVVA.js +1 -0
  136. package/core/built/admin/assets/notifications-rosQCyXH.js +1 -0
  137. package/core/built/admin/assets/offers-container-modal-J2j6NpDL.js +1 -0
  138. package/core/built/admin/assets/onboarding-route-DTjcThKl.js +1 -0
  139. package/core/built/admin/assets/overview-BxvWzGaf.js +1 -0
  140. package/core/built/admin/assets/overview-D6JG0hkZ.js +1 -0
  141. package/core/built/admin/assets/{page-header-VLPJfj_d.js → page-header-l7vXmLIw.js} +1 -1
  142. package/core/built/admin/assets/pintura-modal-BGHmudVB.js +1 -0
  143. package/core/built/admin/assets/portal-frame-DVc4VHX_.js +1 -0
  144. package/core/built/admin/assets/portal-modal-BCOcdiRi.js +1 -0
  145. package/core/built/admin/assets/{post-analytics-Gv81eN_g.js → post-analytics-CTSZMK6I.js} +1 -1
  146. package/core/built/admin/assets/post-analytics-header-Dt4RQGq0.js +1 -0
  147. package/core/built/admin/assets/{post-analytics-provider-O2YjZMhN.js → post-analytics-provider-C4ydiboO.js} +1 -1
  148. package/core/built/admin/assets/post-share-modal-DjH_a_1L.js +1 -0
  149. package/core/built/admin/assets/preferences-BLo6VJUS.js +5 -0
  150. package/core/built/admin/assets/preview-modal-BOgjgsJL.js +1 -0
  151. package/core/built/admin/assets/profile-DG6iCdRH.js +1 -0
  152. package/core/built/admin/assets/radio-group-ChHD4EQJ.js +1 -0
  153. package/core/built/admin/assets/router-provider-Bexg1t-V.js +1 -0
  154. package/core/built/admin/assets/select-ChxknEcT.js +1 -0
  155. package/core/built/admin/assets/settings-B0VDAhgV.js +1 -0
  156. package/core/built/admin/assets/settings-Dwo3CeAD.js +4 -0
  157. package/core/built/admin/assets/settings-breadcrumbs-sLDNedBW.js +1 -0
  158. package/core/built/admin/assets/share-modal-BDb2nacg.js +1 -0
  159. package/core/built/admin/assets/skeleton-D7hwjdry.js +1 -0
  160. package/core/built/admin/assets/slack-modal-CwNAD69x.js +1 -0
  161. package/core/built/admin/assets/sort-button-DhqpxkrO.js +1 -0
  162. package/core/built/admin/assets/source-icon-BPsD5ees.js +1 -0
  163. package/core/built/admin/assets/stats-WdDJ8c_1.js +1 -0
  164. package/core/built/admin/assets/stats-view-J3PI2eT_.js +1 -0
  165. package/core/built/admin/assets/step-1-2q1SjerQ.js +1 -0
  166. package/core/built/admin/assets/step-2-D5mJB3Uu.js +1 -0
  167. package/core/built/admin/assets/step-3-BpAuYTGZ.js +2 -0
  168. package/core/built/admin/assets/{stripe-button-Bh4p6Wud.js → stripe-button-DDoUKN5a.js} +1 -1
  169. package/core/built/admin/assets/stripe-connect-modal-pMdF3t4S.js +1 -0
  170. package/core/built/admin/assets/switch-B_1yU3Aw.js +1 -0
  171. package/core/built/admin/assets/{table-DghJxZMH.js → table-CrqQtkR2.js} +1 -1
  172. package/core/built/admin/assets/tabs-BhzVdh5p.js +1 -0
  173. package/core/built/admin/assets/tag-detail-CwJhI4qg.js +2 -0
  174. package/core/built/admin/assets/tags-CvJ0PgrB.js +1 -0
  175. package/core/built/admin/assets/testimonials-modal-CV82IAnI.js +1 -0
  176. package/core/built/admin/assets/tier-detail-modal-pLzCOfeg.js +1 -0
  177. package/core/built/admin/assets/toggle-group-BW_T4yn6.js +1 -0
  178. package/core/built/admin/assets/topic-filter-DkXjDejV.js +1 -0
  179. package/core/built/admin/assets/transistor-modal-TMRvHZ6B.js +1 -0
  180. package/core/built/admin/assets/unsplash-modal-CV92RdPw.js +1 -0
  181. package/core/built/admin/assets/{use-analytics-data-IxJcSjc9.js → use-analytics-data-BM_uV9SU.js} +1 -1
  182. package/core/built/admin/assets/use-check-theme-limit-error-DkBnXMSY.js +1 -0
  183. package/core/built/admin/assets/use-confirm-unload-SzlkOIpm.js +1 -0
  184. package/core/built/admin/assets/use-feature-flag-cahOlMva.js +1 -0
  185. package/core/built/admin/assets/use-filter-params-BX5qf0Cg.js +1 -0
  186. package/core/built/admin/assets/{use-growth-stats-1NW-8eEZ.js → use-growth-stats-D0LlWBe6.js} +1 -1
  187. package/core/built/admin/assets/{use-hash-link-navigation-guard-B9j6HIrV.js → use-hash-link-navigation-guard-B_Y3FhYH.js} +1 -1
  188. package/core/built/admin/assets/use-limiter-D3DHSoAj.js +2 -0
  189. package/core/built/admin/assets/{use-pintura-config-BjFChXV1.js → use-pintura-config-D63Xu0SG.js} +1 -1
  190. package/core/built/admin/assets/use-pintura-editor-Z51aFnC8.js +1 -0
  191. package/core/built/admin/assets/{use-post-referrers-Dp1BnTAK.js → use-post-referrers-Cvymr3gt.js} +1 -1
  192. package/core/built/admin/assets/use-query-params-BfzuqbcD.js +1 -0
  193. package/core/built/admin/assets/use-reply-chain-data-Dc18Ujqo.js +1 -0
  194. package/core/built/admin/assets/use-setting-group-DYRIzqC0.js +1 -0
  195. package/core/built/admin/assets/use-settings-navigation-aDSLtmEl.js +1 -0
  196. package/core/built/admin/assets/{use-simple-pagination-DsEGSJhe.js → use-simple-pagination-B2TdNX67.js} +1 -1
  197. package/core/built/admin/assets/{use-tinybird-query-Ci_DiPkX.js → use-tinybird-query-BvQIVuRc.js} +1 -1
  198. package/core/built/admin/assets/{use-tinybird-token-CsUwc722.js → use-tinybird-token-COQTPIwL.js} +1 -1
  199. package/core/built/admin/assets/use-upgrade-route-BZf1g59m.js +1 -0
  200. package/core/built/admin/assets/{use-url-input-BEZJpVgN.js → use-url-input-PcqZadXa.js} +1 -1
  201. package/core/built/admin/assets/user-detail-modal-DeO3SAZq.js +1 -0
  202. package/core/built/admin/assets/{virtual-list-D5ugXyZY.js → virtual-list-D3MfPNOh.js} +1 -1
  203. package/core/built/admin/assets/web-CDdyG7z1.js +2 -0
  204. package/core/built/admin/assets/web-CwQ8_QUc.js +1 -0
  205. package/core/built/admin/assets/zapier-modal-a7t75iNI.js +1 -0
  206. package/core/built/admin/index.html +15 -12
  207. package/core/frontend/apps/private-blogging/lib/helpers/input_password.js +2 -1
  208. package/core/frontend/helpers/body_class.js +2 -1
  209. package/core/frontend/helpers/cancel_link.js +2 -1
  210. package/core/frontend/helpers/color_to_rgba.js +2 -1
  211. package/core/frontend/helpers/content_api_key.js +2 -1
  212. package/core/frontend/helpers/content_api_url.js +2 -1
  213. package/core/frontend/helpers/contrast_text_color.js +2 -1
  214. package/core/frontend/helpers/facebook_url.js +2 -1
  215. package/core/frontend/helpers/ghost_foot.js +2 -1
  216. package/core/frontend/helpers/ghost_head.js +2 -1
  217. package/core/frontend/helpers/has.js +4 -2
  218. package/core/frontend/helpers/link_class.js +2 -1
  219. package/core/frontend/helpers/meta_description.js +2 -1
  220. package/core/frontend/helpers/meta_title.js +2 -1
  221. package/core/frontend/helpers/navigation.js +113 -22
  222. package/core/frontend/helpers/page_url.js +2 -1
  223. package/core/frontend/helpers/post_class.js +2 -1
  224. package/core/frontend/helpers/reading_time.js +2 -1
  225. package/core/frontend/helpers/social_accounts.js +2 -1
  226. package/core/frontend/helpers/social_url.js +2 -1
  227. package/core/frontend/helpers/total_members.js +2 -1
  228. package/core/frontend/helpers/total_paid_members.js +2 -1
  229. package/core/frontend/helpers/tpl/navigation.hbs +1 -1
  230. package/core/frontend/helpers/twitter_url.js +2 -1
  231. package/core/frontend/public/cards.manifest.json +1 -1
  232. package/core/server/api/endpoints/posts.js +7 -4
  233. package/core/server/api/endpoints/utils/permissions.js +2 -1
  234. package/core/server/api/endpoints/utils/validators/input/settings.js +83 -1
  235. package/core/server/data/exporter/table-lists.js +1 -0
  236. package/core/server/data/importer/handlers/json.js +2 -1
  237. package/core/server/data/migrations/versions/5.19/2022-09-02-20-52-backfill-new-product-columns.js +2 -1
  238. package/core/server/data/migrations/versions/5.21/2022-10-26-04-50-member-subscription-created-batch-id.js +4 -2
  239. package/core/server/data/migrations/versions/5.22/2022-10-31-12-03-backfill-new-product-columns.js +2 -1
  240. package/core/server/data/migrations/versions/6.58/2026-08-11-21-22-48-rename-email-batches-provider-id.js +1 -1
  241. package/core/server/data/migrations/versions/6.59/2026-08-18-17-06-46-add-gift-delivery-fields-to-gifts.js +26 -0
  242. package/core/server/data/migrations/versions/6.59/2026-08-18-17-07-01-add-gift-deliveries.js +20 -0
  243. package/core/server/data/schema/commands.js +48 -24
  244. package/core/server/data/schema/schema.js +28 -7
  245. package/core/server/data/seeders/importers/automation-action-revisions-importer.js +3 -36
  246. package/core/server/data/seeders/importers/automation-actions-importer.js +5 -41
  247. package/core/server/data/seeders/importers/automation-run-steps-importer.js +3 -36
  248. package/core/server/data/seeders/importers/automation-runs-importer.js +7 -42
  249. package/core/server/data/seeders/importers/automations-importer.js +3 -36
  250. package/core/server/data/seeders/importers/comment-reports-importer.js +5 -5
  251. package/core/server/data/seeders/importers/comments-importer.js +5 -5
  252. package/core/server/data/seeders/importers/email-batches-importer.js +5 -4
  253. package/core/server/data/seeders/importers/email-recipients-importer.js +12 -20
  254. package/core/server/data/seeders/importers/emails-importer.js +6 -6
  255. package/core/server/data/seeders/importers/labels-importer.js +3 -3
  256. package/core/server/data/seeders/importers/members-click-events-importer.js +5 -5
  257. package/core/server/data/seeders/importers/members-created-events-importer.js +13 -12
  258. package/core/server/data/seeders/importers/members-feedback-importer.js +7 -7
  259. package/core/server/data/seeders/importers/members-importer.js +4 -4
  260. package/core/server/data/seeders/importers/members-login-events-importer.js +3 -3
  261. package/core/server/data/seeders/importers/members-products-importer.js +2 -2
  262. package/core/server/data/seeders/importers/members-status-events-importer.js +4 -3
  263. package/core/server/data/seeders/importers/members-stripe-customers-importer.js +2 -2
  264. package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +7 -7
  265. package/core/server/data/seeders/importers/members-subscribe-events-importer.js +3 -3
  266. package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +3 -3
  267. package/core/server/data/seeders/importers/offer-redemptions-importer.js +7 -7
  268. package/core/server/data/seeders/importers/offers-importer.js +3 -3
  269. package/core/server/data/seeders/importers/posts-importer.js +4 -4
  270. package/core/server/data/seeders/importers/table-importer.js +2 -35
  271. package/core/server/data/seeders/importers/tags-importer.js +2 -2
  272. package/core/server/data/seeders/importers/users-importer.js +2 -2
  273. package/core/server/data/seeders/importers/web-mentions-importer.js +2 -2
  274. package/core/server/data/seeders/utils/random.js +7 -0
  275. package/core/server/ghost-server.js +19 -5
  276. package/core/server/lib/db-date.js +72 -3
  277. package/core/server/models/gift-delivery.js +23 -0
  278. package/core/server/models/gift.js +9 -0
  279. package/core/server/models/index.js +3 -2
  280. package/core/server/models/settings.js +43 -4
  281. package/core/server/services/automations/database-automations-repository.js +38 -31
  282. package/core/server/services/automations/poll.js +1 -1
  283. package/core/server/services/content-import/csv/index.js +8 -0
  284. package/core/server/services/content-import/csv/parse.js +60 -0
  285. package/core/server/services/content-import/import/importer.js +222 -0
  286. package/core/server/services/content-import/import/post-data.js +52 -0
  287. package/core/server/services/content-import/import/reader.js +15 -0
  288. package/core/server/services/content-import/import/row.js +50 -0
  289. package/core/server/services/content-import/import/store.js +71 -0
  290. package/core/server/services/content-import/index.js +67 -0
  291. package/core/server/services/email-analytics/automation-email-analytics-batch-processor.js +1 -1
  292. package/core/server/services/email-analytics/index.js +3 -1
  293. package/core/server/services/email-analytics/jobs/index.js +2 -2
  294. package/core/server/services/email-service/email-service-wrapper.js +1 -1
  295. package/core/server/services/email-suppression-list/email-suppression-list.js +4 -2
  296. package/core/server/services/gifts/CONTEXT.md +27 -3
  297. package/core/server/services/gifts/README.md +8 -4
  298. package/core/server/services/gifts/constants.js +2 -1
  299. package/core/server/services/gifts/email-templates/gift-delivery.hbs +20 -0
  300. package/core/server/services/gifts/email-templates/gift-delivery.js +39 -0
  301. package/core/server/services/gifts/email-templates/gift-purchase-confirmation.hbs +2 -2
  302. package/core/server/services/gifts/email-templates/gift-purchase-confirmation.js +19 -4
  303. package/core/server/services/gifts/events/send-gift-delivery-event.js +15 -0
  304. package/core/server/services/gifts/gift-bookshelf-repository.js +23 -3
  305. package/core/server/services/gifts/gift-checkout-adapter.js +5 -3
  306. package/core/server/services/gifts/gift-codec.js +8 -0
  307. package/core/server/services/gifts/gift-delivery-bookshelf-repository.js +107 -0
  308. package/core/server/services/gifts/gift-delivery-codec.js +12 -0
  309. package/core/server/services/gifts/gift-delivery-schema.js +15 -0
  310. package/core/server/services/gifts/gift-delivery-service.js +209 -0
  311. package/core/server/services/gifts/gift-email-renderer.js +13 -1
  312. package/core/server/services/gifts/gift-email-service.js +97 -17
  313. package/core/server/services/gifts/gift-schema.js +10 -6
  314. package/core/server/services/gifts/gift-service.js +259 -34
  315. package/core/server/services/gifts/gift.js +59 -5
  316. package/core/server/services/gifts/index.js +69 -3
  317. package/core/server/services/lib/mailgun-client.js +5 -2
  318. package/core/server/services/mail/ghost-mailer.js +9 -1
  319. package/core/server/services/member-welcome-emails/service.js +6 -1
  320. package/core/server/services/members/members-api/controllers/router-controller.js +26 -8
  321. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +100 -12
  322. package/core/server/services/stripe/stripe-api.js +3 -2
  323. package/core/server/services/stripe/webhook-controller.js +6 -3
  324. package/core/server/services/stripe/webhook-manager.js +2 -0
  325. package/core/shared/labs.js +1 -0
  326. package/package.json +9 -8
  327. package/pnpm-lock.yaml +26 -11
  328. package/pnpm-workspace.yaml +5 -6
  329. package/content/themes/source/yarn.lock +0 -6232
  330. package/core/built/admin/assets/Combination-BDvCdg1t.js +0 -41
  331. package/core/built/admin/assets/about-B_BvSyLF.js +0 -1
  332. package/core/built/admin/assets/account-migration-oJUGxnzT.js +0 -1
  333. package/core/built/admin/assets/activitypub/dist-Dqggkccr.js +0 -215
  334. package/core/built/admin/assets/activitypub/inbox-z1o2j1Tb.js +0 -1221
  335. package/core/built/admin/assets/activitypub/layout-BRMezuty.js +0 -1
  336. package/core/built/admin/assets/activitypub/moderation-CZudJi8N.js +0 -160
  337. package/core/built/admin/assets/activitypub/settings-CrSV1cux.js +0 -107
  338. package/core/built/admin/assets/add-integration-modal-BW23PDYs.js +0 -1
  339. package/core/built/admin/assets/add-newsletter-modal-M0ls8BKO.js +0 -1
  340. package/core/built/admin/assets/add-recommendation-modal-B0NeBMzl.js +0 -1
  341. package/core/built/admin/assets/announcement-bar-modal-pXBqjQE_.js +0 -1
  342. package/core/built/admin/assets/api-keys-Df6uv1dT.js +0 -1
  343. package/core/built/admin/assets/audience-BY8od8If.js +0 -1
  344. package/core/built/admin/assets/automations-DCs6Wady.js +0 -1
  345. package/core/built/admin/assets/bluesky-sharing-D0P42Cws.js +0 -1
  346. package/core/built/admin/assets/breadcrumb-MTj_cKLb.js +0 -1
  347. package/core/built/admin/assets/chart-helpers-DcO3k_vA.js +0 -1
  348. package/core/built/admin/assets/chunk-KS7C4IRE-DG9HTHQ3.js +0 -4
  349. package/core/built/admin/assets/color-picker-CBlJMv3y.js +0 -3
  350. package/core/built/admin/assets/combobox-BbPJzjCp.js +0 -1
  351. package/core/built/admin/assets/command-BrhXIlDr.js +0 -1
  352. package/core/built/admin/assets/comments-Cu4rD1aJ.js +0 -1
  353. package/core/built/admin/assets/confirmation-provider-BEdrnHns.js +0 -1
  354. package/core/built/admin/assets/custom-field-type-option-CNhAgHbJ.js +0 -1
  355. package/core/built/admin/assets/custom-integration-modal-CrGOI8IB.js +0 -1
  356. package/core/built/admin/assets/date-range-select-Bsh4gIek.js +0 -1
  357. package/core/built/admin/assets/design-and-theme-modal-DWZguwWX.js +0 -23
  358. package/core/built/admin/assets/dirty-confirm-dialog-DmdMpgyN.js +0 -1
  359. package/core/built/admin/assets/disabled-sources-indicator-BLnmyWgt.js +0 -1
  360. package/core/built/admin/assets/dist-DMFGvqqU.js +0 -1
  361. package/core/built/admin/assets/dist-DlCyLrOC.js +0 -1
  362. package/core/built/admin/assets/dist-j1xxxnY8.js +0 -1
  363. package/core/built/admin/assets/domain-Dp9TRrFp.js +0 -1
  364. package/core/built/admin/assets/edit-profile-DG6lpMsr.js +0 -1
  365. package/core/built/admin/assets/editor-CPQOrhrn.js +0 -8
  366. package/core/built/admin/assets/embed-signup-form-modal-CgWniDha.js +0 -9
  367. package/core/built/admin/assets/explore-C3rzONJv.js +0 -1
  368. package/core/built/admin/assets/feed-DpUwS1cU.js +0 -1
  369. package/core/built/admin/assets/filters-DZJT29GW.js +0 -1
  370. package/core/built/admin/assets/first-promoter-modal-DJhQQheG.js +0 -1
  371. package/core/built/admin/assets/gift-link-modal-sdFLjND9.js +0 -1
  372. package/core/built/admin/assets/global-data-provider-CixmTX00.js +0 -1
  373. package/core/built/admin/assets/growth-0YYkBEeS.js +0 -1
  374. package/core/built/admin/assets/growth-DpjAPeQT.js +0 -3
  375. package/core/built/admin/assets/history-modal-BWJ4-cJ0.js +0 -1
  376. package/core/built/admin/assets/html-field-C-oa5DEl.js +0 -1
  377. package/core/built/admin/assets/iframe-buffering-Ba9sDpi2.js +0 -1
  378. package/core/built/admin/assets/index-BOJzlYiz.js +0 -67
  379. package/core/built/admin/assets/index-Bid6LAyc.css +0 -1
  380. package/core/built/admin/assets/invite-user-modal-DCiQSiuD.js +0 -1
  381. package/core/built/admin/assets/koenig-editor-base-BApy8Q7C.js +0 -1
  382. package/core/built/admin/assets/kpi-helpers-ssbuy-hD.js +0 -1
  383. package/core/built/admin/assets/kpi-tabs-BqoIM6bI.js +0 -1
  384. package/core/built/admin/assets/label-picker-Cvvbmzb5.js +0 -1
  385. package/core/built/admin/assets/layout-DkkGyev2.js +0 -1
  386. package/core/built/admin/assets/member-custom-fields-CvGcpaiW.js +0 -1
  387. package/core/built/admin/assets/member-detail-CMCMZ47_.js +0 -1
  388. package/core/built/admin/assets/members-sRl6fNfq.js +0 -11
  389. package/core/built/admin/assets/moderation-KhKwGqI1.js +0 -1
  390. package/core/built/admin/assets/multi-select-combobox-nhCff0_K.js +0 -1
  391. package/core/built/admin/assets/navigation-modal-MDJExWDJ.js +0 -1
  392. package/core/built/admin/assets/newsletter-BIBHumfV.js +0 -1
  393. package/core/built/admin/assets/newsletter-detail-modal-CfjBMH3v.js +0 -1
  394. package/core/built/admin/assets/newsletter-emails-ClDL-7dA.js +0 -1
  395. package/core/built/admin/assets/newsletters-CBe-IPzK.js +0 -1
  396. package/core/built/admin/assets/note-HnNUOt4d.js +0 -1
  397. package/core/built/admin/assets/notifications-Cj5e-258.js +0 -1
  398. package/core/built/admin/assets/offers-container-modal-BHwHtixC.js +0 -1
  399. package/core/built/admin/assets/onboarding-route-D_4jp7Nq.js +0 -1
  400. package/core/built/admin/assets/overview-CezDdg-F.js +0 -1
  401. package/core/built/admin/assets/overview-D5mM51Lj.js +0 -1
  402. package/core/built/admin/assets/pintura-modal-BXXJ8Iaa.js +0 -1
  403. package/core/built/admin/assets/portal-frame-BLCvF8f-.js +0 -1
  404. package/core/built/admin/assets/portal-modal-DN80tAcy.js +0 -1
  405. package/core/built/admin/assets/post-analytics-header-_ydSY8qO.js +0 -1
  406. package/core/built/admin/assets/post-share-modal-CzYak_a5.js +0 -1
  407. package/core/built/admin/assets/preferences-gneLb6LV.js +0 -5
  408. package/core/built/admin/assets/preview-modal-Bkq-tgVm.js +0 -1
  409. package/core/built/admin/assets/profile-CzXmCNTC.js +0 -1
  410. package/core/built/admin/assets/radio-group-Dsq5ZEbV.js +0 -1
  411. package/core/built/admin/assets/router-provider-CkB_ArLF.js +0 -1
  412. package/core/built/admin/assets/select-xuZAuDyS.js +0 -1
  413. package/core/built/admin/assets/settings-Ct8pabhr.js +0 -1
  414. package/core/built/admin/assets/settings-KSWWQanQ.js +0 -4
  415. package/core/built/admin/assets/settings-breadcrumbs-DbPGu-Tu.js +0 -1
  416. package/core/built/admin/assets/share-modal-CdiUx9WM.js +0 -1
  417. package/core/built/admin/assets/slack-modal-BP--Z3jE.js +0 -1
  418. package/core/built/admin/assets/sort-button-CjfKdlsL.js +0 -1
  419. package/core/built/admin/assets/source-icon-DHj1h6Ts.js +0 -1
  420. package/core/built/admin/assets/stats-C615kulJ.js +0 -1
  421. package/core/built/admin/assets/stats-view-BSMRdYiN.js +0 -1
  422. package/core/built/admin/assets/step-1-pSdGYtIF.js +0 -1
  423. package/core/built/admin/assets/step-2-T9Uy4eBD.js +0 -1
  424. package/core/built/admin/assets/step-3-D4uXe_XG.js +0 -2
  425. package/core/built/admin/assets/stripe-connect-modal-C2vTvepi.js +0 -1
  426. package/core/built/admin/assets/switch-CE2NuMn-.js +0 -1
  427. package/core/built/admin/assets/tabs-l9c7FjzI.js +0 -1
  428. package/core/built/admin/assets/tag-detail-DBw_M2-p.js +0 -2
  429. package/core/built/admin/assets/tags-DoWsAG6l.js +0 -1
  430. package/core/built/admin/assets/testimonials-modal-BZKePE2T.js +0 -1
  431. package/core/built/admin/assets/tier-detail-modal-D65pVWsN.js +0 -1
  432. package/core/built/admin/assets/toggle-group-uJnl42w3.js +0 -1
  433. package/core/built/admin/assets/topic-filter-BM7hz0kW.js +0 -1
  434. package/core/built/admin/assets/transistor-modal-VZOGN3od.js +0 -1
  435. package/core/built/admin/assets/unsplash-modal-CKGfACxF.js +0 -1
  436. package/core/built/admin/assets/use-check-theme-limit-error-CGp3CGT5.js +0 -1
  437. package/core/built/admin/assets/use-feature-flag-CSq2Lwzt.js +0 -1
  438. package/core/built/admin/assets/use-filter-params-0hcJJuEJ.js +0 -1
  439. package/core/built/admin/assets/use-limiter-ffwpsZPp.js +0 -2
  440. package/core/built/admin/assets/use-pintura-editor-Cb41oJyL.js +0 -1
  441. package/core/built/admin/assets/use-query-params-DHhhu8wi.js +0 -1
  442. package/core/built/admin/assets/use-reply-chain-data-C0ZUTkfk.js +0 -1
  443. package/core/built/admin/assets/use-setting-group-Bx8M6FL2.js +0 -1
  444. package/core/built/admin/assets/use-settings-navigation-BOZcat_V.js +0 -1
  445. package/core/built/admin/assets/use-upgrade-route-B3_DUiuT.js +0 -1
  446. package/core/built/admin/assets/user-detail-modal-595z1N5r.js +0 -1
  447. package/core/built/admin/assets/web-CAta3lRE.js +0 -1
  448. package/core/built/admin/assets/web-Ds9_wWJK.js +0 -2
  449. package/core/built/admin/assets/zapier-modal-CcfDZY53.js +0 -1
  450. package/core/server/data/seeders/utils/database-date.js +0 -28
  451. package/core/server/services/automations/database-date.js +0 -59
  452. /package/core/built/admin/assets/{dist-CqO2lWS02.js → dist-CqO2lWS0.js} +0 -0
  453. /package/core/server/services/{automations → lib}/mailgun-message-id.js +0 -0
@@ -68,6 +68,7 @@ function createMessage(message) {
68
68
  delete cleanMessage.tags;
69
69
  delete cleanMessage.forceTextContent;
70
70
  delete cleanMessage.trackOpens;
71
+ delete cleanMessage.disableTracking;
71
72
 
72
73
  const addresses = getFromAddress(message.from, message.replyTo);
73
74
 
@@ -132,6 +133,7 @@ module.exports = class GhostMailer {
132
133
  * @param {string} [message.text] - text version of this message
133
134
  * @param {string[]} [message.tags] - optional additional Mailgun tags
134
135
  * @param {boolean} [message.trackOpens] - per-message override for Mailgun open tracking
136
+ * @param {boolean} [message.disableTracking] - explicitly disable Mailgun open and click tracking
135
137
  * @param {Record<string, string>} [message.headers] - optional additional email headers (merged with defaults)
136
138
  * @param {boolean} [message.forceTextContent] - maps to generateTextFromHTML nodemailer option
137
139
  * which is: "if set to true uses HTML to generate plain text body part from the HTML if the text is not defined"
@@ -155,7 +157,13 @@ module.exports = class GhostMailer {
155
157
  const trackOpens = typeof message.trackOpens === 'boolean' ?
156
158
  message.trackOpens :
157
159
  settingsCache.get('email_track_opens');
158
- if (trackOpens) {
160
+ // nodemailer-mailgun-transport drops falsy option values, so an explicit
161
+ // opt-out must be Mailgun's string form rather than boolean false
162
+ if (message.disableTracking === true) {
163
+ messageToSend['o:tracking'] = 'no';
164
+ messageToSend['o:tracking-opens'] = 'no';
165
+ messageToSend['o:tracking-clicks'] = 'no';
166
+ } else if (trackOpens) {
159
167
  messageToSend['o:tracking-opens'] = true;
160
168
  }
161
169
  if (messageToSend.headers) {
@@ -420,10 +420,15 @@ class MemberWelcomeEmailService {
420
420
  tags = [MEMBER_WELCOME_EMAIL_TAG];
421
421
  sendEmail = this.#sendTransactionalEmail.bind(this);
422
422
  break;
423
- case 'automation':
423
+ case 'automation': {
424
424
  tags = [AUTOMATION_EMAIL_TAG];
425
+ const mailgunTagFromConfig = config.get('bulkEmail:mailgun:tag');
426
+ if (typeof mailgunTagFromConfig === 'string' && mailgunTagFromConfig.length > 0) {
427
+ tags.push(mailgunTagFromConfig);
428
+ }
425
429
  sendEmail = this.#sendBulkEmail.bind(this);
426
430
  break;
431
+ }
427
432
  default: {
428
433
  /** @type {never} */ const _exhaustive = emailType;
429
434
  throw new errors.InternalServerError({
@@ -67,6 +67,7 @@ function extractGiftToken(input) {
67
67
  const RESERVED_CHECKOUT_METADATA_KEYS = new Set([
68
68
  'ghost_donation',
69
69
  'ghost_gift',
70
+ 'ghost_gift_id',
70
71
  'ghostSignupContext',
71
72
  'gift_token',
72
73
  'tier_id',
@@ -684,10 +685,14 @@ module.exports = class RouterController {
684
685
  * @param {string} [options.offerId]
685
686
  * @param {string} [options.cadence]
686
687
  * @param {number} [options.duration]
688
+ * @param {'link'|'email'} [options.deliveryMethod]
689
+ * @param {string} [options.recipientEmail]
690
+ * @param {string} [options.recipientName]
691
+ * @param {string} [options.buyerName]
692
+ * @param {string} [options.personalMessage]
687
693
  * @param {string} [options.email]
688
694
  * @param {string} options.successUrl
689
695
  * @param {string} options.cancelUrl
690
- * @param {object} options.metadata
691
696
  * @param {object} [options.member]
692
697
  * @param {boolean} options.isAuthenticated
693
698
  * @returns
@@ -705,7 +710,11 @@ module.exports = class RouterController {
705
710
  offerId: options.offerId,
706
711
  cadence: options.cadence,
707
712
  duration: options.duration,
708
- metadata: options.metadata,
713
+ deliveryMethod: options.deliveryMethod,
714
+ recipientEmail: options.recipientEmail,
715
+ recipientName: options.recipientName,
716
+ buyerName: options.buyerName,
717
+ personalMessage: options.personalMessage,
709
718
  successUrl: options.successUrl,
710
719
  cancelUrl: options.cancelUrl,
711
720
  buyer: {
@@ -857,6 +866,11 @@ module.exports = class RouterController {
857
866
  offerId: req.body.offerId,
858
867
  cadence: req.body.cadence,
859
868
  duration: req.body.duration,
869
+ deliveryMethod: req.body.deliveryMethod,
870
+ recipientEmail: req.body.recipientEmail,
871
+ recipientName: req.body.recipientName,
872
+ buyerName: req.body.buyerName,
873
+ personalMessage: req.body.personalMessage,
860
874
  successUrl: siteUrl,
861
875
  cancelUrl: options.cancelUrl || siteUrl
862
876
  });
@@ -1261,20 +1275,24 @@ module.exports = class RouterController {
1261
1275
  }
1262
1276
  };
1263
1277
 
1278
+ // Stripe's limit on `custom_fields[].label.custom` — longer labels make session creation fail
1279
+ const STRIPE_CUSTOM_FIELD_LABEL_MAX_LENGTH = 50;
1280
+
1264
1281
  function parsePersonalNote(rawText) {
1265
1282
  if (rawText && typeof rawText !== 'string') {
1266
1283
  logging.warn('Donation personal note is not a string, ignoring');
1267
1284
  return '';
1268
1285
  }
1269
- if (rawText && rawText.length > 255) {
1270
- logging.warn('Donation personal note is too long, ignoring:', rawText);
1271
- return '';
1272
- }
1273
1286
 
1274
- const safeInput = sanitizeHtml(rawText, {
1287
+ // Bounded twice, for two different reasons. Before sanitising because this is a
1288
+ // public endpoint and nothing past the limit can survive anyway, so there is no
1289
+ // reason to sanitise more than that. After, because sanitising can lengthen the
1290
+ // string (`&` becomes `&amp;`), and the second bound is the one Stripe measures.
1291
+ const bounded = (rawText ?? '').slice(0, STRIPE_CUSTOM_FIELD_LABEL_MAX_LENGTH);
1292
+ const safeInput = sanitizeHtml(bounded, {
1275
1293
  allowedTags: [],
1276
1294
  allowedAttributes: {}
1277
1295
  });
1278
1296
 
1279
- return safeInput;
1297
+ return safeInput.slice(0, STRIPE_CUSTOM_FIELD_LABEL_MAX_LENGTH);
1280
1298
  }
@@ -14,8 +14,18 @@ function hasStripeMetadataKey(metadata, key) {
14
14
  return Object.prototype.hasOwnProperty.call(metadata || {}, key);
15
15
  }
16
16
 
17
- function hasConflictingCheckoutFlowMetadata(metadata) {
18
- return hasStripeMetadataKey(metadata, 'ghost_donation') && hasStripeMetadataKey(metadata, 'ghost_gift');
17
+ function isGiftCheckoutSession(session) {
18
+ return hasStripeMetadataKey(session.metadata, 'ghost_gift_id') || isStripeMetadataTrue(session.metadata?.ghost_gift);
19
+ }
20
+
21
+ function isDonationCheckoutSession(session) {
22
+ return isStripeMetadataTrue(session.metadata?.ghost_donation);
23
+ }
24
+
25
+ // Matches the donation marker on key presence, not truthiness, so an ill-formed
26
+ // donation marker alongside a true gift marker still counts as a conflict.
27
+ function hasConflictingCheckoutFlowMetadata(session) {
28
+ return hasStripeMetadataKey(session.metadata, 'ghost_donation') && isGiftCheckoutSession(session);
19
29
  }
20
30
 
21
31
  function getStripeResourceId(resource) {
@@ -30,6 +40,18 @@ function getStripeResourceId(resource) {
30
40
  return null;
31
41
  }
32
42
 
43
+ function getGiftBuyerEmailFromSession(session) {
44
+ if (session.customer_details?.email) {
45
+ return session.customer_details.email;
46
+ }
47
+
48
+ if (session.customer && typeof session.customer === 'object' && !session.customer.deleted && session.customer.email) {
49
+ return session.customer.email;
50
+ }
51
+
52
+ return null;
53
+ }
54
+
33
55
  /**
34
56
  * Handles `checkout.session.completed` webhook events
35
57
  *
@@ -65,8 +87,20 @@ module.exports = class CheckoutSessionEventService {
65
87
  * Handles a `checkout.session.completed` event
66
88
  * Delegates to the appropriate handler based on the session mode and metadata
67
89
  * @param {import('stripe').Stripe.Checkout.Session} session
90
+ * @param {import('stripe').Stripe.Event.Type} [eventType]
68
91
  */
69
- async handleEvent(session) {
92
+ async handleEvent(session, eventType = 'checkout.session.completed') {
93
+ if (eventType === 'checkout.session.async_payment_failed') {
94
+ return;
95
+ }
96
+
97
+ if (eventType === 'checkout.session.async_payment_succeeded') {
98
+ if (session.mode === 'payment' && isGiftCheckoutSession(session)) {
99
+ await this.handlePaymentEvent(session);
100
+ }
101
+ return;
102
+ }
103
+
70
104
  if (session.mode === 'setup') {
71
105
  await this.handleSetupEvent(session);
72
106
  }
@@ -76,16 +110,33 @@ module.exports = class CheckoutSessionEventService {
76
110
  }
77
111
 
78
112
  if (session.mode === 'payment') {
79
- if (hasConflictingCheckoutFlowMetadata(session.metadata)) {
80
- logging.warn('Ignoring checkout session with conflicting payment flow metadata');
113
+ await this.handlePaymentEvent(session);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Routes a `payment` mode session to the donation or gift handler. Gift purchases
119
+ * may complete asynchronously, so their handler only runs once Stripe reports the
120
+ * session as paid, whichever event carried it.
121
+ *
122
+ * @param {import('stripe').Stripe.Checkout.Session} session
123
+ */
124
+ async handlePaymentEvent(session) {
125
+ if (hasConflictingCheckoutFlowMetadata(session)) {
126
+ logging.warn('Ignoring checkout session with conflicting payment flow metadata');
127
+ return;
128
+ }
129
+
130
+ if (isGiftCheckoutSession(session)) {
131
+ if (session.payment_status !== 'paid') {
81
132
  return;
82
133
  }
134
+ await this.handleGiftEvent(session);
135
+ return;
136
+ }
83
137
 
84
- if (isStripeMetadataTrue(session.metadata?.ghost_donation)) {
85
- await this.handleDonationEvent(session);
86
- } else if (isStripeMetadataTrue(session.metadata?.ghost_gift)) {
87
- await this.handleGiftEvent(session);
88
- }
138
+ if (isDonationCheckoutSession(session)) {
139
+ await this.handleDonationEvent(session);
89
140
  }
90
141
  }
91
142
 
@@ -95,10 +146,24 @@ module.exports = class CheckoutSessionEventService {
95
146
  * @param {import('stripe').Stripe.Checkout.Session} session
96
147
  */
97
148
  async handleGiftEvent(session) {
149
+ const stripeCustomerId = getStripeResourceId(session.customer);
150
+
151
+ if (session.metadata?.ghost_gift_id) {
152
+ await this.deps.giftService.completePurchase({
153
+ giftId: session.metadata.ghost_gift_id,
154
+ buyerEmail: getGiftBuyerEmailFromSession(session),
155
+ stripeCustomerId,
156
+ stripeCheckoutSessionId: session.id,
157
+ stripePaymentIntentId: getStripeResourceId(session.payment_intent)
158
+ });
159
+ return;
160
+ }
161
+
162
+ const buyerEmail = await this.getGiftBuyerEmail(session, stripeCustomerId);
98
163
  await this.deps.giftService.completePurchase({
99
164
  token: session.metadata?.gift_token,
100
- buyerEmail: session.customer_details?.email,
101
- stripeCustomerId: getStripeResourceId(session.customer),
165
+ buyerEmail,
166
+ stripeCustomerId,
102
167
  tierId: session.metadata?.tier_id,
103
168
  cadence: session.metadata?.cadence,
104
169
  duration: Number(session.metadata?.duration),
@@ -109,6 +174,29 @@ module.exports = class CheckoutSessionEventService {
109
174
  });
110
175
  }
111
176
 
177
+ /**
178
+ * Legacy gift Checkout sessions predate persisted buyer details. If their
179
+ * webhook snapshot has no customer details, recover the required buyer email
180
+ * from the Customer associated with the session.
181
+ *
182
+ * @param {import('stripe').Stripe.Checkout.Session} session
183
+ * @param {string|null} stripeCustomerId
184
+ * @returns {Promise<string|null>}
185
+ */
186
+ async getGiftBuyerEmail(session, stripeCustomerId) {
187
+ const sessionEmail = getGiftBuyerEmailFromSession(session);
188
+ if (sessionEmail) {
189
+ return sessionEmail;
190
+ }
191
+
192
+ if (!stripeCustomerId) {
193
+ return null;
194
+ }
195
+
196
+ const customer = await this.api.getCustomer(stripeCustomerId);
197
+ return customer.deleted ? null : customer.email ?? null;
198
+ }
199
+
112
200
  /**
113
201
  * Handles a `checkout.session.completed` event for a donation
114
202
  * @param {import('stripe').Stripe.Checkout.Session} session
@@ -706,10 +706,11 @@ module.exports = class StripeAPI {
706
706
  * @param {string} options.cancelUrl
707
707
  * @param {ICustomer|null} options.customer
708
708
  * @param {string} [options.customerEmail]
709
+ * @param {string} options.idempotencyKey
709
710
  *
710
711
  * @returns {Promise<ICheckoutSession>}
711
712
  */
712
- async createGiftCheckoutSession({amount, currency, tierName, cadence, duration, metadata, successUrl, cancelUrl, customer, customerEmail}) {
713
+ async createGiftCheckoutSession({amount, currency, tierName, cadence, duration, metadata, successUrl, cancelUrl, customer, customerEmail, idempotencyKey}) {
713
714
  await this._rateLimitBucket.throttle();
714
715
 
715
716
  const cadenceLabel = cadence === 'year' ?
@@ -745,7 +746,7 @@ module.exports = class StripeAPI {
745
746
 
746
747
  this._applyAutomaticTaxSessionOptions(stripeSessionOptions, {hasCustomer: Boolean(customer)});
747
748
 
748
- const session = await this._stripe.checkout.sessions.create(stripeSessionOptions);
749
+ const session = await this._stripe.checkout.sessions.create(stripeSessionOptions, {idempotencyKey});
749
750
 
750
751
  return session;
751
752
  }
@@ -21,6 +21,8 @@ module.exports = class WebhookController {
21
21
  'customer.subscription.created': this.subscriptionEvent,
22
22
  'invoice.payment_succeeded': this.invoiceEvent,
23
23
  'checkout.session.completed': this.checkoutSessionEvent,
24
+ 'checkout.session.async_payment_succeeded': this.checkoutSessionEvent,
25
+ 'checkout.session.async_payment_failed': this.checkoutSessionEvent,
24
26
  'charge.refunded': this.chargeRefundedEvent
25
27
  };
26
28
  }
@@ -119,7 +121,7 @@ module.exports = class WebhookController {
119
121
  return;
120
122
  }
121
123
 
122
- await this.handlers[event.type].call(this, event.data.object);
124
+ await this.handlers[event.type].call(this, event.data.object, event.type);
123
125
  }
124
126
 
125
127
  /**
@@ -143,10 +145,11 @@ module.exports = class WebhookController {
143
145
  /**
144
146
  * Delegates any `checkout.session.*` events to the `checkoutSessionEventService`
145
147
  * @param {import('stripe').Stripe.Checkout.Session} session
148
+ * @param {import('stripe').Stripe.Event.Type} eventType
146
149
  * @private
147
150
  */
148
- async checkoutSessionEvent(session) {
149
- await this.checkoutSessionEventService.handleEvent(session);
151
+ async checkoutSessionEvent(session, eventType) {
152
+ await this.checkoutSessionEventService.handleEvent(session, eventType);
150
153
  }
151
154
 
152
155
  /**
@@ -43,6 +43,8 @@ module.exports = class WebhookManager {
43
43
  /** @type {WebhookEvent[]} */
44
44
  static events = [
45
45
  'checkout.session.completed',
46
+ 'checkout.session.async_payment_succeeded',
47
+ 'checkout.session.async_payment_failed',
46
48
  'customer.subscription.deleted',
47
49
  'customer.subscription.updated',
48
50
  'customer.subscription.created',
@@ -51,6 +51,7 @@ const PRIVATE_FEATURES = [
51
51
  'themeTranslation',
52
52
  'pictureImageFormats',
53
53
  'getHelperDeduplication',
54
+ 'navigationIcons',
54
55
  'membersCustomFields',
55
56
  'paywallImprovements',
56
57
  'giftSubCustomization',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghost",
3
- "version": "6.58.0",
3
+ "version": "6.59.0",
4
4
  "description": "The professional publishing platform",
5
5
  "author": "Ghost Foundation",
6
6
  "homepage": "https://ghost.org",
@@ -184,6 +184,7 @@
184
184
  "simple-dom": "1.4.0",
185
185
  "stoppable": "1.1.0",
186
186
  "stripe": "8.222.0",
187
+ "temporal-polyfill": "0.3.2",
187
188
  "terser": "5.48.0",
188
189
  "tiny-glob": "0.2.9",
189
190
  "tldts": "^7.4.4",
@@ -192,24 +193,24 @@
192
193
  "unidecode": "1.1.0",
193
194
  "xml": "1.0.1",
194
195
  "zod": "4.4.3",
195
- "@tryghost/adapter-base-redirects": "file:components/tryghost-adapter-base-redirects-0.0.0.tgz",
196
196
  "@tryghost/adapter-base-cache": "file:components/tryghost-adapter-base-cache-0.2.0.tgz",
197
+ "@tryghost/adapter-base-jobs": "file:components/tryghost-adapter-base-jobs-0.0.0.tgz",
198
+ "@tryghost/adapter-base-redirects": "file:components/tryghost-adapter-base-redirects-0.0.0.tgz",
197
199
  "@tryghost/adapter-base-route-settings": "file:components/tryghost-adapter-base-route-settings-0.0.0.tgz",
198
200
  "@tryghost/adapter-base-scheduling": "file:components/tryghost-adapter-base-scheduling-0.2.2.tgz",
199
201
  "@tryghost/adapter-base-sso": "file:components/tryghost-adapter-base-sso-0.1.2.tgz",
200
202
  "@tryghost/admin-api-schema": "file:components/tryghost-admin-api-schema-0.0.0.tgz",
201
- "@tryghost/custom-field-types": "file:components/tryghost-custom-field-types-0.0.0.tgz",
202
203
  "@tryghost/i18n": "file:components/tryghost-i18n-0.0.0.tgz",
204
+ "@tryghost/custom-field-types": "file:components/tryghost-custom-field-types-0.0.0.tgz",
203
205
  "@tryghost/kg-card-factory": "file:components/tryghost-kg-card-factory-5.2.4.tgz",
206
+ "@tryghost/kg-converters": "file:components/tryghost-kg-converters-1.2.5.tgz",
204
207
  "@tryghost/kg-default-cards": "file:components/tryghost-kg-default-cards-10.3.5.tgz",
208
+ "@tryghost/kg-default-nodes": "file:components/tryghost-kg-default-nodes-2.2.0.tgz",
205
209
  "@tryghost/kg-html-to-lexical": "file:components/tryghost-kg-html-to-lexical-1.4.0.tgz",
206
210
  "@tryghost/kg-lexical-html-renderer": "file:components/tryghost-kg-lexical-html-renderer-1.5.0.tgz",
207
- "@tryghost/kg-converters": "file:components/tryghost-kg-converters-1.2.5.tgz",
208
- "@tryghost/kg-default-nodes": "file:components/tryghost-kg-default-nodes-2.2.0.tgz",
211
+ "@tryghost/nql-string": "file:components/tryghost-nql-string-0.0.0.tgz",
209
212
  "@tryghost/parse-email-address": "file:components/tryghost-parse-email-address-0.0.0.tgz",
210
- "ghost-storage-base": "file:components/ghost-storage-base-3.0.0.tgz",
211
- "@tryghost/adapter-base-jobs": "file:components/tryghost-adapter-base-jobs-0.0.0.tgz",
212
- "@tryghost/nql-string": "file:components/tryghost-nql-string-0.0.0.tgz"
213
+ "ghost-storage-base": "file:components/ghost-storage-base-3.0.0.tgz"
213
214
  },
214
215
  "overrides": {
215
216
  "cron-validate": "1.4.5"
package/pnpm-lock.yaml CHANGED
@@ -68,24 +68,24 @@ overrides:
68
68
  '@tryghost/adapter-base-cache': file:components/tryghost-adapter-base-cache-0.2.0.tgz
69
69
  '@tryghost/adapter-base-route-settings': file:components/tryghost-adapter-base-route-settings-0.0.0.tgz
70
70
  '@tryghost/adapter-base-jobs': file:components/tryghost-adapter-base-jobs-0.0.0.tgz
71
+ '@tryghost/adapter-base-sso': file:components/tryghost-adapter-base-sso-0.1.2.tgz
72
+ '@tryghost/adapter-base-scheduling': file:components/tryghost-adapter-base-scheduling-0.2.2.tgz
71
73
  '@tryghost/custom-field-types': file:components/tryghost-custom-field-types-0.0.0.tgz
72
74
  '@tryghost/admin-api-schema': file:components/tryghost-admin-api-schema-0.0.0.tgz
73
75
  '@tryghost/i18n': file:components/tryghost-i18n-0.0.0.tgz
74
- '@tryghost/adapter-base-scheduling': file:components/tryghost-adapter-base-scheduling-0.2.2.tgz
75
- '@tryghost/adapter-base-sso': file:components/tryghost-adapter-base-sso-0.1.2.tgz
76
- '@tryghost/kg-card-factory': file:components/tryghost-kg-card-factory-5.2.4.tgz
76
+ '@tryghost/kg-utils': file:components/tryghost-kg-utils-1.1.4.tgz
77
77
  '@tryghost/nql-string': file:components/tryghost-nql-string-0.0.0.tgz
78
78
  '@tryghost/parse-email-address': file:components/tryghost-parse-email-address-0.0.0.tgz
79
- '@tryghost/kg-utils': file:components/tryghost-kg-utils-1.1.4.tgz
80
79
  ghost-storage-base: file:components/ghost-storage-base-3.0.0.tgz
81
80
  '@tryghost/kg-converters': file:components/tryghost-kg-converters-1.2.5.tgz
81
+ '@tryghost/kg-card-factory': file:components/tryghost-kg-card-factory-5.2.4.tgz
82
82
  '@tryghost/kg-clean-basic-html': file:components/tryghost-kg-clean-basic-html-4.3.4.tgz
83
83
  '@tryghost/kg-markdown-html-renderer': file:components/tryghost-kg-markdown-html-renderer-7.2.4.tgz
84
84
  '@tryghost/kg-default-nodes': file:components/tryghost-kg-default-nodes-2.2.0.tgz
85
85
  '@tryghost/kg-default-cards': file:components/tryghost-kg-default-cards-10.3.5.tgz
86
86
  '@tryghost/kg-default-transforms': file:components/tryghost-kg-default-transforms-1.3.4.tgz
87
- '@tryghost/kg-lexical-html-renderer': file:components/tryghost-kg-lexical-html-renderer-1.5.0.tgz
88
87
  '@tryghost/kg-html-to-lexical': file:components/tryghost-kg-html-to-lexical-1.4.0.tgz
88
+ '@tryghost/kg-lexical-html-renderer': file:components/tryghost-kg-lexical-html-renderer-1.5.0.tgz
89
89
 
90
90
  packageExtensionsChecksum: sha256-gFsvptlcVXY90ntXWh9ANUP1/LYyeqXjWoDGw6BCfOY=
91
91
 
@@ -558,6 +558,9 @@ importers:
558
558
  stripe:
559
559
  specifier: 8.222.0
560
560
  version: 8.222.0
561
+ temporal-polyfill:
562
+ specifier: 0.3.2
563
+ version: 0.3.2
561
564
  terser:
562
565
  specifier: 5.48.0
563
566
  version: 5.48.0
@@ -1391,11 +1394,11 @@ packages:
1391
1394
  version: 0.0.0
1392
1395
 
1393
1396
  '@tryghost/adapter-base-scheduling@file:components/tryghost-adapter-base-scheduling-0.2.2.tgz':
1394
- resolution: {integrity: sha512-CD40gLA91netEC58r5wnPwQzcpbzYpgWJmpf+xvtDWDM7KsWybsfPz503RluPbF52tAMjOCPYvj+I8ZXNL8eUw==, tarball: file:components/tryghost-adapter-base-scheduling-0.2.2.tgz}
1397
+ resolution: {integrity: sha512-i1kaVr13yLTqciCZCUtHatxOf0yCG6Fc2lZb+O9nZzxV2P3torpvhInZRz0qZ4czNh9X5c8KUQygzsVeWRZNqw==, tarball: file:components/tryghost-adapter-base-scheduling-0.2.2.tgz}
1395
1398
  version: 0.2.2
1396
1399
 
1397
1400
  '@tryghost/adapter-base-sso@file:components/tryghost-adapter-base-sso-0.1.2.tgz':
1398
- resolution: {integrity: sha512-CE5TpgSrYnP3n4eNKuQ4OJdweyU0tRNvnlfmuwZ56a4ZYNksLcTYWY6b/Sg0oMC94g/aBoXxwx+eXCEuVONHQw==, tarball: file:components/tryghost-adapter-base-sso-0.1.2.tgz}
1401
+ resolution: {integrity: sha512-kRcMtxlPyGd1AfJOAIRS5/norqLTBs5oHwQlTr4kONvCN7dOGZqk0Woi5tuyMbdkILmwjOnRAVmamIyZGpV63A==, tarball: file:components/tryghost-adapter-base-sso-0.1.2.tgz}
1399
1402
  version: 0.1.2
1400
1403
 
1401
1404
  '@tryghost/admin-api-schema@file:components/tryghost-admin-api-schema-0.0.0.tgz':
@@ -1507,7 +1510,7 @@ packages:
1507
1510
  resolution: {integrity: sha512-ffxWIJ8bGBZS2d/NkFfOgqWEkd1LoqT9AIEqdBTvlDm3jDMqu585IbIluTddrnZIIGgKJNi5+lyFfjBj5z1CAg==}
1508
1511
 
1509
1512
  '@tryghost/i18n@file:components/tryghost-i18n-0.0.0.tgz':
1510
- resolution: {integrity: sha512-Oub2nUWVghw6gfdWVp6LN+qzR0zzMEJqHlEIKb/zxv+VoLL4cevTavbV0fjFGLR0SwHKSEEG0YxJrKDlkBu6Rg==, tarball: file:components/tryghost-i18n-0.0.0.tgz}
1513
+ resolution: {integrity: sha512-rxWoxVT0AWBe09hb5OJwOoCaajAGeSBAOPoYozrDKEbWdiq+VYbW5wQRt2+1YJhufz9vuKJlWy5fs/J2PcpZlg==, tarball: file:components/tryghost-i18n-0.0.0.tgz}
1511
1514
  version: 0.0.0
1512
1515
 
1513
1516
  '@tryghost/image-transform@1.4.17':
@@ -1536,7 +1539,7 @@ packages:
1536
1539
  engines: {node: ^22.13.1 || ^24.0.0}
1537
1540
 
1538
1541
  '@tryghost/kg-default-nodes@file:components/tryghost-kg-default-nodes-2.2.0.tgz':
1539
- resolution: {integrity: sha512-+7HiqaLukYeGKqMnt/d15lzPnlfwvt94V2ID/NSplzxi8V6FjlcAnpTr56AaRE8+6eafAMWy+N7RBKSIFV2fMA==, tarball: file:components/tryghost-kg-default-nodes-2.2.0.tgz}
1542
+ resolution: {integrity: sha512-M+hCAHuNw+qP9P/FpbUp/4eVG49tNR2LT4k9RMfPEvRzColewitY4Xq/BKsNGhTqXlR4pV2TOr9PtLL9XEwWTA==, tarball: file:components/tryghost-kg-default-nodes-2.2.0.tgz}
1540
1543
  version: 2.2.0
1541
1544
  engines: {node: ^22.22.2 || ^24.15.0}
1542
1545
 
@@ -1545,12 +1548,12 @@ packages:
1545
1548
  version: 1.3.4
1546
1549
 
1547
1550
  '@tryghost/kg-html-to-lexical@file:components/tryghost-kg-html-to-lexical-1.4.0.tgz':
1548
- resolution: {integrity: sha512-oWAF0rtIZMU2i1cZz83GhJwIt/bc2TJh+VKpCo0MU0l1yhlQo1UcW7XWxTUKWR0d/iM7cqL+lRhCBHFe8Fm1nw==, tarball: file:components/tryghost-kg-html-to-lexical-1.4.0.tgz}
1551
+ resolution: {integrity: sha512-ZzRiFk6hE0WJerp7pa6pMSp4vDRKWLnviRuisnb7rcEdh1hQwq7zRcaSxMJk6lp/KVF6+uwgkeeNcIl3UDTzFQ==, tarball: file:components/tryghost-kg-html-to-lexical-1.4.0.tgz}
1549
1552
  version: 1.4.0
1550
1553
  engines: {node: ^22.22.2 || ^24.15.0}
1551
1554
 
1552
1555
  '@tryghost/kg-lexical-html-renderer@file:components/tryghost-kg-lexical-html-renderer-1.5.0.tgz':
1553
- resolution: {integrity: sha512-+JGxNt0ktsrCje6kBvbwzcVuaNTbUaJ7Ia3rTaCJd0qk614BWLZmr9dhT2G6KtRWaMo5SXIr+MnwRmmkH9mw+w==, tarball: file:components/tryghost-kg-lexical-html-renderer-1.5.0.tgz}
1556
+ resolution: {integrity: sha512-zjeo3FjPEil+TLE635IicGBbjsA8qbv1JGlpO5GL7mFf7jH7OVnBJEdNzWOh2WIjJIBXagivb4UPgFzU8fFtEg==, tarball: file:components/tryghost-kg-lexical-html-renderer-1.5.0.tgz}
1554
1557
  version: 1.5.0
1555
1558
  engines: {node: ^22.22.2 || ^24.15.0}
1556
1559
 
@@ -4987,6 +4990,12 @@ packages:
4987
4990
  teex@1.0.1:
4988
4991
  resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==}
4989
4992
 
4993
+ temporal-polyfill@0.3.2:
4994
+ resolution: {integrity: sha512-TzHthD/heRK947GNiSu3Y5gSPpeUDH34+LESnfsq8bqpFhsB79HFBX8+Z834IVX68P3EUyRPZK5bL/1fh437Eg==}
4995
+
4996
+ temporal-spec@0.3.1:
4997
+ resolution: {integrity: sha512-B4TUhezh9knfSIMwt7RVggApDRJZo73uZdj8AacL2mZ8RP5KtLianh2MXxL06GN9ESYiIsiuoLQhgVfwe55Yhw==}
4998
+
4990
4999
  terser@5.48.0:
4991
5000
  resolution: {integrity: sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==}
4992
5001
  engines: {node: '>=10'}
@@ -10566,6 +10575,12 @@ snapshots:
10566
10575
  - bare-abort-controller
10567
10576
  - react-native-b4a
10568
10577
 
10578
+ temporal-polyfill@0.3.2:
10579
+ dependencies:
10580
+ temporal-spec: 0.3.1
10581
+
10582
+ temporal-spec@0.3.1: {}
10583
+
10569
10584
  terser@5.48.0:
10570
10585
  dependencies:
10571
10586
  '@jridgewell/source-map': 0.3.11
@@ -12,7 +12,6 @@ catalog:
12
12
  '@codemirror/state': 6.7.1
13
13
  '@codemirror/theme-one-dark': 6.1.3
14
14
  '@codemirror/view': 6.43.6
15
- '@ebay/nice-modal-react': 1.2.13
16
15
  '@eslint/compat': 2.1.0
17
16
  '@eslint/js': 9.39.5
18
17
  '@faker-js/faker': 10.5.0
@@ -258,24 +257,24 @@ overrides:
258
257
  '@tryghost/adapter-base-cache': file:components/tryghost-adapter-base-cache-0.2.0.tgz
259
258
  '@tryghost/adapter-base-route-settings': file:components/tryghost-adapter-base-route-settings-0.0.0.tgz
260
259
  '@tryghost/adapter-base-jobs': file:components/tryghost-adapter-base-jobs-0.0.0.tgz
260
+ '@tryghost/adapter-base-sso': file:components/tryghost-adapter-base-sso-0.1.2.tgz
261
+ '@tryghost/adapter-base-scheduling': file:components/tryghost-adapter-base-scheduling-0.2.2.tgz
261
262
  '@tryghost/custom-field-types': file:components/tryghost-custom-field-types-0.0.0.tgz
262
263
  '@tryghost/admin-api-schema': file:components/tryghost-admin-api-schema-0.0.0.tgz
263
264
  '@tryghost/i18n': file:components/tryghost-i18n-0.0.0.tgz
264
- '@tryghost/adapter-base-scheduling': file:components/tryghost-adapter-base-scheduling-0.2.2.tgz
265
- '@tryghost/adapter-base-sso': file:components/tryghost-adapter-base-sso-0.1.2.tgz
266
- '@tryghost/kg-card-factory': file:components/tryghost-kg-card-factory-5.2.4.tgz
265
+ '@tryghost/kg-utils': file:components/tryghost-kg-utils-1.1.4.tgz
267
266
  '@tryghost/nql-string': file:components/tryghost-nql-string-0.0.0.tgz
268
267
  '@tryghost/parse-email-address': file:components/tryghost-parse-email-address-0.0.0.tgz
269
- '@tryghost/kg-utils': file:components/tryghost-kg-utils-1.1.4.tgz
270
268
  ghost-storage-base: file:components/ghost-storage-base-3.0.0.tgz
271
269
  '@tryghost/kg-converters': file:components/tryghost-kg-converters-1.2.5.tgz
270
+ '@tryghost/kg-card-factory': file:components/tryghost-kg-card-factory-5.2.4.tgz
272
271
  '@tryghost/kg-clean-basic-html': file:components/tryghost-kg-clean-basic-html-4.3.4.tgz
273
272
  '@tryghost/kg-markdown-html-renderer': file:components/tryghost-kg-markdown-html-renderer-7.2.4.tgz
274
273
  '@tryghost/kg-default-nodes': file:components/tryghost-kg-default-nodes-2.2.0.tgz
275
274
  '@tryghost/kg-default-cards': file:components/tryghost-kg-default-cards-10.3.5.tgz
276
275
  '@tryghost/kg-default-transforms': file:components/tryghost-kg-default-transforms-1.3.4.tgz
277
- '@tryghost/kg-lexical-html-renderer': file:components/tryghost-kg-lexical-html-renderer-1.5.0.tgz
278
276
  '@tryghost/kg-html-to-lexical': file:components/tryghost-kg-html-to-lexical-1.4.0.tgz
277
+ '@tryghost/kg-lexical-html-renderer': file:components/tryghost-kg-lexical-html-renderer-1.5.0.tgz
279
278
  packageExtensions:
280
279
  '@doist/react-interpolate@2.2.1':
281
280
  dependencies: