ghost 6.61.0 → 6.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (619) hide show
  1. package/components/ghost-storage-base-3.0.0.tgz +0 -0
  2. package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
  3. package/components/tryghost-adapter-base-jobs-0.0.0.tgz +0 -0
  4. package/components/tryghost-adapter-base-redirects-0.0.0.tgz +0 -0
  5. package/components/tryghost-adapter-base-route-settings-0.0.0.tgz +0 -0
  6. package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
  7. package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
  8. package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
  9. package/components/tryghost-checkout-0.0.0.tgz +0 -0
  10. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  11. package/components/tryghost-kg-card-factory-5.2.4.tgz +0 -0
  12. package/components/tryghost-kg-clean-basic-html-4.3.4.tgz +0 -0
  13. package/components/tryghost-kg-converters-1.2.5.tgz +0 -0
  14. package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
  15. package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
  16. package/components/tryghost-kg-default-transforms-1.3.4.tgz +0 -0
  17. package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
  18. package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
  19. package/components/tryghost-kg-markdown-html-renderer-7.2.4.tgz +0 -0
  20. package/components/tryghost-kg-utils-1.1.4.tgz +0 -0
  21. package/components/tryghost-limit-service-0.0.0.tgz +0 -0
  22. package/components/tryghost-metafield-types-0.0.0.tgz +0 -0
  23. package/components/tryghost-nql-string-0.0.0.tgz +0 -0
  24. package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
  25. package/content/settings/README.md +1 -1
  26. package/content/themes/casper/.gitignore +28 -0
  27. package/content/themes/casper/assets/built/casper.js +1 -1
  28. package/content/themes/casper/assets/built/screen.css +1 -1
  29. package/content/themes/casper/assets/css/screen.css +2 -1
  30. package/content/themes/casper/assets/js/lightbox.js +63 -46
  31. package/content/themes/casper/package.json +6 -6
  32. package/content/themes/casper/page.hbs +1 -0
  33. package/content/themes/casper/post.hbs +1 -0
  34. package/content/themes/source/.gitignore +28 -0
  35. package/content/themes/source/assets/built/screen.css +1 -1
  36. package/content/themes/source/assets/built/source.js +1 -1
  37. package/content/themes/source/assets/css/screen.css +2 -1
  38. package/content/themes/source/assets/js/lightbox.js +62 -45
  39. package/content/themes/source/assets/js/main.js +2 -2
  40. package/content/themes/source/package.json +4 -4
  41. package/content/themes/source/partials/feature-image.hbs +1 -0
  42. package/content/themes/source/partials/post-card.hbs +1 -1
  43. package/core/boot.js +61 -27
  44. package/core/built/admin/assets/Combination-B0l4MKVh.js +41 -0
  45. package/core/built/admin/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
  46. package/core/built/admin/assets/InterVariable-Italic-FCBEiFp6.woff2 +0 -0
  47. package/core/built/admin/assets/{about-Bve7IJS2.js → about-C1C3s5-g.js} +1 -1
  48. package/core/built/admin/assets/accordion-CxGsDKwa.js +1 -0
  49. package/core/built/admin/assets/account-migration-CbUhW6gk.js +1 -0
  50. package/core/built/admin/assets/activitypub/{account-migration-C-aej4x_.js → account-migration-KA6Jjf9L.js} +16 -16
  51. package/core/built/admin/assets/activitypub/activitypub.js +9 -9
  52. package/core/built/admin/assets/activitypub/{avatar-DLPL3Abs.js → avatar-DVJF5bxP.js} +2 -2
  53. package/core/built/admin/assets/activitypub/{avatar-flipboard-C9iDY-QV.js → avatar-flipboard-csQaNeYK.js} +2 -2
  54. package/core/built/admin/assets/activitypub/{bluesky-sharing-BXkA5mqV.js → bluesky-sharing-C7nTDMvw.js} +37 -37
  55. package/core/built/admin/assets/activitypub/{content-formatters-CHcyMFk4.js → content-formatters-CLcjaBwV.js} +4 -4
  56. package/core/built/admin/assets/activitypub/{copy-DIAOQoCZ.js → copy-DcOh8kXw.js} +2 -2
  57. package/core/built/admin/assets/activitypub/{domain-B3ihkPde.js → domain-fZ-X8i4-.js} +121 -121
  58. package/core/built/admin/assets/activitypub/{edit-profile-DsZM3rTX.js → edit-profile-BqMLQV88.js} +40 -40
  59. package/core/built/admin/assets/activitypub/{explore-BodNrZgR.js → explore-B4yPoP8E.js} +27 -27
  60. package/core/built/admin/assets/activitypub/{feed-PwH1iJ84.js → feed-BRC_mvAe.js} +51 -51
  61. package/core/built/admin/assets/activitypub/{field-D06-kmOJ.js → field-COacNgOt.js} +3 -3
  62. package/core/built/admin/assets/activitypub/{hash-Bm3WxYN4.js → hash-C7u-irQQ.js} +2 -2
  63. package/core/built/admin/assets/activitypub/inbox-BW-yvUoN.js +1284 -0
  64. package/core/built/admin/assets/activitypub/{inbox-d8oJRTf4.js → inbox-CbTTdDQ3.js} +2 -2
  65. package/core/built/admin/assets/activitypub/label-kPMmYI7l.js +16 -0
  66. package/core/built/admin/assets/activitypub/layout-BL4_jtuV.js +1 -0
  67. package/core/built/admin/assets/activitypub/{moderation-D1Yapsod.js → moderation-CuidJzc0.js} +91 -91
  68. package/core/built/admin/assets/activitypub/{note-C5zjqq5C.js → note-CAMRRSqD.js} +24 -24
  69. package/core/built/admin/assets/activitypub/{notifications-B9p8eCHD.js → notifications-BmNlXGgp.js} +51 -51
  70. package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-Bqg7fh_L.js} +2 -2
  71. package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-Dmun9jr_.js} +2 -2
  72. package/core/built/admin/assets/activitypub/{preferences-BCqUdC3v.js → preferences--oH19wf9.js} +1519 -1519
  73. package/core/built/admin/assets/activitypub/{profile-BRCWoFem.js → profile-DH_tQx2D.js} +185 -185
  74. package/core/built/admin/assets/activitypub/{reply-DYK5vVqb.js → reply-Cap9PxSH.js} +2 -2
  75. package/core/built/admin/assets/activitypub/{routes-BSXT992i.js → routes-DdyY9uFF.js} +744 -735
  76. package/core/built/admin/assets/activitypub/{separator-BbQqTm-p.js → separator-CAxxu8VV.js} +3 -3
  77. package/core/built/admin/assets/activitypub/settings-B6EEcVkW.js +315 -0
  78. package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-BYps63oh.js} +2 -2
  79. package/core/built/admin/assets/activitypub/{step-1-B-YfsVeO.js → step-1-CKjR2KAm.js} +6 -6
  80. package/core/built/admin/assets/activitypub/{step-2-DtPQzlTH.js → step-2-B6PKfOUQ.js} +6 -6
  81. package/core/built/admin/assets/activitypub/{step-3-D6BFMXL_.js → step-3-C-qBbcUo.js} +11 -11
  82. package/core/built/admin/assets/activitypub/{tabs-GpNecvfB.js → tabs-DLhZtVde.js} +306 -306
  83. package/core/built/admin/assets/activitypub/{topic-filter-BPDeQQys.js → topic-filter-DsUOuu0k.js} +3 -3
  84. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-BoVOxXkV.js → use-activity-pub-queries-CX9snsLs.js} +3 -3
  85. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Bmk5h4lW.js → use-navigate-with-base-path-DsJTGDSS.js} +988 -959
  86. package/core/built/admin/assets/activitypub/{use-reply-chain-data-wVBX7swM.js → use-reply-chain-data-AJi9zkzm.js} +30 -30
  87. package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-inweyKL5.js} +192 -164
  88. package/core/built/admin/assets/activitypub/{x-DbQZOLiI.js → x-DR8AT3-4.js} +2 -2
  89. package/core/built/admin/assets/add-integration-modal-BT_onDJy.js +1 -0
  90. package/core/built/admin/assets/add-newsletter-modal-Cx1kQpiY.js +1 -0
  91. package/core/built/admin/assets/add-recommendation-modal-B5nvAhvr.js +1 -0
  92. package/core/built/admin/assets/analytics-DjoJWPI7.js +1 -0
  93. package/core/built/admin/assets/{announcement-bar-modal-DM3cYOpo.js → announcement-bar-modal-Dwd0EGFP.js} +1 -1
  94. package/core/built/admin/assets/{api-keys-3-0vJC3Y.js → api-keys-BGPzLHzA.js} +1 -1
  95. package/core/built/admin/assets/{api-keys-BLm2NDBh.js → api-keys-BoeacM-s.js} +1 -1
  96. package/core/built/admin/assets/{audience-9mwU5TW6.js → audience-ceV3XVHq.js} +1 -1
  97. package/core/built/admin/assets/automated-emails-BLesE41L.js +1 -0
  98. package/core/built/admin/assets/{automations-sAcJ1334.js → automations-BN4u3GR8.js} +1 -1
  99. package/core/built/admin/assets/automations-C-ZTUwW3.js +1 -0
  100. package/core/built/admin/assets/bluesky-sharing-vzh-oPXL.js +1 -0
  101. package/core/built/admin/assets/{breadcrumb-DLiqCyFc.js → breadcrumb-CaLk2b7D.js} +1 -1
  102. package/core/built/admin/assets/{button-B2jcu6bk.js → button-Dvcv1QSR.js} +1 -1
  103. package/core/built/admin/assets/calendar-Bl9RLcZX.js +1 -0
  104. package/core/built/admin/assets/{chart-helpers-Fo3bUL3K.js → chart-helpers-FHywU0pj.js} +1 -1
  105. package/core/built/admin/assets/{checkbox-BfKktMph.js → checkbox-BtayFtjg.js} +1 -1
  106. package/core/built/admin/assets/chunk.254.035b85ec456ebbd7336b.js +440 -0
  107. package/core/built/admin/assets/{chunk.524.60ca4692d91c6022042f.js → chunk.524.e6975095fccdf22d90f8.js} +5 -5
  108. package/core/built/admin/assets/{chunk.582.525c7617c2d9e94c940a.js → chunk.582.98b485f9b2802f540897.js} +6 -6
  109. package/core/built/admin/assets/{chunk.492.f24d855d7e3f3aad261c.js → chunk.901.4ccc639821020230bcca.js} +9949 -7921
  110. package/core/built/admin/assets/{code-editor-view-DCQJxsfU.js → code-editor-view-C3ZfoF1X.js} +1 -1
  111. package/core/built/admin/assets/{code-editor-view-CYVu4EW6.js → code-editor-view-CAyRWy1s.js} +1 -1
  112. package/core/built/admin/assets/color-picker-G4kGR7rp.js +3 -0
  113. package/core/built/admin/assets/color-picker-field-DQFVTNnT.js +1 -0
  114. package/core/built/admin/assets/combobox-BnYzgEB4.js +1 -0
  115. package/core/built/admin/assets/command-C_vyTikI.js +1 -0
  116. package/core/built/admin/assets/comments-aBrxfnZf.js +1 -0
  117. package/core/built/admin/assets/{config-DOMQDZGZ.js → config-kSHvwdTG.js} +1 -1
  118. package/core/built/admin/assets/confirmation-context-DwXX_Y5h.js +1 -0
  119. package/core/built/admin/assets/{content-api-modal-CyQEC3fr.js → content-api-modal-D2G0nJP6.js} +1 -1
  120. package/core/built/admin/assets/context-menu-DOVB6yaz.js +1 -0
  121. package/core/built/admin/assets/{copy-field-B3M1s78L.js → copy-field-DCJwh9qf.js} +1 -1
  122. package/core/built/admin/assets/create-ghost-browse-value-source-5C53jJaX.js +1 -0
  123. package/core/built/admin/assets/custom-field-type-option-BAuW0F-E.js +1 -0
  124. package/core/built/admin/assets/custom-integration-modal-AbJGVyKc.js +1 -0
  125. package/core/built/admin/assets/{date-range-select-DD2RKkgB.js → date-range-select-BY3K-ukj.js} +1 -1
  126. package/core/built/admin/assets/design-and-theme-modal-BvEy4_pC.js +2 -0
  127. package/core/built/admin/assets/dirty-confirm-dialog-DVPuGz3U.js +1 -0
  128. package/core/built/admin/assets/{disabled-sources-indicator-Cvy47bE2.js → disabled-sources-indicator-Cy7Zp4c8.js} +1 -1
  129. package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
  130. package/core/built/admin/assets/domain-Dl61QGuk.js +1 -0
  131. package/core/built/admin/assets/dropzone-Dtz5Rmjt.js +5 -0
  132. package/core/built/admin/assets/edit-profile-DNJSMDwm.js +1 -0
  133. package/core/built/admin/assets/editor-DbAen9zf.js +8 -0
  134. package/core/built/admin/assets/editor-screen-BFWThIai.js +26 -0
  135. package/core/built/admin/assets/email-sending-status-context-CWDOD1FN.js +1 -0
  136. package/core/built/admin/assets/email-sending-status-provider-DCPkDICt.js +1 -0
  137. package/core/built/admin/assets/emails-vFMk4yYl.js +1 -0
  138. package/core/built/admin/assets/{embed-signup-form-modal-DeBMLxlL.js → embed-signup-form-modal-DGqsORxS.js} +1 -1
  139. package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
  140. package/core/built/admin/assets/explore-nnRr1Fja.js +1 -0
  141. package/core/built/admin/assets/feature-flag-overrides-context-DQjdJFAk.js +1 -0
  142. package/core/built/admin/assets/feature-image-placeholder-BrIHmPs8.js +1 -0
  143. package/core/built/admin/assets/feed-BNUcNu-W.js +1 -0
  144. package/core/built/admin/assets/feedback-DJ4Zb9rZ.js +1 -0
  145. package/core/built/admin/assets/{field-Cj8lmDOo.js → field-C93_Mg6j.js} +1 -1
  146. package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
  147. package/core/built/admin/assets/filter-sources-CGJb4C5r.js +1 -0
  148. package/core/built/admin/assets/filters--kKP-EC8.js +1 -0
  149. package/core/built/admin/assets/filters-DxA_a4FP.js +1 -0
  150. package/core/built/admin/assets/first-promoter-modal-BYDtrz2S.js +1 -0
  151. package/core/built/admin/assets/focus-koenig-editor-on-bottom-click-BbSnGOtK.js +1 -0
  152. package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8fd5bb799356bbefb254210ba7e1236d.css} +1 -1
  153. package/core/built/admin/assets/{ghost-3894eedcc6968f658578c0abfe942aab.js → ghost-b4e8a403baba61905cd7560e30b9732d.js} +63 -44
  154. package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-cac0cb2d5bb78e9bd14d8d1c2768ed45.css} +1 -1
  155. package/core/built/admin/assets/gift-link-modal-B7u5bD4e.js +1 -0
  156. package/core/built/admin/assets/{gift-links-DLDS7ljO.js → gift-links-CfLSnst2.js} +1 -1
  157. package/core/built/admin/assets/{growth-D6mhcx3q.js → growth-Cd1uO9d2.js} +1 -1
  158. package/core/built/admin/assets/growth-aG32xfdE.js +3 -0
  159. package/core/built/admin/assets/history-modal-Df8lW8h-.js +1 -0
  160. package/core/built/admin/assets/hooks-Cy_-oZ4o.js +2 -0
  161. package/core/built/admin/assets/{html-field-C8qVGGC1.js → html-field-DA4eU7eq.js} +1 -1
  162. package/core/built/admin/assets/{images-h8VZEQ9k.js → images-KXmyO3Ss.js} +1 -1
  163. package/core/built/admin/assets/{inbox-BYd1M06Q.js → inbox-gJHG7_xd.js} +14 -14
  164. package/core/built/admin/assets/index-BHHXtR5C.css +2 -0
  165. package/core/built/admin/assets/index-CgMCwsxN.js +4 -0
  166. package/core/built/admin/assets/index.es-CY6-yuw9.js +1 -0
  167. package/core/built/admin/assets/{input-group-D8sCXRF5.js → input-group-BE8rM2y1.js} +1 -1
  168. package/core/built/admin/assets/{integrations-Bjbu86Z0.js → integrations-B4kuRBFY.js} +1 -1
  169. package/core/built/admin/assets/invite-user-modal-B4CuNcx4.js +1 -0
  170. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
  171. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
  172. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  173. package/core/built/admin/assets/{koenig-lexical-_-IsVI7E.js → koenig-lexical-CGXb0F8o.js} +3 -3
  174. package/core/built/admin/assets/koenig-loader-BeM5rFPX.js +2 -0
  175. package/core/built/admin/assets/{kpi-card-DZQk_0W8.js → kpi-card-B21aToe8.js} +1 -1
  176. package/core/built/admin/assets/{kpi-card-DW_2y3ug.js → kpi-card-pz6Wv4Ae.js} +1 -1
  177. package/core/built/admin/assets/{kpi-helpers-PueTKuA6.js → kpi-helpers-Dq5jelmP.js} +1 -1
  178. package/core/built/admin/assets/{kpi-tabs-CojDs-Qz.js → kpi-tabs-DEZHpKUt.js} +1 -1
  179. package/core/built/admin/assets/{label-DjbT91GM.js → label-OLCzze8N.js} +1 -1
  180. package/core/built/admin/assets/label-picker-BigOvMPV.js +1 -0
  181. package/core/built/admin/assets/{labels-CH3Kn8RV.js → labels-Dr0SgUQD.js} +1 -1
  182. package/core/built/admin/assets/layout-DUTL8SH5.js +1 -0
  183. package/core/built/admin/assets/lib-7QPTI0FS.js +1 -0
  184. package/core/built/admin/assets/link-helpers-BRAg9SCj.js +1 -0
  185. package/core/built/admin/assets/links-BDHPTlyj.js +1 -0
  186. package/core/built/admin/assets/member-custom-fields-TRTHCAz9.js +1 -0
  187. package/core/built/admin/assets/member-detail-b6dRwc3C.js +1 -0
  188. package/core/built/admin/assets/members-Czt5lJSc.js +4 -0
  189. package/core/built/admin/assets/moderation-ZWefD9uH.js +1 -0
  190. package/core/built/admin/assets/{multi-select-combobox-B6LiRzDO.js → multi-select-combobox-CT13MTo-.js} +1 -1
  191. package/core/built/admin/assets/navigation-modal-C8FEhBK5.js +1 -0
  192. package/core/built/admin/assets/newsletter-5VYW4RyJ.js +1 -0
  193. package/core/built/admin/assets/newsletter-detail-modal-ChjC0ZqH.js +1 -0
  194. package/core/built/admin/assets/{newsletter-emails-CFeLlt4z.js → newsletter-emails-DZH6I-PY.js} +1 -1
  195. package/core/built/admin/assets/newsletters-DOC9KBcX.js +1 -0
  196. package/core/built/admin/assets/newsletters-Rq1M3GD-.js +1 -0
  197. package/core/built/admin/assets/note-DIV-Pojr.js +1 -0
  198. package/core/built/admin/assets/notifications-s20-H49V.js +1 -0
  199. package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
  200. package/core/built/admin/assets/{offers-9J1CSiLy.js → offers--e2nGvkW.js} +1 -1
  201. package/core/built/admin/assets/offers-container-modal-BmG5M5Tv.js +1 -0
  202. package/core/built/admin/assets/onboarding-CUuy9unR.js +1 -0
  203. package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-pXyct0Jm.js} +1 -1
  204. package/core/built/admin/assets/{onboarding-route-Dmc4IPm3.js → onboarding-route-CK4pcXoR.js} +1 -1
  205. package/core/built/admin/assets/overview-CaPsciMs.js +1 -0
  206. package/core/built/admin/assets/overview-a8GfcsKX.js +1 -0
  207. package/core/built/admin/assets/{page-header-BR_nbIPp.js → page-header-DM_KyoFI.js} +1 -1
  208. package/core/built/admin/assets/pagemenu-vgZVUVKR.js +1 -0
  209. package/core/built/admin/assets/pages-CjDY2CBI.js +1 -0
  210. package/core/built/admin/assets/pages-route-BzKZYdV5.js +1 -0
  211. package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
  212. package/core/built/admin/assets/{pintura-modal-BR9hEvS8.js → pintura-modal-DExCF1ii.js} +1 -1
  213. package/core/built/admin/assets/portal-frame-Cqanidq4.js +1 -0
  214. package/core/built/admin/assets/portal-modal-oinBgA27.js +1 -0
  215. package/core/built/admin/assets/post-analytics-C5oJ1dWV.js +1 -0
  216. package/core/built/admin/assets/post-analytics-header-OATo3X_r.js +1 -0
  217. package/core/built/admin/assets/post-analytics-provider-tOpIVGT5.js +1 -0
  218. package/core/built/admin/assets/post-helpers-C88JBa4D.js +1 -0
  219. package/core/built/admin/assets/post-share-modal-DvhC1XgV.js +1 -0
  220. package/core/built/admin/assets/post-utils-DKF4mfuo.js +1 -0
  221. package/core/built/admin/assets/posts-list-screen-o4ZjbgS3.js +2 -0
  222. package/core/built/admin/assets/posts-pCPrhQeR.js +1 -0
  223. package/core/built/admin/assets/posts-route-9F--xdIb.js +1 -0
  224. package/core/built/admin/assets/preferences--vNubsqD.js +5 -0
  225. package/core/built/admin/assets/{preview-modal-C-BL-F9k.js → preview-modal-YYbzlYdO.js} +1 -1
  226. package/core/built/admin/assets/profile-BllKV3dR.js +1 -0
  227. package/core/built/admin/assets/{radio-group-Bgz60i81.js → radio-group-DL8GI8rt.js} +1 -1
  228. package/core/built/admin/assets/{referrers-CnhCMWCs.js → referrers-D8oHPmDB.js} +1 -1
  229. package/core/built/admin/assets/router-provider-BSvTXgZY.js +1 -0
  230. package/core/built/admin/assets/schemas-BoYdB6YU.js +64 -0
  231. package/core/built/admin/assets/select-v5YbA3Mw.js +1 -0
  232. package/core/built/admin/assets/settings-PEsZupw1.js +4 -0
  233. package/core/built/admin/assets/{settings-breadcrumbs-CyP_9zTo.js → settings-breadcrumbs-NwPnCTC7.js} +1 -1
  234. package/core/built/admin/assets/settings-u_s1CRkr.js +1 -0
  235. package/core/built/admin/assets/share-modal-SskCmVGL.js +1 -0
  236. package/core/built/admin/assets/slack-modal-XxSJiYgo.js +1 -0
  237. package/core/built/admin/assets/{sort-button-Cc-Z96sA.js → sort-button-Cx1KtINE.js} +1 -1
  238. package/core/built/admin/assets/{source-icon-v6PUnmyM.js → source-icon-Bdp9Im_5.js} +1 -1
  239. package/core/built/admin/assets/stats-D9PDLS3x.js +1 -0
  240. package/core/built/admin/assets/stats-view-W2g6Jsd-.js +1 -0
  241. package/core/built/admin/assets/{step-1-DSRp2vBj.js → step-1-BQYzvBzr.js} +1 -1
  242. package/core/built/admin/assets/{step-2-COqv2g0u.js → step-2-xES32xJV.js} +1 -1
  243. package/core/built/admin/assets/{step-3-6W1NMVQc.js → step-3-DA_XK5kW.js} +2 -2
  244. package/core/built/admin/assets/{stripe-button-D2K42Uty.js → stripe-button-CVsLHelt.js} +1 -1
  245. package/core/built/admin/assets/stripe-connect-modal-ClmLOMGS.js +1 -0
  246. package/core/built/admin/assets/style-Wd9nQubI.css +1 -0
  247. package/core/built/admin/assets/{table-B2pIKjVh.js → table-BenqVupI.js} +1 -1
  248. package/core/built/admin/assets/{tabs-SaW_UT-Q.js → tabs-eBBlxPp8.js} +1 -1
  249. package/core/built/admin/assets/tag-detail-Ce8Se2qd.js +2 -0
  250. package/core/built/admin/assets/tag-picker-C3UR-uJ-.js +1 -0
  251. package/core/built/admin/assets/tags-B-kJxCs7.js +1 -0
  252. package/core/built/admin/assets/{tags-zTFiKRpb.js → tags-ChfdwJyS.js} +1 -1
  253. package/core/built/admin/assets/testimonials-modal-9Q6fT06V.js +1 -0
  254. package/core/built/admin/assets/tier-detail-modal-CDyYdqK7.js +1 -0
  255. package/core/built/admin/assets/tiers-BCpIOGQr.js +1 -0
  256. package/core/built/admin/assets/{toggle-group-EM9WpESu.js → toggle-group-CviIkyok.js} +1 -1
  257. package/core/built/admin/assets/{topic-filter-DY4gNHn2.js → topic-filter-I2jCBGxm.js} +1 -1
  258. package/core/built/admin/assets/{transistor-modal-CpyPG-MH.js → transistor-modal-p53u3W8y.js} +1 -1
  259. package/core/built/admin/assets/{trend-badge-ByMkuAuH.js → trend-badge-CideVzQd.js} +1 -1
  260. package/core/built/admin/assets/{unsplash-modal-Cv2Q6GtY.js → unsplash-modal-DY8UcKcE.js} +1 -1
  261. package/core/built/admin/assets/{use-analytics-data-CHvjMYuT.js → use-analytics-data-DAIGcr2f.js} +1 -1
  262. package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
  263. package/core/built/admin/assets/{use-check-theme-limit-error-Qv4SVXqw.js → use-check-theme-limit-error-DRUjK4YM.js} +1 -1
  264. package/core/built/admin/assets/use-filter-params-JkZhIS8L.js +1 -0
  265. package/core/built/admin/assets/{use-filterable-api-CzXcpUh8.js → use-filterable-api-BVEVMrhZ.js} +1 -1
  266. package/core/built/admin/assets/use-growth-stats-937CUj6j.js +1 -0
  267. package/core/built/admin/assets/use-host-limits-D0Dv3tKA.js +1 -0
  268. package/core/built/admin/assets/{use-limiter-cwJvsNBo.js → use-limiter-CohWfzvK.js} +1 -1
  269. package/core/built/admin/assets/{use-navigate-with-base-path-BHPA228f.js → use-navigate-with-base-path-BkxcPj5l.js} +1 -1
  270. package/core/built/admin/assets/use-pintura-config-xgytjU35.js +1 -0
  271. package/core/built/admin/assets/{use-pintura-editor-BDBXWUYq.js → use-pintura-editor-CaV1mbfO.js} +1 -1
  272. package/core/built/admin/assets/{use-post-referrers-DbY-mzci.js → use-post-referrers-BCQI7fDg.js} +1 -1
  273. package/core/built/admin/assets/use-reply-chain-data-CYRhoaxY.js +1 -0
  274. package/core/built/admin/assets/{use-router-history-entry-Bg6BhBQQ.js → use-router-history-entry-NOKcd--l.js} +1 -1
  275. package/core/built/admin/assets/{use-setting-group-VM7FQwMY.js → use-setting-group-bLKMwoBT.js} +1 -1
  276. package/core/built/admin/assets/use-settings-navigation-B-qrriKD.js +1 -0
  277. package/core/built/admin/assets/{use-simple-pagination-Dum6Irbs.js → use-simple-pagination-CNPd6Rf6.js} +1 -1
  278. package/core/built/admin/assets/use-staff-users-pRIMIyiW.js +1 -0
  279. package/core/built/admin/assets/use-tinybird-query-CmdbCS9X.js +1 -0
  280. package/core/built/admin/assets/use-tinybird-token-KLne235s.js +1 -0
  281. package/core/built/admin/assets/{use-unsaved-changes-guard-BAy0RANR.js → use-unsaved-changes-guard-7-ug0JdH.js} +1 -1
  282. package/core/built/admin/assets/use-upgrade-route-Dm_qqKr0.js +1 -0
  283. package/core/built/admin/assets/{use-url-input-Df5QzNa7.js → use-url-input-fvp-TpPx.js} +1 -1
  284. package/core/built/admin/assets/user-detail-modal-D3KlGYv-.js +1 -0
  285. package/core/built/admin/assets/users-DVNWrqg9.js +1 -0
  286. package/core/built/admin/assets/{vendor-5753232c7d6ffb3c44e1eb0a02133953.js → vendor-2dd263291938d407802568d3357ec69e.js} +19 -17
  287. package/core/built/admin/assets/{virtual-list-DEx8WgiO.js → virtual-list-CZ3RK2Yf.js} +1 -1
  288. package/core/built/admin/assets/web-ClEJsCAj.js +2 -0
  289. package/core/built/admin/assets/web-X9rdnrtq.js +1 -0
  290. package/core/built/admin/assets/{zapier-modal-Cw3BTBUu.js → zapier-modal-DfVhV17j.js} +1 -1
  291. package/core/built/admin/index.html +23 -27
  292. package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
  293. package/core/frontend/helpers/cancel_link.js +2 -2
  294. package/core/frontend/helpers/pagination.js +2 -2
  295. package/core/frontend/helpers/social_accounts.js +2 -2
  296. package/core/frontend/public/ghost.css +1 -1
  297. package/core/frontend/public/ghost.min.css +1 -1
  298. package/core/frontend/services/sitemap/user-map-generator.js +9 -2
  299. package/core/server/adapters/jobs/InMemoryJobsBackend.js +74 -29
  300. package/core/server/api/endpoints/authentication.js +1 -2
  301. package/core/server/api/endpoints/authors-public.js +15 -5
  302. package/core/server/api/endpoints/emails.js +13 -0
  303. package/core/server/api/endpoints/index.js +10 -2
  304. package/core/server/api/endpoints/mail.js +1 -1
  305. package/core/server/api/endpoints/member-metafields-members.js +23 -0
  306. package/core/server/api/endpoints/member-metafields.js +102 -0
  307. package/core/server/api/endpoints/members-account.js +42 -0
  308. package/core/server/api/endpoints/members.js +4 -4
  309. package/core/server/api/endpoints/newsletters-public.js +10 -1
  310. package/core/server/api/endpoints/pages-public.js +15 -5
  311. package/core/server/api/endpoints/posts-public.js +15 -5
  312. package/core/server/api/endpoints/posts.js +3 -3
  313. package/core/server/api/endpoints/tags-public.js +22 -3
  314. package/core/server/api/endpoints/tiers-checkout-config.js +2 -2
  315. package/core/server/api/endpoints/tiers-public.js +38 -1
  316. package/core/server/api/endpoints/users.js +2 -2
  317. package/core/server/api/endpoints/utils/api-filter-utils.js +170 -3
  318. package/core/server/api/endpoints/utils/public-cache-keys.js +3 -0
  319. package/core/server/api/endpoints/utils/serializers/input/authors.js +2 -0
  320. package/core/server/api/endpoints/utils/serializers/input/members.js +20 -9
  321. package/core/server/api/endpoints/utils/serializers/input/pages.js +2 -0
  322. package/core/server/api/endpoints/utils/serializers/input/posts.js +2 -0
  323. package/core/server/api/endpoints/utils/serializers/input/tags.js +2 -0
  324. package/core/server/api/endpoints/utils/serializers/output/emails.js +7 -0
  325. package/core/server/api/endpoints/utils/serializers/output/index.js +6 -2
  326. package/core/server/api/endpoints/utils/serializers/output/member-metafields.js +18 -0
  327. package/core/server/api/endpoints/utils/serializers/output/members-account.js +19 -0
  328. package/core/server/api/endpoints/utils/serializers/output/members-csv-transform.js +1 -1
  329. package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
  330. package/core/server/api/endpoints/utils/serializers/output/tiers.js +10 -2
  331. package/core/server/api/endpoints/utils/serializers/output/users.js +0 -10
  332. package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
  333. package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
  334. package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
  335. package/core/server/data/exporter/table-lists.js +3 -3
  336. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  337. package/core/server/data/migrations/utils/migrations.js +1 -1
  338. package/core/server/data/migrations/versions/6.53/2026-07-15-20-22-53-add-members-custom-field-values.js +1 -1
  339. package/core/server/data/migrations/versions/6.57/2026-08-04-18-00-00-store-custom-field-values-as-leaf-rows.js +10 -1
  340. package/core/server/data/migrations/versions/6.63/2026-09-03-10-07-03-rename-custom-field-tables-to-metafields.js +169 -0
  341. package/core/server/data/migrations/versions/6.63/2026-09-03-11-03-31-remove-member-custom-field-read-permissions.js +30 -0
  342. package/core/server/data/schema/fixtures/fixtures.json +0 -11
  343. package/core/server/data/schema/lib/default-index-name.js +8 -11
  344. package/core/server/data/schema/schema.js +18 -18
  345. package/core/server/data/seeders/README.md +48 -0
  346. package/core/server/data/tinybird/pipes/mv_hits.pipe +86 -50
  347. package/core/server/lib/db-types/count.js +16 -0
  348. package/core/server/lib/image/image-size.js +24 -0
  349. package/core/server/lib/package-json/parse.js +2 -2
  350. package/core/server/lib/validate-password.js +81 -120
  351. package/core/server/models/action.js +4 -4
  352. package/core/server/models/base/plugins/filtered-collection.js +16 -0
  353. package/core/server/models/member.js +10 -21
  354. package/core/server/models/post.js +2 -2
  355. package/core/server/models/relations/authors.js +2 -16
  356. package/core/server/models/user.js +10 -3
  357. package/core/server/services/auth/passwordreset.js +13 -0
  358. package/core/server/services/automations/automations-api.js +1 -1
  359. package/core/server/services/automations/database-automations-repository.js +11 -4
  360. package/core/server/services/comments/comments-controller.js +30 -9
  361. package/core/server/services/comments/comments-service.js +55 -5
  362. package/core/server/services/content-import/csv/formula.js +12 -0
  363. package/core/server/services/content-import/csv/index.js +6 -1
  364. package/core/server/services/content-import/csv/parse.js +27 -6
  365. package/core/server/services/content-import/csv/serialize.js +13 -0
  366. package/core/server/services/content-import/import/completion-email.js +164 -0
  367. package/core/server/services/content-import/import/errors-file.js +36 -0
  368. package/core/server/services/content-import/import/importer.js +160 -53
  369. package/core/server/services/content-import/import/local-media-url.js +63 -0
  370. package/core/server/services/content-import/import/media.js +254 -0
  371. package/core/server/services/content-import/import/post-data.js +0 -1
  372. package/core/server/services/content-import/import/post-link.js +11 -0
  373. package/core/server/services/content-import/import/post-repository.js +25 -3
  374. package/core/server/services/content-import/import/reader.js +9 -2
  375. package/core/server/services/content-import/import/report.js +34 -0
  376. package/core/server/services/content-import/import/row.js +0 -2
  377. package/core/server/services/content-import/import/schema.js +1 -0
  378. package/core/server/services/content-import/import/staged-file.js +29 -0
  379. package/core/server/services/content-import/import/store.js +25 -2
  380. package/core/server/services/content-import/index.js +52 -6
  381. package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
  382. package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
  383. package/core/server/services/custom-redirects/redirects-service.js +1 -1
  384. package/core/server/services/custom-redirects/validation.js +1 -1
  385. package/core/server/services/email-address/email-address-parser.js +30 -38
  386. package/core/server/services/email-address/email-address-service.js +37 -4
  387. package/core/server/services/email-analytics/index.js +2 -7
  388. package/core/server/services/email-service/CONTEXT.md +37 -0
  389. package/core/server/services/email-service/README.md +42 -0
  390. package/core/server/services/email-service/batch-sending-service.js +2 -4
  391. package/core/server/services/email-service/email-controller.js +18 -2
  392. package/core/server/services/email-service/email-renderer.js +14 -4
  393. package/core/server/services/email-service/email-service-wrapper.js +3 -9
  394. package/core/server/services/email-service/mailgun-email-provider.js +20 -9
  395. package/core/server/services/email-service/sending-status-schema.js +21 -0
  396. package/core/server/services/email-service/sending-status-serializers.js +33 -0
  397. package/core/server/services/email-service/sending-status-service.js +47 -0
  398. package/core/server/services/email-service/sending-status.js +111 -0
  399. package/core/server/services/email-suppression-list/email-suppression-list.js +0 -33
  400. package/core/server/services/email-suppression-list/mailgun-email-suppression-list.js +6 -7
  401. package/core/server/services/gifts/README.md +2 -2
  402. package/core/server/services/gifts/constants.js +1 -1
  403. package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
  404. package/core/server/services/gifts/gift-email-service.js +0 -1
  405. package/core/server/services/gifts/gift-service.js +19 -57
  406. package/core/server/services/gifts/index.js +3 -5
  407. package/core/server/services/gifts/jobs/index.js +4 -4
  408. package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
  409. package/core/server/services/invitations/accept.js +4 -2
  410. package/core/server/services/jobs/job-service.js +0 -9
  411. package/core/server/services/jobs-service/index.js +8 -0
  412. package/core/server/services/jobs-service/jobs-service.js +52 -3
  413. package/core/server/services/jobs-service/register-job-handlers.js +32 -11
  414. package/core/server/services/mail/ghost-mailer.js +4 -4
  415. package/core/server/services/member-welcome-emails/service.js +7 -7
  416. package/core/server/services/members/account-service.js +98 -0
  417. package/core/server/services/members/api.js +4 -3
  418. package/core/server/services/members/import-export/csv/parse.js +0 -7
  419. package/core/server/services/members/import-export/export/exporter.js +20 -20
  420. package/core/server/services/members/import-export/import/completion-email.js +8 -11
  421. package/core/server/services/members/import-export/import/importer.js +13 -13
  422. package/core/server/services/members/import-export/import/row.js +0 -3
  423. package/core/server/services/members/import-export/index.js +10 -17
  424. package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
  425. package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
  426. package/core/server/services/members/jobs/index.js +48 -24
  427. package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
  428. package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
  429. package/core/server/services/members/members-api/members-api.js +26 -8
  430. package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
  431. package/core/server/services/members/members-api/repositories/member-repository.js +4 -4
  432. package/core/server/services/members/members-api/services/member-bread-service.js +62 -84
  433. package/core/server/services/members/members-api/services/payments-service.js +1 -1
  434. package/core/server/services/members/members-ssr.js +18 -0
  435. package/core/server/services/members/middleware.js +95 -81
  436. package/core/server/services/members/service.js +71 -47
  437. package/core/server/services/members/utils.js +9 -0
  438. package/core/server/services/members-metafields/access.js +28 -0
  439. package/core/server/services/{members-custom-fields → members-metafields}/actions.js +5 -5
  440. package/core/server/services/members-metafields/bindings-service.js +147 -0
  441. package/core/server/services/members-metafields/codec.js +14 -0
  442. package/core/server/services/{members-custom-fields → members-metafields}/config.js +1 -1
  443. package/core/server/services/{members-custom-fields → members-metafields}/definitions-service.js +68 -22
  444. package/core/server/services/members-metafields/filter.js +181 -0
  445. package/core/server/services/{members-custom-fields → members-metafields}/index.js +16 -7
  446. package/core/server/services/{members-custom-fields → members-metafields}/key.js +2 -1
  447. package/core/server/services/{members-custom-fields → members-metafields}/models.js +5 -5
  448. package/core/server/services/members-metafields/namespaces.js +34 -0
  449. package/core/server/services/{members-custom-fields → members-metafields}/queries.js +1 -1
  450. package/core/server/services/{members-custom-fields → members-metafields}/schema.js +16 -12
  451. package/core/server/services/members-metafields/serializers.js +22 -0
  452. package/core/server/services/{members-custom-fields → members-metafields}/values-service.js +80 -48
  453. package/core/server/services/mentions/mention-controller.js +23 -21
  454. package/core/server/services/mentions/mention-sending-service.js +26 -9
  455. package/core/server/services/mentions/process-webmention-job.js +16 -0
  456. package/core/server/services/mentions/send-webmentions-job.js +18 -0
  457. package/core/server/services/mentions/service.js +7 -33
  458. package/core/server/services/route-settings/validation-errors.js +1 -1
  459. package/core/server/services/route-settings/yaml-parser.js +1 -1
  460. package/core/server/services/settings/settings-service.js +1 -8
  461. package/core/server/services/settings-helpers/settings-helpers.js +4 -6
  462. package/core/server/services/slack-ping/slack-ping-service.js +1 -1
  463. package/core/server/services/staff/staff-service-emails.js +2 -2
  464. package/core/server/services/stripe/config.js +14 -8
  465. package/core/server/services/stripe/service.js +10 -1
  466. package/core/server/services/stripe/services/checkout/completed-session.js +2 -2
  467. package/core/server/services/stripe/services/checkout/session-options.js +18 -15
  468. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +28 -7
  469. package/core/server/services/stripe/stripe-api.js +2 -0
  470. package/core/server/services/stripe/stripe-service.js +24 -14
  471. package/core/server/services/stripe/webhook-controller.js +10 -0
  472. package/core/server/services/tier-checkout-config/codec.js +11 -7
  473. package/core/server/services/tier-checkout-config/index.js +2 -1
  474. package/core/server/services/tier-checkout-config/models.js +11 -5
  475. package/core/server/services/tier-checkout-config/queries.js +12 -12
  476. package/core/server/services/tier-checkout-config/serializers.js +73 -10
  477. package/core/server/services/tier-checkout-config/service.js +14 -13
  478. package/core/server/services/tiers/service.js +3 -3
  479. package/core/server/services/update-check/index.js +13 -13
  480. package/core/server/services/update-check/jobs/update-check-job.js +7 -0
  481. package/core/server/services/update-check/update-check-service.js +2 -2
  482. package/core/server/services/url/router-filter.js +8 -10
  483. package/core/server/services/users.js +1 -19
  484. package/core/server/web/admin/controller.js +1 -1
  485. package/core/server/web/api/endpoints/admin/routes.js +20 -16
  486. package/core/server/web/members/account/index.js +2 -0
  487. package/core/server/web/members/account/routes.js +46 -0
  488. package/core/server/web/members/app.js +4 -18
  489. package/core/shared/config/defaults.json +1 -1
  490. package/core/shared/config/env/config.testing-mysql.json +1 -1
  491. package/core/shared/labs.js +7 -2
  492. package/package.json +42 -41
  493. package/pnpm-lock.yaml +1159 -582
  494. package/pnpm-workspace.yaml +18 -15
  495. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  496. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  497. package/core/built/admin/assets/Combination-5fYEzgbs.js +0 -41
  498. package/core/built/admin/assets/account-migration-DRhAehfw.js +0 -1
  499. package/core/built/admin/assets/activitypub/inbox-BluD2ucT.js +0 -1284
  500. package/core/built/admin/assets/activitypub/label-FHSh6ZAw.js +0 -16
  501. package/core/built/admin/assets/activitypub/layout-Cq4NG0Xr.js +0 -1
  502. package/core/built/admin/assets/activitypub/settings-DQDkr06X.js +0 -315
  503. package/core/built/admin/assets/add-integration-modal-BC0jExDZ.js +0 -1
  504. package/core/built/admin/assets/add-newsletter-modal-DchTkA7l.js +0 -1
  505. package/core/built/admin/assets/add-recommendation-modal-DMvaJZKp.js +0 -1
  506. package/core/built/admin/assets/alert-dialog-QhXzdHfc.js +0 -1
  507. package/core/built/admin/assets/analytics-No1DDY3A.js +0 -1
  508. package/core/built/admin/assets/automated-emails-te1D5kq-.js +0 -1
  509. package/core/built/admin/assets/automations-DpUNUdcZ.js +0 -1
  510. package/core/built/admin/assets/bluesky-sharing-Cjrv_f62.js +0 -1
  511. package/core/built/admin/assets/chunk.896.435fe0637944d4a69810.js +0 -366
  512. package/core/built/admin/assets/color-picker-BTY_NdEm.js +0 -3
  513. package/core/built/admin/assets/color-picker-field-CPlkzOH0.js +0 -1
  514. package/core/built/admin/assets/combobox-DrMtv_4P.js +0 -1
  515. package/core/built/admin/assets/command-ZdgYJpoI.js +0 -1
  516. package/core/built/admin/assets/comments-kidj60-h.js +0 -1
  517. package/core/built/admin/assets/confirmation-context-BhbmQQEl.js +0 -1
  518. package/core/built/admin/assets/custom-field-type-option-CsGIZk1J.js +0 -10
  519. package/core/built/admin/assets/custom-integration-modal-BY37O_9X.js +0 -1
  520. package/core/built/admin/assets/design-and-theme-modal-DUSKM4uC.js +0 -22
  521. package/core/built/admin/assets/dialog-B44iRwlc.js +0 -1
  522. package/core/built/admin/assets/dirty-confirm-dialog-BxgQgQ6H.js +0 -1
  523. package/core/built/admin/assets/dist-Cy8tfrp_.js +0 -1
  524. package/core/built/admin/assets/domain-Ca6KhoQt.js +0 -1
  525. package/core/built/admin/assets/dropzone-Bb-5zQTk.js +0 -5
  526. package/core/built/admin/assets/edit-profile-BdupLlus.js +0 -1
  527. package/core/built/admin/assets/editor-BP883Lpn.js +0 -8
  528. package/core/built/admin/assets/explore-FB-CimXw.js +0 -1
  529. package/core/built/admin/assets/feed-C1GxsmI2.js +0 -1
  530. package/core/built/admin/assets/filter-sources-D5n5bFA2.js +0 -1
  531. package/core/built/admin/assets/filters-DJEzkMUK.js +0 -1
  532. package/core/built/admin/assets/filters-MZXvdH5D.js +0 -1
  533. package/core/built/admin/assets/first-promoter-modal-CGTGLCr5.js +0 -1
  534. package/core/built/admin/assets/gift-link-modal-B6v0tnRN.js +0 -1
  535. package/core/built/admin/assets/growth-BGAJD1rs.js +0 -3
  536. package/core/built/admin/assets/history-modal-iKwUY3XR.js +0 -1
  537. package/core/built/admin/assets/hooks-CuEZV2-q.js +0 -2
  538. package/core/built/admin/assets/index-DjQe-e5s.js +0 -4
  539. package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
  540. package/core/built/admin/assets/index.es-VihPwfeH.js +0 -1
  541. package/core/built/admin/assets/input--W-rCTrX.js +0 -1
  542. package/core/built/admin/assets/invite-user-modal-MdImLCaJ.js +0 -1
  543. package/core/built/admin/assets/koenig-loader-DYZpm6El.js +0 -2
  544. package/core/built/admin/assets/label-picker-cB51xl1r.js +0 -1
  545. package/core/built/admin/assets/layout-c_B_1hax.js +0 -1
  546. package/core/built/admin/assets/link-helpers-MVDdnFCY.js +0 -1
  547. package/core/built/admin/assets/loading-indicator-BpFWTVgh.js +0 -1
  548. package/core/built/admin/assets/member-custom-fields-qs0dIkxM.js +0 -1
  549. package/core/built/admin/assets/member-detail-B6uec2a6.js +0 -1
  550. package/core/built/admin/assets/members-BQF3CqhI.js +0 -2
  551. package/core/built/admin/assets/moderation-DY4wF1Q3.js +0 -1
  552. package/core/built/admin/assets/navigation-modal-DX-gNF3X.js +0 -1
  553. package/core/built/admin/assets/newsletter-CyQA7m3m.js +0 -1
  554. package/core/built/admin/assets/newsletter-detail-modal-BDrptuxn.js +0 -1
  555. package/core/built/admin/assets/newsletters-DXuNmC42.js +0 -1
  556. package/core/built/admin/assets/newsletters-DhNigJUh.js +0 -1
  557. package/core/built/admin/assets/note-Cgo2LCJ6.js +0 -1
  558. package/core/built/admin/assets/notifications-BC50AMku.js +0 -1
  559. package/core/built/admin/assets/offers-container-modal-DWycIMzT.js +0 -1
  560. package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
  561. package/core/built/admin/assets/overview-CVbFtn-k.js +0 -1
  562. package/core/built/admin/assets/overview-YKj7SZaK.js +0 -1
  563. package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
  564. package/core/built/admin/assets/popover-CCy0h5rq.js +0 -1
  565. package/core/built/admin/assets/portal-frame-dc4XKr0e.js +0 -1
  566. package/core/built/admin/assets/portal-modal-BvvdF_B9.js +0 -1
  567. package/core/built/admin/assets/post-analytics-DX470WRG.js +0 -1
  568. package/core/built/admin/assets/post-analytics-header-CXpJmdDv.js +0 -1
  569. package/core/built/admin/assets/post-analytics-provider-CLfKGWZy.js +0 -1
  570. package/core/built/admin/assets/post-helpers-C5OQMBoi.js +0 -1
  571. package/core/built/admin/assets/post-share-modal-Cl0NXRJr.js +0 -1
  572. package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
  573. package/core/built/admin/assets/preferences-DO0UUWFp.js +0 -5
  574. package/core/built/admin/assets/profile-CxT-0l4d.js +0 -1
  575. package/core/built/admin/assets/router-provider-B0gZyiGJ.js +0 -1
  576. package/core/built/admin/assets/schemas-4UPic-oD.js +0 -64
  577. package/core/built/admin/assets/select-DuDUFdPq.js +0 -1
  578. package/core/built/admin/assets/settings-BjCii7BM.js +0 -1
  579. package/core/built/admin/assets/settings-b8kNzZSQ.js +0 -4
  580. package/core/built/admin/assets/share-modal-BV70mr9k.js +0 -1
  581. package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
  582. package/core/built/admin/assets/slack-modal-Be2_KK-z.js +0 -1
  583. package/core/built/admin/assets/stats-C4reGh9O.js +0 -1
  584. package/core/built/admin/assets/stats-view-DP9pQ62k.js +0 -1
  585. package/core/built/admin/assets/stripe-connect-modal-Z-UT_BGc.js +0 -1
  586. package/core/built/admin/assets/tag-detail-Dc0nTOtU.js +0 -2
  587. package/core/built/admin/assets/tags-BLaXBwnb.js +0 -1
  588. package/core/built/admin/assets/testimonials-modal-sFwRnNLh.js +0 -1
  589. package/core/built/admin/assets/tier-detail-modal-BCFpWwUS.js +0 -1
  590. package/core/built/admin/assets/tiers-Nd_z4BZY.js +0 -1
  591. package/core/built/admin/assets/use-filter-params-CAvfDvf1.js +0 -1
  592. package/core/built/admin/assets/use-growth-stats-D6mZXGhK.js +0 -1
  593. package/core/built/admin/assets/use-host-limits-DZtR08oa.js +0 -1
  594. package/core/built/admin/assets/use-pintura-config-CzTfnufz.js +0 -1
  595. package/core/built/admin/assets/use-reply-chain-data-BeQwz8oF.js +0 -1
  596. package/core/built/admin/assets/use-settings-navigation-BbrSUVcf.js +0 -1
  597. package/core/built/admin/assets/use-staff-users-cZg4ugOF.js +0 -1
  598. package/core/built/admin/assets/use-tinybird-query-B1IMyAcv.js +0 -39
  599. package/core/built/admin/assets/use-tinybird-token-Bow0Zwn8.js +0 -1
  600. package/core/built/admin/assets/use-upgrade-route-DhRSo7at.js +0 -1
  601. package/core/built/admin/assets/user-detail-modal-yipSoQfv.js +0 -1
  602. package/core/built/admin/assets/users-5msE1WMs.js +0 -1
  603. package/core/built/admin/assets/web-CKcXAu86.js +0 -1
  604. package/core/built/admin/assets/web-DR4TqM3E.js +0 -2
  605. package/core/server/api/endpoints/member-custom-fields.js +0 -90
  606. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +0 -20
  607. package/core/server/services/email-suppression-list/in-memory-email-suppression-list.js +0 -39
  608. package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
  609. package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
  610. package/core/server/services/members-custom-fields/bindings-service.js +0 -119
  611. package/core/server/services/members-custom-fields/codec.js +0 -15
  612. package/core/server/services/members-custom-fields/filter.js +0 -199
  613. package/core/server/services/members-custom-fields/serializers.js +0 -24
  614. package/core/server/services/stripe/services/checkout/allowed-countries.js +0 -267
  615. package/core/server/services/stripe/services/checkout/field-ports.js +0 -34
  616. package/core/server/services/tier-checkout-config/destinations.js +0 -17
  617. package/core/server/services/update-check/run-update-check.js +0 -63
  618. /package/core/built/admin/assets/{chunk.492.f24d855d7e3f3aad261c.js.LICENSE.txt → chunk.901.4ccc639821020230bcca.js.LICENSE.txt} +0 -0
  619. /package/core/server/services/{members-custom-fields → members-metafields}/storage.js +0 -0
@@ -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} */ (
@@ -449,7 +453,7 @@ module.exports = class CheckoutSessionEventService {
449
453
 
450
454
  /**
451
455
  * This service knows how to read a completed Stripe session. It does not know, and must
452
- * not know, which custom field any of those values belongs in — that is what a binding
456
+ * not know, which metafield any of those values belongs in — that is what a binding
453
457
  * decides, so no field key appears anywhere in this code.
454
458
  *
455
459
  * Nothing here may be fatal: a throw fails the webhook, which makes Stripe retry it and
@@ -457,22 +461,39 @@ 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
 
475
- await this.deps.customFieldBindings.writeCollected(
496
+ await this.deps.metafieldBindings.writeCollected(
476
497
  memberId,
477
498
  tierId,
478
499
  collectedByPort.parse(session),
@@ -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
@@ -10,7 +10,7 @@ const InvoiceEventService = require('./services/webhook/invoice-event-service');
10
10
  const CheckoutSessionEventService = require('./services/webhook/checkout-session-event-service');
11
11
  const ChargeRefundedEventService = require('./services/webhook/charge-refunded-event-service');
12
12
  const memberWelcomeEmailService = require('../member-welcome-emails/service');
13
- const customFields = require('../members-custom-fields');
13
+ const metafields = require('../members-metafields');
14
14
 
15
15
  /**
16
16
  * @typedef {object} IStripeServiceConfig
@@ -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,11 +135,10 @@ module.exports = class StripeService {
134
135
  memberWelcomeEmailService.init();
135
136
  return memberWelcomeEmailService.api.isMemberWelcomeEmailActive('paid');
136
137
  },
137
- labsService: labs,
138
- // A getter because the custom field services are built during boot: reading the
138
+ // A getter because the metafields services are built during boot: reading the
139
139
  // binding at construction would capture the empty value it had beforehand.
140
- get customFieldBindings() {
141
- return customFields.bindings;
140
+ get metafieldBindings() {
141
+ return metafields.bindings;
142
142
  },
143
143
  });
144
144
 
@@ -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(
@@ -2,25 +2,29 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.questionRowCodec = exports.QuestionRow = exports.collectionRowCodec = exports.CollectionRow = exports.optionsCodec = void 0;
4
4
  const zod_1 = require("zod");
5
- const custom_field_types_1 = require("@tryghost/custom-field-types");
5
+ const metafield_types_1 = require("@tryghost/metafield-types");
6
6
  const boolean_1 = require("../../lib/db-types/boolean");
7
7
  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);
@@ -63,7 +67,7 @@ exports.QuestionRow = zod_1.z.object({
63
67
  label: schema_1.DbCheckoutQuestion.shape.label,
64
68
  optional: schema_1.DbCheckoutQuestion.shape.optional,
65
69
  question_name: zod_1.z.string().nullable(),
66
- question_type: custom_field_types_1.FieldTypeSchema.nullable(),
70
+ question_type: metafield_types_1.FieldTypeSchema.nullable(),
67
71
  });
68
72
  exports.questionRowCodec = exports.QuestionRow.transform((row) => ({
69
73
  tierId: row.product_id,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toCheckoutConfigResponse = exports.TierCheckoutConfig = exports.ShippingCollection = exports.ResolvedQuestion = exports.ResolvedCheckout = exports.PhoneCollection = exports.emptyCheckoutConfig = exports.CheckoutQuestion = exports.TierCheckoutConfigService = void 0;
3
+ exports.requirementsByTier = exports.toCheckoutConfigResponse = exports.TierCheckoutConfig = exports.ShippingCollection = exports.ResolvedQuestion = exports.ResolvedCheckout = exports.PhoneCollection = exports.emptyCheckoutConfig = exports.CheckoutQuestion = exports.TierCheckoutConfigService = void 0;
4
4
  /**
5
5
  * What a tier's checkout asks and collects.
6
6
  *
@@ -24,3 +24,4 @@ Object.defineProperty(exports, "ShippingCollection", { enumerable: true, get: fu
24
24
  Object.defineProperty(exports, "TierCheckoutConfig", { enumerable: true, get: function () { return models_1.TierCheckoutConfig; } });
25
25
  var serializers_1 = require("./serializers");
26
26
  Object.defineProperty(exports, "toCheckoutConfigResponse", { enumerable: true, get: function () { return serializers_1.toCheckoutConfigResponse; } });
27
+ Object.defineProperty(exports, "requirementsByTier", { enumerable: true, get: function () { return serializers_1.requirementsByTier; } });
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ResolvedCheckout = exports.ResolvedQuestion = exports.CheckoutOptions = exports.emptyCheckoutConfig = exports.emptyCollection = exports.TierCheckoutConfig = exports.PhoneCollection = exports.ShippingCollection = exports.CheckoutQuestion = void 0;
4
4
  const zod_1 = require("zod");
5
- const custom_field_types_1 = require("@tryghost/custom-field-types");
5
+ const metafield_types_1 = require("@tryghost/metafield-types");
6
6
  exports.CheckoutQuestion = zod_1.z.object({
7
7
  key: zod_1.z.string(),
8
8
  label: zod_1.z.string().nullable(),
@@ -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,12 +48,12 @@ 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({
49
55
  prompt: zod_1.z.string(),
50
- type: custom_field_types_1.FieldTypeSchema,
56
+ type: metafield_types_1.FieldTypeSchema,
51
57
  });
52
58
  exports.ResolvedCheckout = zod_1.z.object({
53
59
  customFields: zod_1.z.array(exports.ResolvedQuestion),
@@ -4,13 +4,13 @@ exports.FIELDS_TABLE = exports.BINDINGS_TABLE = exports.CONFIG_TABLE = exports.Q
4
4
  exports.collectionRowsForTier = collectionRowsForTier;
5
5
  exports.configuredCollectionRows = configuredCollectionRows;
6
6
  exports.questionRows = questionRows;
7
- const schema_1 = require("../members-custom-fields/schema");
8
- const field_ports_1 = require("../stripe/services/checkout/field-ports");
7
+ const schema_1 = require("../members-metafields/schema");
8
+ const checkout_1 = require("@tryghost/checkout");
9
9
  const schema_2 = require("./schema");
10
10
  exports.QUESTIONS_TABLE = 'products_checkout_fields';
11
11
  exports.CONFIG_TABLE = 'products_checkout_config';
12
- exports.BINDINGS_TABLE = 'members_custom_field_bindings';
13
- exports.FIELDS_TABLE = 'members_custom_fields';
12
+ exports.BINDINGS_TABLE = 'members_metafield_bindings';
13
+ exports.FIELDS_TABLE = 'members_metafields';
14
14
  const ACTIVE = schema_1.FIELD_STATUS.active;
15
15
  const optionColumns = Object.keys(schema_2.DbCheckoutOptions.shape).map((column) => `${exports.CONFIG_TABLE}.${column}`);
16
16
  function collectionQuery(db) {
@@ -18,26 +18,26 @@ function collectionQuery(db) {
18
18
  this.on(`${alias}.product_id`, 'products.id').andOn(db.raw(`${alias}.port = ?`, [port]));
19
19
  };
20
20
  const landsIn = (alias, binding) => function () {
21
- this.on(`${alias}.key`, `${binding}.custom_field_key`).andOn(db.raw(`${alias}.status = ?`, [ACTIVE]));
21
+ this.on(`${alias}.key`, `${binding}.metafield_key`).andOn(db.raw(`${alias}.status = ?`, [ACTIVE]));
22
22
  };
23
23
  const query = db('products')
24
24
  .leftJoin(exports.CONFIG_TABLE, `${exports.CONFIG_TABLE}.product_id`, 'products.id')
25
- .leftJoin({ name_binding: exports.BINDINGS_TABLE }, bindTo('name_binding', field_ports_1.STRIPE_PORT.shippingName))
25
+ .leftJoin({ name_binding: exports.BINDINGS_TABLE }, bindTo('name_binding', checkout_1.STRIPE_PORT.shippingName))
26
26
  .leftJoin({ name_field: exports.FIELDS_TABLE }, landsIn('name_field', 'name_binding'))
27
- .leftJoin({ shipping_binding: exports.BINDINGS_TABLE }, bindTo('shipping_binding', field_ports_1.STRIPE_PORT.shippingAddress))
27
+ .leftJoin({ shipping_binding: exports.BINDINGS_TABLE }, bindTo('shipping_binding', checkout_1.STRIPE_PORT.shippingAddress))
28
28
  .leftJoin({ shipping_field: exports.FIELDS_TABLE }, landsIn('shipping_field', 'shipping_binding'))
29
- .leftJoin({ phone_binding: exports.BINDINGS_TABLE }, bindTo('phone_binding', field_ports_1.STRIPE_PORT.phone))
29
+ .leftJoin({ phone_binding: exports.BINDINGS_TABLE }, bindTo('phone_binding', checkout_1.STRIPE_PORT.phone))
30
30
  .leftJoin({ phone_field: exports.FIELDS_TABLE }, landsIn('phone_field', 'phone_binding'))
31
31
  .orderBy('products.id', 'asc')
32
32
  .select([
33
33
  'products.id as product_id',
34
34
  `${exports.CONFIG_TABLE}.id as config_id`,
35
35
  ...optionColumns,
36
- 'name_binding.custom_field_key as shipping_name_key',
36
+ 'name_binding.metafield_key as shipping_name_key',
37
37
  'name_field.key as shipping_name_collectable',
38
- 'shipping_binding.custom_field_key as shipping_address_key',
38
+ 'shipping_binding.metafield_key as shipping_address_key',
39
39
  'shipping_field.key as shipping_address_collectable',
40
- 'phone_binding.custom_field_key as phone_key',
40
+ 'phone_binding.metafield_key as phone_key',
41
41
  'phone_field.key as phone_collectable',
42
42
  ]);
43
43
  return query;
@@ -60,7 +60,7 @@ function questionRows(db, productId) {
60
60
  const query = db(exports.QUESTIONS_TABLE)
61
61
  .join(exports.BINDINGS_TABLE, `${exports.BINDINGS_TABLE}.id`, `${exports.QUESTIONS_TABLE}.binding_id`)
62
62
  .leftJoin({ question_field: exports.FIELDS_TABLE }, function () {
63
- this.on('question_field.key', `${exports.BINDINGS_TABLE}.custom_field_key`).andOn(db.raw('question_field.status = ?', [ACTIVE]));
63
+ this.on('question_field.key', `${exports.BINDINGS_TABLE}.metafield_key`).andOn(db.raw('question_field.status = ?', [ACTIVE]));
64
64
  })
65
65
  .orderBy(`${exports.BINDINGS_TABLE}.product_id`, 'asc')
66
66
  .orderBy(`${exports.QUESTIONS_TABLE}.sort_order`, 'asc')