ghost 6.61.0 → 6.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (472) hide show
  1. package/components/ghost-storage-base-3.0.0.tgz +0 -0
  2. package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
  3. package/components/tryghost-adapter-base-jobs-0.0.0.tgz +0 -0
  4. package/components/tryghost-adapter-base-redirects-0.0.0.tgz +0 -0
  5. package/components/tryghost-adapter-base-route-settings-0.0.0.tgz +0 -0
  6. package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
  7. package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
  8. package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
  9. package/components/tryghost-checkout-0.0.0.tgz +0 -0
  10. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  11. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  12. package/components/tryghost-kg-card-factory-5.2.4.tgz +0 -0
  13. package/components/tryghost-kg-clean-basic-html-4.3.4.tgz +0 -0
  14. package/components/tryghost-kg-converters-1.2.5.tgz +0 -0
  15. package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
  16. package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
  17. package/components/tryghost-kg-default-transforms-1.3.4.tgz +0 -0
  18. package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
  19. package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
  20. package/components/tryghost-kg-markdown-html-renderer-7.2.4.tgz +0 -0
  21. package/components/tryghost-kg-utils-1.1.4.tgz +0 -0
  22. package/components/tryghost-nql-string-0.0.0.tgz +0 -0
  23. package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
  24. package/content/settings/README.md +1 -1
  25. package/content/themes/casper/.gitignore +28 -0
  26. package/content/themes/casper/assets/built/casper.js +1 -1
  27. package/content/themes/casper/assets/built/screen.css +1 -1
  28. package/content/themes/casper/assets/css/screen.css +2 -1
  29. package/content/themes/casper/assets/js/lightbox.js +63 -46
  30. package/content/themes/casper/package.json +6 -6
  31. package/content/themes/casper/page.hbs +1 -0
  32. package/content/themes/casper/post.hbs +1 -0
  33. package/content/themes/source/.gitignore +28 -0
  34. package/content/themes/source/assets/built/screen.css +1 -1
  35. package/content/themes/source/assets/built/source.js +1 -1
  36. package/content/themes/source/assets/css/screen.css +2 -1
  37. package/content/themes/source/assets/js/lightbox.js +62 -45
  38. package/content/themes/source/assets/js/main.js +2 -2
  39. package/content/themes/source/package.json +4 -4
  40. package/content/themes/source/partials/feature-image.hbs +1 -0
  41. package/core/boot.js +54 -22
  42. package/core/built/admin/assets/Combination-B0l4MKVh.js +41 -0
  43. package/core/built/admin/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
  44. package/core/built/admin/assets/InterVariable-Italic-FCBEiFp6.woff2 +0 -0
  45. package/core/built/admin/assets/{about-Bve7IJS2.js → about-Dyae_UT6.js} +1 -1
  46. package/core/built/admin/assets/account-migration-CESa0mnX.js +1 -0
  47. package/core/built/admin/assets/activitypub/{account-migration-C-aej4x_.js → account-migration-By69CgCp.js} +16 -16
  48. package/core/built/admin/assets/activitypub/activitypub.js +9 -9
  49. package/core/built/admin/assets/activitypub/{bluesky-sharing-BXkA5mqV.js → bluesky-sharing-BJcPMrDd.js} +36 -36
  50. package/core/built/admin/assets/activitypub/{content-formatters-CHcyMFk4.js → content-formatters-3rTHg3mp.js} +3 -3
  51. package/core/built/admin/assets/activitypub/{domain-B3ihkPde.js → domain-DUR4xSkV.js} +121 -121
  52. package/core/built/admin/assets/activitypub/{edit-profile-DsZM3rTX.js → edit-profile-BqtfzxCp.js} +40 -40
  53. package/core/built/admin/assets/activitypub/{explore-BodNrZgR.js → explore-BxuJd-J4.js} +26 -26
  54. package/core/built/admin/assets/activitypub/{feed-PwH1iJ84.js → feed-BM1TcksA.js} +48 -48
  55. package/core/built/admin/assets/activitypub/{field-D06-kmOJ.js → field-Dn7HHx2-.js} +2 -2
  56. package/core/built/admin/assets/activitypub/inbox-CCjkuow2.js +1284 -0
  57. package/core/built/admin/assets/activitypub/label-1AA_s9Fa.js +16 -0
  58. package/core/built/admin/assets/activitypub/layout-2-0bw6HN.js +1 -0
  59. package/core/built/admin/assets/activitypub/{moderation-D1Yapsod.js → moderation-CnmxEB8w.js} +91 -91
  60. package/core/built/admin/assets/activitypub/{note-C5zjqq5C.js → note-ZKc_Bnba.js} +23 -23
  61. package/core/built/admin/assets/activitypub/{notifications-B9p8eCHD.js → notifications-CB2tJZau.js} +48 -48
  62. package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-BsJ9E5qf.js} +2 -2
  63. package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-CSUJJIlh.js} +2 -2
  64. package/core/built/admin/assets/activitypub/{preferences-BCqUdC3v.js → preferences-0-JZnUkI.js} +1519 -1519
  65. package/core/built/admin/assets/activitypub/{profile-BRCWoFem.js → profile-C35cFIhM.js} +183 -183
  66. package/core/built/admin/assets/activitypub/{routes-BSXT992i.js → routes-BD4vscyc.js} +740 -731
  67. package/core/built/admin/assets/activitypub/settings-BsMROdqh.js +315 -0
  68. package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-O0RL9YCN.js} +2 -2
  69. package/core/built/admin/assets/activitypub/{step-1-B-YfsVeO.js → step-1-BMSx7c_X.js} +4 -4
  70. package/core/built/admin/assets/activitypub/{step-3-D6BFMXL_.js → step-3-CLlOZTyt.js} +3 -3
  71. package/core/built/admin/assets/activitypub/{tabs-GpNecvfB.js → tabs-Dxk-b9M-.js} +306 -306
  72. package/core/built/admin/assets/activitypub/{topic-filter-BPDeQQys.js → topic-filter-5yZH6tId.js} +2 -2
  73. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-BoVOxXkV.js → use-activity-pub-queries-CV50qe03.js} +2 -2
  74. package/core/built/admin/assets/activitypub/{use-reply-chain-data-wVBX7swM.js → use-reply-chain-data-Cbvzgjzd.js} +30 -30
  75. package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-BjcoP_HC.js} +7 -5
  76. package/core/built/admin/assets/add-integration-modal-BlF6rs_f.js +1 -0
  77. package/core/built/admin/assets/add-newsletter-modal-CglVQqah.js +1 -0
  78. package/core/built/admin/assets/add-recommendation-modal-wz7BsuaG.js +1 -0
  79. package/core/built/admin/assets/analytics-C4HE1gBg.js +1 -0
  80. package/core/built/admin/assets/{announcement-bar-modal-DM3cYOpo.js → announcement-bar-modal-Ci4zz8jO.js} +1 -1
  81. package/core/built/admin/assets/{api-keys-BLm2NDBh.js → api-keys-Ck-Yteiv.js} +1 -1
  82. package/core/built/admin/assets/{audience-9mwU5TW6.js → audience-CtbA54Sn.js} +1 -1
  83. package/core/built/admin/assets/{automated-emails-te1D5kq-.js → automated-emails-D5VVMND9.js} +1 -1
  84. package/core/built/admin/assets/automations-CzKt5fb8.js +1 -0
  85. package/core/built/admin/assets/bluesky-sharing-BEtJ_gL_.js +1 -0
  86. package/core/built/admin/assets/{breadcrumb-DLiqCyFc.js → breadcrumb-zUrZrBtW.js} +1 -1
  87. package/core/built/admin/assets/{button-B2jcu6bk.js → button-eNMKQWXr.js} +1 -1
  88. package/core/built/admin/assets/{chart-helpers-Fo3bUL3K.js → chart-helpers-CfBKt0vT.js} +1 -1
  89. package/core/built/admin/assets/{checkbox-BfKktMph.js → checkbox-CgOn_tKW.js} +1 -1
  90. package/core/built/admin/assets/{chunk.524.60ca4692d91c6022042f.js → chunk.524.a697dee88db67fdf6021.js} +4 -4
  91. package/core/built/admin/assets/{chunk.582.525c7617c2d9e94c940a.js → chunk.582.5ed5d124cfca9c259b9c.js} +6 -6
  92. package/core/built/admin/assets/{chunk.896.435fe0637944d4a69810.js → chunk.598.7e056fabb47ce7dbd73f.js} +14 -14
  93. package/core/built/admin/assets/{code-editor-view-CYVu4EW6.js → code-editor-view-BYNoAoNV.js} +1 -1
  94. package/core/built/admin/assets/{code-editor-view-DCQJxsfU.js → code-editor-view-K2wI-I5f.js} +1 -1
  95. package/core/built/admin/assets/color-picker-Ddw80xX6.js +3 -0
  96. package/core/built/admin/assets/color-picker-field-D9nUhvA7.js +1 -0
  97. package/core/built/admin/assets/combobox-w9j8PPQT.js +1 -0
  98. package/core/built/admin/assets/command-BfpHORBv.js +1 -0
  99. package/core/built/admin/assets/comments-BLmCmyCs.js +1 -0
  100. package/core/built/admin/assets/confirmation-context-CBM8G0Vj.js +1 -0
  101. package/core/built/admin/assets/{content-api-modal-CyQEC3fr.js → content-api-modal-TXRz3U7S.js} +1 -1
  102. package/core/built/admin/assets/context-menu-_QMdd3kp.js +1 -0
  103. package/core/built/admin/assets/{copy-field-B3M1s78L.js → copy-field-6N01S07E.js} +1 -1
  104. package/core/built/admin/assets/create-ghost-browse-value-source-qIBymvvf.js +1 -0
  105. package/core/built/admin/assets/custom-field-type-option-BddFlJFa.js +1 -0
  106. package/core/built/admin/assets/custom-integration-modal-DmNquxUV.js +1 -0
  107. package/core/built/admin/assets/{date-range-select-DD2RKkgB.js → date-range-select-uvz_DtPh.js} +1 -1
  108. package/core/built/admin/assets/design-and-theme-modal-BSmo12Op.js +2 -0
  109. package/core/built/admin/assets/dirty-confirm-dialog-BZ1iytEd.js +1 -0
  110. package/core/built/admin/assets/{disabled-sources-indicator-Cvy47bE2.js → disabled-sources-indicator-DMRrxsiJ.js} +1 -1
  111. package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
  112. package/core/built/admin/assets/domain-BNYrt0aD.js +1 -0
  113. package/core/built/admin/assets/dropzone-D7nFdAe5.js +5 -0
  114. package/core/built/admin/assets/edit-profile-C5Asm4LA.js +1 -0
  115. package/core/built/admin/assets/editor-REokrzci.js +8 -0
  116. package/core/built/admin/assets/{embed-signup-form-modal-DeBMLxlL.js → embed-signup-form-modal-Ds6mPEi5.js} +1 -1
  117. package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
  118. package/core/built/admin/assets/explore-UY10Egsp.js +1 -0
  119. package/core/built/admin/assets/feature-image-placeholder-D1iF_8bc.js +1 -0
  120. package/core/built/admin/assets/feed-81C8mJWR.js +1 -0
  121. package/core/built/admin/assets/{field-Cj8lmDOo.js → field-Dihp5p18.js} +1 -1
  122. package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
  123. package/core/built/admin/assets/filter-sources-BO9xUPj7.js +1 -0
  124. package/core/built/admin/assets/filters-CRUWecfY.js +1 -0
  125. package/core/built/admin/assets/filters-DirqNXjH.js +1 -0
  126. package/core/built/admin/assets/first-promoter-modal-CT6MxYZb.js +1 -0
  127. package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8eabfc1ece81b03cf7b90780d31487e8.css} +1 -1
  128. package/core/built/admin/assets/{ghost-3894eedcc6968f658578c0abfe942aab.js → ghost-c2848508292937415f20f5a830eea59e.js} +31 -28
  129. package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-a7bebe2c561f55369dcf29f4c820f7ff.css} +1 -1
  130. package/core/built/admin/assets/gift-link-modal-CQVAye17.js +1 -0
  131. package/core/built/admin/assets/growth-BWIu-6xj.js +3 -0
  132. package/core/built/admin/assets/growth-DU29oxeA.js +1 -0
  133. package/core/built/admin/assets/history-modal-CFd1Hvx6.js +1 -0
  134. package/core/built/admin/assets/{html-field-C8qVGGC1.js → html-field-CJBCLTvv.js} +1 -1
  135. package/core/built/admin/assets/{images-h8VZEQ9k.js → images-scfkWZiK.js} +1 -1
  136. package/core/built/admin/assets/{inbox-BYd1M06Q.js → inbox-Mcp4DXZN.js} +14 -14
  137. package/core/built/admin/assets/index-6MkPdCtr.js +4 -0
  138. package/core/built/admin/assets/index-Bn7QhcZu.css +2 -0
  139. package/core/built/admin/assets/index.es-CNnuNH0d.js +1 -0
  140. package/core/built/admin/assets/{input-group-D8sCXRF5.js → input-group-CMhe2DvY.js} +1 -1
  141. package/core/built/admin/assets/invite-user-modal-DfheMXs0.js +1 -0
  142. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
  143. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
  144. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  145. package/core/built/admin/assets/{koenig-lexical-_-IsVI7E.js → koenig-lexical-DBSqAuiI.js} +3 -3
  146. package/core/built/admin/assets/koenig-loader-aFQNlJlD.js +2 -0
  147. package/core/built/admin/assets/{kpi-card-DZQk_0W8.js → kpi-card-DBRMfGOW.js} +1 -1
  148. package/core/built/admin/assets/{kpi-card-DW_2y3ug.js → kpi-card-DFafD1qq.js} +1 -1
  149. package/core/built/admin/assets/{kpi-helpers-PueTKuA6.js → kpi-helpers-Cv8i8hns.js} +1 -1
  150. package/core/built/admin/assets/{kpi-tabs-CojDs-Qz.js → kpi-tabs-BJItvLYm.js} +1 -1
  151. package/core/built/admin/assets/{label-DjbT91GM.js → label-BnSCvffu.js} +1 -1
  152. package/core/built/admin/assets/label-picker-KVoo91sh.js +1 -0
  153. package/core/built/admin/assets/layout-Bjv2Ll-5.js +1 -0
  154. package/core/built/admin/assets/member-custom-fields-DDQV6QeG.js +1 -0
  155. package/core/built/admin/assets/member-detail-CdJF6Agw.js +1 -0
  156. package/core/built/admin/assets/members-DjQbq9Z2.js +4 -0
  157. package/core/built/admin/assets/moderation-AgCIEso4.js +1 -0
  158. package/core/built/admin/assets/{multi-select-combobox-B6LiRzDO.js → multi-select-combobox-BcITkUVr.js} +1 -1
  159. package/core/built/admin/assets/navigation-modal-BkT7b1M2.js +1 -0
  160. package/core/built/admin/assets/newsletter-BMMAuvgq.js +1 -0
  161. package/core/built/admin/assets/newsletter-detail-modal-0SCJ7Zpm.js +1 -0
  162. package/core/built/admin/assets/{newsletter-emails-CFeLlt4z.js → newsletter-emails-DKzwafuh.js} +1 -1
  163. package/core/built/admin/assets/newsletters-BRBb_uQC.js +1 -0
  164. package/core/built/admin/assets/note-DyGHtS9a.js +1 -0
  165. package/core/built/admin/assets/notifications-ZgWniKna.js +1 -0
  166. package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
  167. package/core/built/admin/assets/offers-container-modal-B-E8TIWr.js +1 -0
  168. package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-CzIsre-d.js} +1 -1
  169. package/core/built/admin/assets/onboarding-qg8Akovm.js +1 -0
  170. package/core/built/admin/assets/{onboarding-route-Dmc4IPm3.js → onboarding-route-CaavZulg.js} +1 -1
  171. package/core/built/admin/assets/overview-BW8GLeYi.js +1 -0
  172. package/core/built/admin/assets/overview-BkXZNzaZ.js +1 -0
  173. package/core/built/admin/assets/{page-header-BR_nbIPp.js → page-header-De0VzKBi.js} +1 -1
  174. package/core/built/admin/assets/pagemenu-B5KKCpbA.js +1 -0
  175. package/core/built/admin/assets/pages-jgaFm69d.js +1 -0
  176. package/core/built/admin/assets/pages-route-CIUAQxtY.js +1 -0
  177. package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
  178. package/core/built/admin/assets/{pintura-modal-BR9hEvS8.js → pintura-modal-BZ2J9w3n.js} +1 -1
  179. package/core/built/admin/assets/portal-frame-B6Hr9wHc.js +1 -0
  180. package/core/built/admin/assets/portal-modal-D4ceei3t.js +1 -0
  181. package/core/built/admin/assets/post-analytics-header-BYCsT0GP.js +1 -0
  182. package/core/built/admin/assets/post-analytics-ot7f6pih.js +1 -0
  183. package/core/built/admin/assets/{post-analytics-provider-CLfKGWZy.js → post-analytics-provider-Bo1gmYaP.js} +1 -1
  184. package/core/built/admin/assets/{post-share-modal-Cl0NXRJr.js → post-share-modal-C-PaYZ_e.js} +1 -1
  185. package/core/built/admin/assets/posts-DuGazgTb.js +1 -0
  186. package/core/built/admin/assets/posts-list-screen-CBGGgjjj.js +2 -0
  187. package/core/built/admin/assets/posts-route-D6xmS7Vf.js +1 -0
  188. package/core/built/admin/assets/preferences-C5YJLp74.js +5 -0
  189. package/core/built/admin/assets/{preview-modal-C-BL-F9k.js → preview-modal-BfeFqi5y.js} +1 -1
  190. package/core/built/admin/assets/profile-B8mx2yAu.js +1 -0
  191. package/core/built/admin/assets/radio-group-DczlLKOn.js +1 -0
  192. package/core/built/admin/assets/{schemas-4UPic-oD.js → schemas-DppqmpeJ.js} +1 -1
  193. package/core/built/admin/assets/select-cb0t_TAJ.js +1 -0
  194. package/core/built/admin/assets/settings-DZqxR0Da.js +1 -0
  195. package/core/built/admin/assets/settings-DvfTNdHQ.js +4 -0
  196. package/core/built/admin/assets/{settings-breadcrumbs-CyP_9zTo.js → settings-breadcrumbs-DLzbRRSt.js} +1 -1
  197. package/core/built/admin/assets/share-modal-D2-Bz1_I.js +1 -0
  198. package/core/built/admin/assets/slack-modal-DYDTUria.js +1 -0
  199. package/core/built/admin/assets/{sort-button-Cc-Z96sA.js → sort-button-VVeQjjbu.js} +1 -1
  200. package/core/built/admin/assets/{source-icon-v6PUnmyM.js → source-icon-Ck5_5Kgq.js} +1 -1
  201. package/core/built/admin/assets/stats-Rjmk5owg.js +1 -0
  202. package/core/built/admin/assets/stats-view-BGGmkmgv.js +1 -0
  203. package/core/built/admin/assets/{step-1-DSRp2vBj.js → step-1-CsaBjeN4.js} +1 -1
  204. package/core/built/admin/assets/{step-2-COqv2g0u.js → step-2-D2vnxOOM.js} +1 -1
  205. package/core/built/admin/assets/{step-3-6W1NMVQc.js → step-3-wBoLdGEb.js} +2 -2
  206. package/core/built/admin/assets/{stripe-button-D2K42Uty.js → stripe-button-CDgLz0S0.js} +1 -1
  207. package/core/built/admin/assets/stripe-connect-modal-CSjMJetP.js +1 -0
  208. package/core/built/admin/assets/{table-B2pIKjVh.js → table-Do6iQ83Q.js} +1 -1
  209. package/core/built/admin/assets/{tabs-SaW_UT-Q.js → tabs-D2yWLMp_.js} +1 -1
  210. package/core/built/admin/assets/tag-detail-BhXlOsCa.js +2 -0
  211. package/core/built/admin/assets/tags-ldukRApe.js +1 -0
  212. package/core/built/admin/assets/testimonials-modal-CtnZBJKl.js +1 -0
  213. package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +1 -0
  214. package/core/built/admin/assets/{toggle-group-EM9WpESu.js → toggle-group-ByUJsxwD.js} +1 -1
  215. package/core/built/admin/assets/{topic-filter-DY4gNHn2.js → topic-filter-BgC3g5_v.js} +1 -1
  216. package/core/built/admin/assets/{transistor-modal-CpyPG-MH.js → transistor-modal-Drr0SNfo.js} +1 -1
  217. package/core/built/admin/assets/{trend-badge-ByMkuAuH.js → trend-badge-6ye93YAW.js} +1 -1
  218. package/core/built/admin/assets/{unsplash-modal-Cv2Q6GtY.js → unsplash-modal-p6AoQoWp.js} +1 -1
  219. package/core/built/admin/assets/{use-analytics-data-CHvjMYuT.js → use-analytics-data-CWCMAESo.js} +1 -1
  220. package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
  221. package/core/built/admin/assets/{use-check-theme-limit-error-Qv4SVXqw.js → use-check-theme-limit-error-Cw3WQHy8.js} +1 -1
  222. package/core/built/admin/assets/use-filter-params-BIni9taJ.js +1 -0
  223. package/core/built/admin/assets/use-growth-stats-DCVG3s9w.js +1 -0
  224. package/core/built/admin/assets/{use-limiter-cwJvsNBo.js → use-limiter-D2WRRx0H.js} +1 -1
  225. package/core/built/admin/assets/{use-pintura-config-CzTfnufz.js → use-pintura-config-h-J0Lvta.js} +1 -1
  226. package/core/built/admin/assets/{use-pintura-editor-BDBXWUYq.js → use-pintura-editor-BfN1UwzH.js} +1 -1
  227. package/core/built/admin/assets/use-post-referrers-Czg47m8s.js +1 -0
  228. package/core/built/admin/assets/use-reply-chain-data-ns0caK8k.js +1 -0
  229. package/core/built/admin/assets/{use-router-history-entry-Bg6BhBQQ.js → use-router-history-entry-uldn7zJO.js} +1 -1
  230. package/core/built/admin/assets/{use-setting-group-VM7FQwMY.js → use-setting-group-DpcuCUDg.js} +1 -1
  231. package/core/built/admin/assets/use-settings-navigation-CZjGrhsp.js +1 -0
  232. package/core/built/admin/assets/{use-simple-pagination-Dum6Irbs.js → use-simple-pagination-DzJWobPR.js} +1 -1
  233. package/core/built/admin/assets/{use-staff-users-cZg4ugOF.js → use-staff-users-Csipb-O0.js} +1 -1
  234. package/core/built/admin/assets/use-tinybird-query-CSnGXzZh.js +1 -0
  235. package/core/built/admin/assets/use-tinybird-token-DTOKRR7e.js +1 -0
  236. package/core/built/admin/assets/{use-unsaved-changes-guard-BAy0RANR.js → use-unsaved-changes-guard-CBzs-KPi.js} +1 -1
  237. package/core/built/admin/assets/{use-url-input-Df5QzNa7.js → use-url-input-DFr8lCbS.js} +1 -1
  238. package/core/built/admin/assets/user-detail-modal-B_iUClI6.js +1 -0
  239. package/core/built/admin/assets/users-Cg-OeGzC.js +1 -0
  240. package/core/built/admin/assets/{virtual-list-DEx8WgiO.js → virtual-list-BW-padMe.js} +1 -1
  241. package/core/built/admin/assets/web-C1v33ehA.js +2 -0
  242. package/core/built/admin/assets/web-C4BKzn2T.js +1 -0
  243. package/core/built/admin/assets/{zapier-modal-Cw3BTBUu.js → zapier-modal-BBFfI6Ml.js} +1 -1
  244. package/core/built/admin/index.html +17 -22
  245. package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
  246. package/core/frontend/helpers/cancel_link.js +2 -2
  247. package/core/frontend/helpers/pagination.js +2 -2
  248. package/core/frontend/helpers/social_accounts.js +2 -2
  249. package/core/frontend/public/ghost.css +1 -1
  250. package/core/frontend/public/ghost.min.css +1 -1
  251. package/core/frontend/services/sitemap/user-map-generator.js +9 -2
  252. package/core/server/api/endpoints/index.js +2 -2
  253. package/core/server/api/endpoints/mail.js +1 -1
  254. package/core/server/api/endpoints/{member-custom-fields.js → member-metafields.js} +27 -28
  255. package/core/server/api/endpoints/members.js +4 -4
  256. package/core/server/api/endpoints/posts.js +3 -3
  257. package/core/server/api/endpoints/utils/serializers/input/members.js +4 -7
  258. package/core/server/api/endpoints/utils/serializers/output/index.js +2 -2
  259. package/core/server/api/endpoints/utils/serializers/output/{member-custom-fields.js → member-metafields.js} +2 -4
  260. package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
  261. package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
  262. package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
  263. package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
  264. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  265. package/core/server/data/migrations/utils/migrations.js +1 -1
  266. package/core/server/lib/image/image-size.js +24 -0
  267. package/core/server/lib/package-json/parse.js +2 -2
  268. package/core/server/models/member.js +6 -17
  269. package/core/server/models/post.js +2 -2
  270. package/core/server/models/relations/authors.js +2 -16
  271. package/core/server/models/user.js +9 -2
  272. package/core/server/services/auth/passwordreset.js +13 -0
  273. package/core/server/services/comments/comments-controller.js +30 -9
  274. package/core/server/services/comments/comments-service.js +55 -5
  275. package/core/server/services/content-import/csv/formula.js +12 -0
  276. package/core/server/services/content-import/csv/index.js +6 -1
  277. package/core/server/services/content-import/csv/parse.js +27 -6
  278. package/core/server/services/content-import/csv/serialize.js +13 -0
  279. package/core/server/services/content-import/import/completion-email.js +164 -0
  280. package/core/server/services/content-import/import/errors-file.js +36 -0
  281. package/core/server/services/content-import/import/importer.js +160 -53
  282. package/core/server/services/content-import/import/local-media-url.js +63 -0
  283. package/core/server/services/content-import/import/media.js +254 -0
  284. package/core/server/services/content-import/import/post-data.js +0 -1
  285. package/core/server/services/content-import/import/post-link.js +11 -0
  286. package/core/server/services/content-import/import/post-repository.js +25 -3
  287. package/core/server/services/content-import/import/reader.js +9 -2
  288. package/core/server/services/content-import/import/report.js +34 -0
  289. package/core/server/services/content-import/import/row.js +0 -2
  290. package/core/server/services/content-import/import/schema.js +1 -0
  291. package/core/server/services/content-import/import/staged-file.js +29 -0
  292. package/core/server/services/content-import/import/store.js +25 -2
  293. package/core/server/services/content-import/index.js +52 -6
  294. package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
  295. package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
  296. package/core/server/services/custom-redirects/redirects-service.js +1 -1
  297. package/core/server/services/custom-redirects/validation.js +1 -1
  298. package/core/server/services/email-address/email-address-parser.js +30 -38
  299. package/core/server/services/email-address/email-address-service.js +37 -4
  300. package/core/server/services/email-analytics/index.js +2 -7
  301. package/core/server/services/email-service/batch-sending-service.js +0 -4
  302. package/core/server/services/email-service/email-renderer.js +14 -4
  303. package/core/server/services/email-service/email-service-wrapper.js +0 -9
  304. package/core/server/services/email-service/mailgun-email-provider.js +20 -9
  305. package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
  306. package/core/server/services/gifts/gift-email-service.js +0 -1
  307. package/core/server/services/gifts/index.js +3 -3
  308. package/core/server/services/gifts/jobs/index.js +4 -4
  309. package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
  310. package/core/server/services/invitations/accept.js +4 -2
  311. package/core/server/services/jobs/job-service.js +0 -9
  312. package/core/server/services/jobs-service/register-job-handlers.js +21 -11
  313. package/core/server/services/mail/ghost-mailer.js +4 -4
  314. package/core/server/services/member-welcome-emails/service.js +7 -7
  315. package/core/server/services/members/api.js +1 -0
  316. package/core/server/services/members/import-export/csv/parse.js +0 -7
  317. package/core/server/services/members/import-export/import/completion-email.js +2 -5
  318. package/core/server/services/members/import-export/import/row.js +0 -3
  319. package/core/server/services/members/import-export/index.js +4 -11
  320. package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
  321. package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
  322. package/core/server/services/members/jobs/index.js +48 -24
  323. package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
  324. package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
  325. package/core/server/services/members/members-api/members-api.js +4 -6
  326. package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
  327. package/core/server/services/members/members-api/services/member-bread-service.js +34 -62
  328. package/core/server/services/members/members-api/services/payments-service.js +1 -1
  329. package/core/server/services/members/service.js +1 -5
  330. package/core/server/services/members-custom-fields/bindings-service.js +2 -1
  331. package/core/server/services/members-custom-fields/codec.js +3 -4
  332. package/core/server/services/members-custom-fields/definitions-service.js +62 -10
  333. package/core/server/services/members-custom-fields/filter.js +75 -93
  334. package/core/server/services/members-custom-fields/key.js +2 -1
  335. package/core/server/services/members-custom-fields/models.js +1 -1
  336. package/core/server/services/members-custom-fields/serializers.js +3 -5
  337. package/core/server/services/members-custom-fields/values-service.js +50 -28
  338. package/core/server/services/mentions/mention-controller.js +23 -21
  339. package/core/server/services/mentions/process-webmention-job.js +16 -0
  340. package/core/server/services/mentions/service.js +8 -4
  341. package/core/server/services/route-settings/validation-errors.js +1 -1
  342. package/core/server/services/route-settings/yaml-parser.js +1 -1
  343. package/core/server/services/settings/settings-service.js +1 -8
  344. package/core/server/services/settings-helpers/settings-helpers.js +4 -6
  345. package/core/server/services/slack-ping/slack-ping-service.js +1 -1
  346. package/core/server/services/staff/staff-service-emails.js +2 -2
  347. package/core/server/services/stripe/config.js +14 -8
  348. package/core/server/services/stripe/service.js +10 -1
  349. package/core/server/services/stripe/services/checkout/completed-session.js +2 -2
  350. package/core/server/services/stripe/services/checkout/session-options.js +18 -15
  351. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +26 -5
  352. package/core/server/services/stripe/stripe-api.js +2 -0
  353. package/core/server/services/stripe/stripe-service.js +20 -10
  354. package/core/server/services/stripe/webhook-controller.js +10 -0
  355. package/core/server/services/tier-checkout-config/codec.js +9 -5
  356. package/core/server/services/tier-checkout-config/models.js +9 -3
  357. package/core/server/services/tier-checkout-config/queries.js +4 -4
  358. package/core/server/services/tier-checkout-config/serializers.js +16 -10
  359. package/core/server/services/tier-checkout-config/service.js +13 -12
  360. package/core/server/services/update-check/index.js +13 -13
  361. package/core/server/services/update-check/jobs/update-check-job.js +7 -0
  362. package/core/server/services/update-check/update-check-service.js +2 -2
  363. package/core/server/web/admin/controller.js +1 -1
  364. package/core/server/web/api/endpoints/admin/routes.js +19 -16
  365. package/core/shared/config/env/config.testing-mysql.json +1 -1
  366. package/core/shared/labs.js +5 -2
  367. package/package.json +24 -23
  368. package/pnpm-lock.yaml +704 -69
  369. package/pnpm-workspace.yaml +8 -5
  370. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  371. package/core/built/admin/assets/Combination-5fYEzgbs.js +0 -41
  372. package/core/built/admin/assets/account-migration-DRhAehfw.js +0 -1
  373. package/core/built/admin/assets/activitypub/inbox-BluD2ucT.js +0 -1284
  374. package/core/built/admin/assets/activitypub/label-FHSh6ZAw.js +0 -16
  375. package/core/built/admin/assets/activitypub/layout-Cq4NG0Xr.js +0 -1
  376. package/core/built/admin/assets/activitypub/settings-DQDkr06X.js +0 -315
  377. package/core/built/admin/assets/add-integration-modal-BC0jExDZ.js +0 -1
  378. package/core/built/admin/assets/add-newsletter-modal-DchTkA7l.js +0 -1
  379. package/core/built/admin/assets/add-recommendation-modal-DMvaJZKp.js +0 -1
  380. package/core/built/admin/assets/alert-dialog-QhXzdHfc.js +0 -1
  381. package/core/built/admin/assets/analytics-No1DDY3A.js +0 -1
  382. package/core/built/admin/assets/automations-DpUNUdcZ.js +0 -1
  383. package/core/built/admin/assets/bluesky-sharing-Cjrv_f62.js +0 -1
  384. package/core/built/admin/assets/color-picker-BTY_NdEm.js +0 -3
  385. package/core/built/admin/assets/color-picker-field-CPlkzOH0.js +0 -1
  386. package/core/built/admin/assets/combobox-DrMtv_4P.js +0 -1
  387. package/core/built/admin/assets/command-ZdgYJpoI.js +0 -1
  388. package/core/built/admin/assets/comments-kidj60-h.js +0 -1
  389. package/core/built/admin/assets/confirmation-context-BhbmQQEl.js +0 -1
  390. package/core/built/admin/assets/custom-field-type-option-CsGIZk1J.js +0 -10
  391. package/core/built/admin/assets/custom-integration-modal-BY37O_9X.js +0 -1
  392. package/core/built/admin/assets/design-and-theme-modal-DUSKM4uC.js +0 -22
  393. package/core/built/admin/assets/dialog-B44iRwlc.js +0 -1
  394. package/core/built/admin/assets/dirty-confirm-dialog-BxgQgQ6H.js +0 -1
  395. package/core/built/admin/assets/dist-Cy8tfrp_.js +0 -1
  396. package/core/built/admin/assets/domain-Ca6KhoQt.js +0 -1
  397. package/core/built/admin/assets/dropzone-Bb-5zQTk.js +0 -5
  398. package/core/built/admin/assets/edit-profile-BdupLlus.js +0 -1
  399. package/core/built/admin/assets/editor-BP883Lpn.js +0 -8
  400. package/core/built/admin/assets/explore-FB-CimXw.js +0 -1
  401. package/core/built/admin/assets/feed-C1GxsmI2.js +0 -1
  402. package/core/built/admin/assets/filter-sources-D5n5bFA2.js +0 -1
  403. package/core/built/admin/assets/filters-DJEzkMUK.js +0 -1
  404. package/core/built/admin/assets/filters-MZXvdH5D.js +0 -1
  405. package/core/built/admin/assets/first-promoter-modal-CGTGLCr5.js +0 -1
  406. package/core/built/admin/assets/gift-link-modal-B6v0tnRN.js +0 -1
  407. package/core/built/admin/assets/growth-BGAJD1rs.js +0 -3
  408. package/core/built/admin/assets/growth-D6mhcx3q.js +0 -1
  409. package/core/built/admin/assets/history-modal-iKwUY3XR.js +0 -1
  410. package/core/built/admin/assets/index-DjQe-e5s.js +0 -4
  411. package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
  412. package/core/built/admin/assets/index.es-VihPwfeH.js +0 -1
  413. package/core/built/admin/assets/input--W-rCTrX.js +0 -1
  414. package/core/built/admin/assets/invite-user-modal-MdImLCaJ.js +0 -1
  415. package/core/built/admin/assets/koenig-loader-DYZpm6El.js +0 -2
  416. package/core/built/admin/assets/label-picker-cB51xl1r.js +0 -1
  417. package/core/built/admin/assets/layout-c_B_1hax.js +0 -1
  418. package/core/built/admin/assets/loading-indicator-BpFWTVgh.js +0 -1
  419. package/core/built/admin/assets/member-custom-fields-qs0dIkxM.js +0 -1
  420. package/core/built/admin/assets/member-detail-B6uec2a6.js +0 -1
  421. package/core/built/admin/assets/members-BQF3CqhI.js +0 -2
  422. package/core/built/admin/assets/moderation-DY4wF1Q3.js +0 -1
  423. package/core/built/admin/assets/navigation-modal-DX-gNF3X.js +0 -1
  424. package/core/built/admin/assets/newsletter-CyQA7m3m.js +0 -1
  425. package/core/built/admin/assets/newsletter-detail-modal-BDrptuxn.js +0 -1
  426. package/core/built/admin/assets/newsletters-DXuNmC42.js +0 -1
  427. package/core/built/admin/assets/note-Cgo2LCJ6.js +0 -1
  428. package/core/built/admin/assets/notifications-BC50AMku.js +0 -1
  429. package/core/built/admin/assets/offers-container-modal-DWycIMzT.js +0 -1
  430. package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
  431. package/core/built/admin/assets/overview-CVbFtn-k.js +0 -1
  432. package/core/built/admin/assets/overview-YKj7SZaK.js +0 -1
  433. package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
  434. package/core/built/admin/assets/popover-CCy0h5rq.js +0 -1
  435. package/core/built/admin/assets/portal-frame-dc4XKr0e.js +0 -1
  436. package/core/built/admin/assets/portal-modal-BvvdF_B9.js +0 -1
  437. package/core/built/admin/assets/post-analytics-DX470WRG.js +0 -1
  438. package/core/built/admin/assets/post-analytics-header-CXpJmdDv.js +0 -1
  439. package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
  440. package/core/built/admin/assets/preferences-DO0UUWFp.js +0 -5
  441. package/core/built/admin/assets/profile-CxT-0l4d.js +0 -1
  442. package/core/built/admin/assets/radio-group-Bgz60i81.js +0 -1
  443. package/core/built/admin/assets/select-DuDUFdPq.js +0 -1
  444. package/core/built/admin/assets/settings-BjCii7BM.js +0 -1
  445. package/core/built/admin/assets/settings-b8kNzZSQ.js +0 -4
  446. package/core/built/admin/assets/share-modal-BV70mr9k.js +0 -1
  447. package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
  448. package/core/built/admin/assets/slack-modal-Be2_KK-z.js +0 -1
  449. package/core/built/admin/assets/stats-C4reGh9O.js +0 -1
  450. package/core/built/admin/assets/stats-view-DP9pQ62k.js +0 -1
  451. package/core/built/admin/assets/stripe-connect-modal-Z-UT_BGc.js +0 -1
  452. package/core/built/admin/assets/tag-detail-Dc0nTOtU.js +0 -2
  453. package/core/built/admin/assets/tags-BLaXBwnb.js +0 -1
  454. package/core/built/admin/assets/testimonials-modal-sFwRnNLh.js +0 -1
  455. package/core/built/admin/assets/tier-detail-modal-BCFpWwUS.js +0 -1
  456. package/core/built/admin/assets/use-filter-params-CAvfDvf1.js +0 -1
  457. package/core/built/admin/assets/use-growth-stats-D6mZXGhK.js +0 -1
  458. package/core/built/admin/assets/use-post-referrers-DbY-mzci.js +0 -1
  459. package/core/built/admin/assets/use-reply-chain-data-BeQwz8oF.js +0 -1
  460. package/core/built/admin/assets/use-settings-navigation-BbrSUVcf.js +0 -1
  461. package/core/built/admin/assets/use-tinybird-query-B1IMyAcv.js +0 -39
  462. package/core/built/admin/assets/use-tinybird-token-Bow0Zwn8.js +0 -1
  463. package/core/built/admin/assets/user-detail-modal-yipSoQfv.js +0 -1
  464. package/core/built/admin/assets/users-5msE1WMs.js +0 -1
  465. package/core/built/admin/assets/web-CKcXAu86.js +0 -1
  466. package/core/built/admin/assets/web-DR4TqM3E.js +0 -2
  467. package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
  468. package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
  469. package/core/server/services/stripe/services/checkout/allowed-countries.js +0 -267
  470. package/core/server/services/stripe/services/checkout/field-ports.js +0 -34
  471. package/core/server/services/tier-checkout-config/destinations.js +0 -17
  472. package/core/server/services/update-check/run-update-check.js +0 -63
@@ -2,89 +2,88 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const members_custom_fields_1 = require("../../services/members-custom-fields");
4
4
  const permissionsService = require('../../services/permissions');
5
- // There is no Bookshelf model for this resource, so permissions are checked
6
- // explicitly against the member_custom_field object type (the default
7
- // `permissions: true` handler would try to load a model that doesn't exist).
5
+ // With `permissions: true` the framework checks against the Bookshelf model named after
6
+ // the resource. These fields have no Bookshelf model, so each handler asks the permissions
7
+ // service directly.
8
8
  function canThis(frame) {
9
9
  return permissionsService.canThis(frame.options.context);
10
10
  }
11
11
  const noCacheInvalidation = { cacheInvalidate: false };
12
12
  const controller = {
13
- docName: 'members_custom_fields',
13
+ docName: 'members_metafields',
14
14
  browse: {
15
15
  headers: noCacheInvalidation,
16
- // `filter` narrows by status (the definition list is otherwise small and
17
- // global, returned whole). Archived fields are hidden by default; Settings
18
- // passes `filter=status:[active,archived]` to see both. No pagination or order
19
- // options: the list comes back in the publisher's own order, which is changed
20
- // by reordering it rather than by asking for it differently.
21
- options: ['filter'],
16
+ options: ['namespace', 'filter'],
17
+ validation: { options: { namespace: { required: true } } },
22
18
  permissions(frame) {
23
19
  return canThis(frame).browse.member_custom_field();
24
20
  },
25
21
  query(frame) {
26
- return members_custom_fields_1.definitions.browse({ filter: frame.options.filter });
22
+ return members_custom_fields_1.definitions.browse({
23
+ namespace: frame.options.namespace,
24
+ filter: frame.options.filter,
25
+ });
27
26
  },
28
27
  },
29
28
  read: {
30
29
  headers: noCacheInvalidation,
31
- options: ['key'],
32
- validation: { options: { key: { required: true } } },
30
+ options: ['namespace', 'key'],
31
+ validation: { options: { namespace: { required: true }, key: { required: true } } },
33
32
  permissions(frame) {
34
33
  return canThis(frame).read.member_custom_field(frame.options.key);
35
34
  },
36
35
  query(frame) {
37
- return members_custom_fields_1.definitions.read(frame.options.key);
36
+ return members_custom_fields_1.definitions.read(frame.options.namespace, frame.options.key);
38
37
  },
39
38
  },
40
39
  add: {
41
40
  statusCode: 201,
42
41
  headers: noCacheInvalidation,
42
+ options: ['namespace'],
43
+ validation: { options: { namespace: { required: true } } },
43
44
  permissions(frame) {
44
45
  return canThis(frame).add.member_custom_field();
45
46
  },
46
- // The whole array is passed through: create is a batch, applied
47
- // all-or-nothing. A client sending a single definition (as Admin does)
48
- // is just the one-item case and sees no change.
49
47
  query(frame) {
50
- return members_custom_fields_1.definitions.add((0, members_custom_fields_1.actingContext)(frame.options.context), frame.data.members_custom_fields);
48
+ return members_custom_fields_1.definitions.add((0, members_custom_fields_1.actingContext)(frame.options.context), frame.options.namespace, frame.data.members_metafields);
51
49
  },
52
50
  },
53
- // Order belongs to the list, so it is set by PUTting the list. No `/order` sub-route:
54
- // `order` is a key a publisher could mint, and the route would shadow it.
55
51
  reorder: {
56
52
  headers: noCacheInvalidation,
53
+ options: ['namespace'],
54
+ validation: { options: { namespace: { required: true } } },
57
55
  permissions(frame) {
58
56
  return canThis(frame).edit.member_custom_field();
59
57
  },
60
58
  query(frame) {
61
- return members_custom_fields_1.definitions.reorder((0, members_custom_fields_1.actingContext)(frame.options.context), frame.data.members_custom_fields);
59
+ return members_custom_fields_1.definitions.reorder((0, members_custom_fields_1.actingContext)(frame.options.context), frame.options.namespace, frame.data.members_metafields);
62
60
  },
63
61
  },
64
62
  edit: {
65
63
  headers: noCacheInvalidation,
66
- options: ['key'],
67
- validation: { options: { key: { required: true } } },
64
+ options: ['namespace', 'key'],
65
+ validation: { options: { namespace: { required: true }, key: { required: true } } },
68
66
  permissions(frame) {
69
67
  return canThis(frame).edit.member_custom_field(frame.options.key);
70
68
  },
71
69
  query(frame) {
72
- return members_custom_fields_1.definitions.edit((0, members_custom_fields_1.actingContext)(frame.options.context), frame.options.key, frame.data.members_custom_fields[0]);
70
+ return members_custom_fields_1.definitions.edit((0, members_custom_fields_1.actingContext)(frame.options.context), frame.options.namespace, frame.options.key, frame.data.members_metafields[0]);
73
71
  },
74
72
  },
75
73
  destroy: {
76
74
  statusCode: 204,
77
75
  headers: noCacheInvalidation,
78
- options: ['key'],
79
- validation: { options: { key: { required: true } } },
76
+ options: ['namespace', 'key'],
77
+ validation: { options: { namespace: { required: true }, key: { required: true } } },
80
78
  permissions(frame) {
81
79
  return canThis(frame).destroy.member_custom_field(frame.options.key);
82
80
  },
83
81
  async query(frame) {
84
- await members_custom_fields_1.definitions.destroy((0, members_custom_fields_1.actingContext)(frame.options.context), frame.options.key);
82
+ await members_custom_fields_1.definitions.destroy((0, members_custom_fields_1.actingContext)(frame.options.context), frame.options.namespace, frame.options.key);
85
83
  return null;
86
84
  },
87
85
  },
88
86
  };
89
- // module.exports (not export): the API framework loads controllers via require().
87
+ // The API framework loads this file with `require()`, so it exports CommonJS-style;
88
+ // `export default` would not be picked up.
90
89
  module.exports = controller;
@@ -44,10 +44,10 @@ const messages = {
44
44
  resourceNotFound: '{resource} not found.',
45
45
  };
46
46
 
47
- // `custom_fields` is a browse include only: a read returns values whenever the
48
- // flag is on, the same way it returns tiers. Values are not a member relation, so
49
- // the input serializer lifts the key out of withRelated before the model sees it.
50
- const allowedIncludes = ['email_recipients', 'products', 'tiers', 'custom_fields'];
47
+ // `metafields` is not a relation on the member model. It is allowed here only so callers
48
+ // can ask for it with `include=`; the input serializer removes it before the model tries
49
+ // to eager-load it.
50
+ const allowedIncludes = ['email_recipients', 'products', 'tiers', 'metafields'];
51
51
 
52
52
  /** @type {import('@tryghost/api-framework').Controller} */
53
53
  const controller = {
@@ -129,13 +129,13 @@ const controller = {
129
129
  method: 'importContent',
130
130
  },
131
131
  async query(frame) {
132
- // The CSV must be parsed before the response goes out: the uploaded temp file is
133
- // deleted as soon as it is sent. The posts are written by a background job behind
134
- // the 202.
132
+ // The content-import service stages and validates the upload before this response;
133
+ // Multer deletes the request temp file as soon as the 202 is sent.
135
134
  const { importId, total } = await contentImportService.importCSV({
136
135
  filePath: frame.file.path,
137
136
  fileName: frame.file.name,
138
137
  mapping: frame.data.mapping,
138
+ requestUserEmail: frame.user ? frame.user.get('email') : null,
139
139
  });
140
140
  return { meta: { import_id: importId, total } };
141
141
  },
@@ -34,16 +34,13 @@ function mapSubscribedFlagToNewsletterRelation(frame) {
34
34
  });
35
35
  }
36
36
 
37
- // Values are not a member relation — they're stored per field type and read by
38
- // the custom fields service — so `include=custom_fields` must not reach the model
39
- // layer as something to eager-load. Lift it out and leave a flag browse can act on.
40
- function liftCustomFieldsInclude(frame) {
41
- if (!frame.options.withRelated.includes('custom_fields')) {
37
+ function liftMetafieldsInclude(frame) {
38
+ if (!frame.options.withRelated.includes('metafields')) {
42
39
  return;
43
40
  }
44
41
 
45
42
  frame.options.withRelated = frame.options.withRelated.filter(
46
- (relation) => relation !== 'custom_fields',
43
+ (relation) => relation !== 'metafields',
47
44
  );
48
45
  frame.options.includeCustomFields = true;
49
46
  }
@@ -54,7 +51,7 @@ module.exports = {
54
51
  return;
55
52
  }
56
53
 
57
- liftCustomFieldsInclude(frame);
54
+ liftMetafieldsInclude(frame);
58
55
 
59
56
  frame.options.withRelated = frame.options.withRelated.map((relation) => {
60
57
  if (relation === 'tiers') {
@@ -76,8 +76,8 @@ module.exports = {
76
76
  return require('./members');
77
77
  },
78
78
 
79
- get members_custom_fields() {
80
- return require('./member-custom-fields');
79
+ get members_metafields() {
80
+ return require('./member-metafields');
81
81
  },
82
82
 
83
83
  get tiers() {
@@ -7,13 +7,11 @@ const serializeOne = (field, _apiConfig, frame) => {
7
7
  const serializeMany = (fields, _apiConfig, frame) => {
8
8
  frame.response = serializers_1.toCustomFieldsResponse.parse(fields);
9
9
  };
10
- // module.exports (not export): the API framework loads serializers via require(). The endpoint ->
11
- // serializer mapping lives here; the response shaping lives with the members-custom-fields service.
10
+ // The API framework loads this file with `require()`, so it exports CommonJS-style;
11
+ // `export default` would not be picked up.
12
12
  module.exports = {
13
13
  browse: serializeMany,
14
14
  read: serializeOne,
15
- // Create is a batch, so it returns every definition it made. The response is
16
- // already an array, so a one-item create looks exactly as it did before.
17
15
  add: serializeMany,
18
16
  reorder: serializeMany,
19
17
  edit: serializeOne,
@@ -131,10 +131,8 @@ function serializeMember(member, options) {
131
131
  serialized.tiers = json.products;
132
132
  }
133
133
 
134
- // Present on a read whenever the flag is on; absent otherwise, and absent on
135
- // browse. An empty object is a member with no values set.
136
- if (json.custom_fields) {
137
- serialized.custom_fields = json.custom_fields;
134
+ if (json.metafields) {
135
+ serialized.metafields = json.metafields;
138
136
  }
139
137
 
140
138
  serialized.current_subscription = json.current_subscription || null;
@@ -4,7 +4,6 @@ const tpl = require('@tryghost/tpl');
4
4
  const errors = require('@tryghost/errors');
5
5
 
6
6
  const messages = {
7
- noEmailProvided: 'No email provided.',
8
7
  noNameProvided: 'No name provided.',
9
8
  noPasswordProvided: 'No password provided.',
10
9
  noTokenProvided: 'No token provided.',
@@ -21,10 +20,6 @@ module.exports = {
21
20
  return Promise.reject(new errors.ValidationError({ message: tpl(messages.noTokenProvided) }));
22
21
  }
23
22
 
24
- if (!data.email) {
25
- return Promise.reject(new errors.ValidationError({ message: tpl(messages.noEmailProvided) }));
26
- }
27
-
28
23
  if (!data.password) {
29
24
  return Promise.reject(
30
25
  new errors.ValidationError({ message: tpl(messages.noPasswordProvided) }),
@@ -8,7 +8,7 @@ const messages = {
8
8
  onlySingleContentSource: 'Pages can have either a mobiledoc or a lexical property, never both.',
9
9
  onlySingleContentSourceContext:
10
10
  'Both the mobiledoc and lexical properties are set, one must be null',
11
- onlySingleContentSourceHelp: 'https://ghost.org/docs/admin-api/#the-post-object',
11
+ onlySingleContentSourceHelp: 'https://docs.ghost.org/admin-api/#the-post-object',
12
12
  };
13
13
 
14
14
  const validateVisibility = async function (frame) {
@@ -8,7 +8,7 @@ const messages = {
8
8
  onlySingleContentSource: 'Posts can have either a mobiledoc or a lexical property, never both.',
9
9
  onlySingleContentSourceContext:
10
10
  'Both the mobiledoc and lexical properties are set, one must be null',
11
- onlySingleContentSourceHelp: 'https://ghost.org/docs/admin-api/#the-post-object',
11
+ onlySingleContentSourceHelp: 'https://docs.ghost.org/admin-api/#the-post-object',
12
12
  };
13
13
 
14
14
  const validateVisibility = async function (frame) {
@@ -99,7 +99,7 @@ DataImporter = {
99
99
  return Promise.reject(
100
100
  new IncorrectUsageError({
101
101
  message: 'Wrong importer structure. `meta` is missing.',
102
- help: 'https://ghost.org/docs/migration/custom/',
102
+ help: 'https://docs.ghost.org/migration/custom/',
103
103
  }),
104
104
  );
105
105
  }
@@ -108,7 +108,7 @@ DataImporter = {
108
108
  return Promise.reject(
109
109
  new IncorrectUsageError({
110
110
  message: 'Wrong importer structure. `meta.version` is missing.',
111
- help: 'https://ghost.org/docs/migration/custom/',
111
+ help: 'https://docs.ghost.org/migration/custom/',
112
112
  }),
113
113
  );
114
114
  }
@@ -119,7 +119,7 @@ DataImporter = {
119
119
  return Promise.reject(
120
120
  new IncorrectUsageError({
121
121
  message: 'Detected unsupported file structure.',
122
- help: 'Please install Ghost 1.0, import the file and then update your blog to the latest Ghost version.\nVisit https://ghost.org/docs/update/ or ask for help in our https://forum.ghost.org.',
122
+ help: 'Please install Ghost 1.0, import the file and then update your blog to the latest Ghost version.\nVisit https://docs.ghost.org/update/ or ask for help in our https://forum.ghost.org.',
123
123
  }),
124
124
  );
125
125
  }
@@ -117,7 +117,7 @@ function createFinalMigration(major) {
117
117
  async function up() {
118
118
  throw new errors.InternalServerError({
119
119
  message: `Unable to run migrations`,
120
- context: `You must be on the latest v${major}.x to update across major versions - https://ghost.org/docs/update/`,
120
+ context: `You must be on the latest v${major}.x to update across major versions - https://docs.ghost.org/update/`,
121
121
  help: `Run 'ghost update v${major}' to get the latest v${major}.x version, then run 'ghost update' to get to the latest.`,
122
122
  });
123
123
  },
@@ -31,6 +31,12 @@ class ImageSize {
31
31
  },
32
32
  response_timeout: this.config.get('times:getImageSizeTimeoutInMS') || 10000,
33
33
  };
34
+
35
+ // Coalesces concurrent getImageSizeFromUrl() calls for the same URL so we only
36
+ // ever issue one underlying request/read per URL at a time. A single post's
37
+ // coverImage/ogImage/twitterImage often resolve to the same feature_image URL
38
+ // and are looked up concurrently, which otherwise fans out into duplicate requests.
39
+ this.inFlightImageSizeLookups = new Map();
34
40
  }
35
41
 
36
42
  // processes the Buffer result of an image file using image-size
@@ -153,6 +159,24 @@ class ImageSize {
153
159
  * @returns {Promise<Object>} imageObject or error
154
160
  */
155
161
  getImageSizeFromUrl(imagePath) {
162
+ if (this.inFlightImageSizeLookups.has(imagePath)) {
163
+ return this.inFlightImageSizeLookups.get(imagePath);
164
+ }
165
+
166
+ const promise = this._getImageSizeFromUrl(imagePath).finally(() => {
167
+ this.inFlightImageSizeLookups.delete(imagePath);
168
+ });
169
+ this.inFlightImageSizeLookups.set(imagePath, promise);
170
+
171
+ return promise;
172
+ }
173
+
174
+ /**
175
+ * @description read image dimensions from URL, without in-flight deduplication
176
+ * @param {string} imagePath as URL
177
+ * @returns {Promise<Object>} imageObject or error
178
+ */
179
+ _getImageSizeFromUrl(imagePath) {
156
180
  if (this.storageUtils.isLocalImage(imagePath)) {
157
181
  // don't make a request for a locally stored image
158
182
  return this.getImageSizeFromStoragePath(imagePath);
@@ -37,7 +37,7 @@ async function parse(path) {
37
37
  message: tpl(messages.themeFileIsMalformed),
38
38
  context: path,
39
39
  err: parseError,
40
- help: tpl(messages.willBeRequired, { url: 'https://ghost.org/docs/themes/' }),
40
+ help: tpl(messages.willBeRequired, { url: 'https://docs.ghost.org/themes/' }),
41
41
  });
42
42
  }
43
43
 
@@ -47,7 +47,7 @@ async function parse(path) {
47
47
  throw new errors.IncorrectUsageError({
48
48
  message: tpl(messages.nameOrVersionMissing),
49
49
  context: path,
50
- help: tpl(messages.willBeRequired, { url: 'https://ghost.org/docs/themes/' }),
50
+ help: tpl(messages.willBeRequired, { url: 'https://docs.ghost.org/themes/' }),
51
51
  });
52
52
  }
53
53
 
@@ -3,7 +3,6 @@ const crypto = require('crypto');
3
3
  const _ = require('lodash');
4
4
  const { chainTransformers } = require('@tryghost/mongo-utils');
5
5
  const config = require('../../shared/config');
6
- const labs = require('../../shared/labs');
7
6
  const { MemberCommentingCodec } = require('../services/members/commenting');
8
7
  const {
9
8
  CUSTOM_FIELDS_RELATION,
@@ -191,18 +190,12 @@ const Member = ghostBookshelf.Model.extend(
191
190
  ];
192
191
  },
193
192
 
194
- // Chain the custom-field filter transformer at this single choke point the method
195
- // every members query routes its filter through (list, CSV export, bulk edit/destroy,
196
- // count, email send all reach it via findPage or getFilteredCollectionQuery) — so a
197
- // saved `custom_fields.*` segment works the same everywhere without each call site
198
- // wiring it. Runs only behind the flag and only when the filter names the relation; the
199
- // transformer maps the public `key`/`value` grammar onto the leaf-row columns.
193
+ // Every members query routes its filter through this one method: list, CSV export, bulk
194
+ // edit and delete, counts and email sends all reach it via findPage or
195
+ // getFilteredCollectionQuery. Chaining the metafield filter transformer here covers them
196
+ // all without any call site wiring it.
200
197
  applyDefaultAndCustomFilters(options) {
201
- if (
202
- labs.isSet('membersCustomFields') &&
203
- options.filter &&
204
- options.filter.includes(`${CUSTOM_FIELDS_RELATION.tableNameAs}.`)
205
- ) {
198
+ if (options.filter && options.filter.includes(`${CUSTOM_FIELDS_RELATION.tableNameAs}.`)) {
206
199
  const transformer = createCustomFieldsFilterTransformer();
207
200
  options.mongoTransformer = options.mongoTransformer
208
201
  ? chainTransformers(options.mongoTransformer, transformer)
@@ -213,11 +206,7 @@ const Member = ghostBookshelf.Model.extend(
213
206
 
214
207
  filterRelations() {
215
208
  return {
216
- // Custom field values are filterable only behind the feature flag. Gating the
217
- // relation here (rather than the whole model) means a `custom_fields.*` filter
218
- // is simply an unknown relation when the flag is off, and the filter is
219
- // rejected — nothing to special-case downstream.
220
- ...(labs.isSet('membersCustomFields') ? { custom_fields: CUSTOM_FIELDS_RELATION } : {}),
209
+ metafields: CUSTOM_FIELDS_RELATION,
221
210
  labels: {
222
211
  tableName: 'labels',
223
212
  type: 'manyToMany',
@@ -29,9 +29,9 @@ const messages = {
29
29
  notEnoughPermission: 'You do not have permission to perform this action',
30
30
  invalidNewsletter: "The newsletter parameter doesn't match any active newsletter.",
31
31
  invalidMobiledocStructure: 'Invalid mobiledoc structure.',
32
- invalidMobiledocStructureHelp: 'https://ghost.org/docs/publishing/',
32
+ invalidMobiledocStructureHelp: 'https://docs.ghost.org/publishing/',
33
33
  invalidLexicalStructure: 'Invalid lexical structure.',
34
- invalidLexicalStructureHelp: 'https://ghost.org/docs/publishing/',
34
+ invalidLexicalStructureHelp: 'https://docs.ghost.org/publishing/',
35
35
  emailOnlyWithoutNewsletter: 'Scheduling an email requires a newsletter reference.',
36
36
  };
37
37
 
@@ -149,7 +149,6 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
149
149
 
150
150
  // CASE: `posts.authors` was not requested, but fetched in specific cases (see top)
151
151
  if (
152
- !this._originalOptions ||
153
152
  !this._originalOptions.withRelated ||
154
153
  this._originalOptions.withRelated.indexOf('authors') === -1
155
154
  ) {
@@ -157,10 +156,7 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
157
156
  }
158
157
 
159
158
  // If the current column settings allow it...
160
- if (
161
- !options.columns ||
162
- (options.columns && options.columns.indexOf('primary_author') > -1)
163
- ) {
159
+ if (!options.columns || options.columns.indexOf('primary_author') > -1) {
164
160
  // ... attach a computed property of primary_author which is the first author
165
161
  if (attrs.authors && attrs.authors.length) {
166
162
  attrs.primary_author = attrs.authors[0];
@@ -398,20 +394,10 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
398
394
  }
399
395
 
400
396
  function isOwner() {
401
- let isCorrectOwner = true;
402
-
403
397
  if (!unsafeAttrs.authors) {
404
398
  return false;
405
399
  }
406
-
407
- if (unsafeAttrs.authors) {
408
- isCorrectOwner =
409
- isCorrectOwner &&
410
- unsafeAttrs.authors.length &&
411
- unsafeAttrs.authors[0].id === context.user;
412
- }
413
-
414
- return isCorrectOwner;
400
+ return unsafeAttrs.authors.length && unsafeAttrs.authors[0].id === context.user;
415
401
  }
416
402
 
417
403
  function isPrimaryAuthor() {
@@ -43,8 +43,13 @@ const messages = {
43
43
  };
44
44
 
45
45
  /**
46
- * inactive: owner user before blog setup, suspended users
47
- * locked user: imported users, they get a random password
46
+ * `inactive`: suspended staff, who cannot sign in or reset their password.
47
+ * Also used for the initial owner before site setup is complete.
48
+ * `locked`: users whose password was randomized by an import or authentication
49
+ * reset. They must reset their password to regain access.
50
+ *
51
+ * Both statuses prevent normal sign-in, so they are grouped here. This is not
52
+ * a suspension check: isInactive() checks only the literal `inactive` status.
48
53
  */
49
54
  const inactiveStates = ['inactive', 'locked'];
50
55
 
@@ -212,6 +217,8 @@ User = ghostBookshelf.Model.extend(
212
217
  return this.save(update, { ...options, patch: true });
213
218
  },
214
219
 
220
+ // Checks the literal status, not membership in inactiveStates: locked users
221
+ // must remain eligible for password resets.
215
222
  isInactive: function isInactive() {
216
223
  return this.get('status') === 'inactive';
217
224
  },
@@ -11,6 +11,7 @@ const mail = require('../mail');
11
11
 
12
12
  const messages = {
13
13
  userNotFound: 'User not found.',
14
+ userSuspended: 'This account has been suspended.',
14
15
  resetPassword: 'Reset Password',
15
16
  expired: {
16
17
  message: 'Cannot reset password.',
@@ -46,6 +47,14 @@ function generateToken(email, settingsAPI, transaction) {
46
47
  throw new errors.NotFoundError({ message: tpl(messages.userNotFound) });
47
48
  }
48
49
 
50
+ // Prevent suspended users from generating a reset token. This same check must appear
51
+ // below in doReset() to account for password reset tokens that were generated prior
52
+ // to suspension since they have a 24-hour lifetime.
53
+ // Locked users must still be able to recover access by resetting their password.
54
+ if (user.isInactive()) {
55
+ throw new errors.NoPermissionError({ message: tpl(messages.userSuspended) });
56
+ }
57
+
49
58
  token = security.tokens.resetToken.generateHash({
50
59
  expires: moment().add(1, 'days').valueOf(),
51
60
  email: email,
@@ -128,6 +137,10 @@ function doReset(options, tokenParts, settingsAPI) {
128
137
  }
129
138
  }
130
139
 
140
+ if (user.isInactive()) {
141
+ throw new errors.NoPermissionError({ message: tpl(messages.userSuspended) });
142
+ }
143
+
131
144
  const updatedUser = await models.User.changePassword(
132
145
  {
133
146
  oldPassword: oldPassword,
@@ -14,6 +14,7 @@ const messages = {
14
14
  cannotDestroyComments: 'You cannot destroy comments.',
15
15
  memberNotFound: 'Unable to find member',
16
16
  unsupportedReportCountFilter: 'Unsupported count.reports filter',
17
+ errorParsingFilter: 'Error parsing filter',
17
18
  };
18
19
 
19
20
  module.exports = class CommentsController {
@@ -26,6 +27,16 @@ module.exports = class CommentsController {
26
27
  this.stats = stats;
27
28
  }
28
29
 
30
+ #getPostIdFromFilter(query) {
31
+ if (typeof query.post_id === 'string') {
32
+ return query.post_id;
33
+ }
34
+
35
+ // Only equality conditions required by an AND can scope a legacy browse.
36
+ // Choosing an ID from an OR or an exclusion would authorize the wrong posts.
37
+ return query.$and?.map((part) => this.#getPostIdFromFilter(part)).find(Boolean);
38
+ }
39
+
29
40
  #withPostFilter(options) {
30
41
  const nextOptions = { ...options };
31
42
 
@@ -138,7 +149,17 @@ module.exports = class CommentsController {
138
149
  * @param {Frame} frame
139
150
  */
140
151
  async browse(frame) {
141
- return await this.service.getComments(this.#withPostFilter(frame.options));
152
+ const options = { ...frame.options };
153
+ if (!options.post_id && options.filter) {
154
+ let query;
155
+ try {
156
+ query = nql(options.filter).parse();
157
+ } catch (err) {
158
+ throw new errors.BadRequestError({ message: tpl(messages.errorParsingFilter), err });
159
+ }
160
+ options.post_id = this.#getPostIdFromFilter(query);
161
+ }
162
+ return await this.service.getComments(this.#withPostFilter(options));
142
163
  }
143
164
 
144
165
  async adminBrowse(frame) {
@@ -345,14 +366,14 @@ module.exports = class CommentsController {
345
366
  async like(frame) {
346
367
  this.#checkMember(frame);
347
368
 
369
+ const comment = await this.service.getCommentByID(frame.options.id, frame.options);
370
+
348
371
  const result = await this.service.likeComment(
349
372
  frame.options.id,
350
373
  frame.options?.context?.member,
351
374
  frame.options,
352
375
  );
353
376
 
354
- const comment = await this.service.getCommentByID(frame.options.id, frame.options);
355
-
356
377
  this.setCacheInvalidationHeaders(comment, frame);
357
378
 
358
379
  return result;
@@ -364,14 +385,14 @@ module.exports = class CommentsController {
364
385
  async unlike(frame) {
365
386
  this.#checkMember(frame);
366
387
 
388
+ const comment = await this.service.getCommentByID(frame.options.id, frame.options);
389
+
367
390
  const result = await this.service.unlikeComment(
368
391
  frame.options.id,
369
392
  frame.options?.context?.member,
370
393
  frame.options,
371
394
  );
372
395
 
373
- const comment = await this.service.getCommentByID(frame.options.id, frame.options);
374
-
375
396
  this.setCacheInvalidationHeaders(comment, frame);
376
397
 
377
398
  return result;
@@ -420,14 +441,14 @@ module.exports = class CommentsController {
420
441
  async dislike(frame) {
421
442
  this.#checkMember(frame);
422
443
 
444
+ const comment = await this.service.getCommentByID(frame.options.id, frame.options);
445
+
423
446
  const result = await this.service.dislikeComment(
424
447
  frame.options.id,
425
448
  frame.options?.context?.member,
426
449
  frame.options,
427
450
  );
428
451
 
429
- const comment = await this.service.getCommentByID(frame.options.id, frame.options);
430
-
431
452
  this.setCacheInvalidationHeaders(comment, frame);
432
453
 
433
454
  return result;
@@ -439,14 +460,14 @@ module.exports = class CommentsController {
439
460
  async undislike(frame) {
440
461
  this.#checkMember(frame);
441
462
 
463
+ const comment = await this.service.getCommentByID(frame.options.id, frame.options);
464
+
442
465
  const result = await this.service.undislikeComment(
443
466
  frame.options.id,
444
467
  frame.options?.context?.member,
445
468
  frame.options,
446
469
  );
447
470
 
448
- const comment = await this.service.getCommentByID(frame.options.id, frame.options);
449
-
450
471
  this.setCacheInvalidationHeaders(comment, frame);
451
472
 
452
473
  return result;