ghost 6.60.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 (613) 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 +62 -21
  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/{PolarAngleAxis-C4qtHy1B.js → PolarAngleAxis-pkMyqz8g.js} +1 -1
  46. package/core/built/admin/assets/{RadialBarChart-Bh09Stsj.js → RadialBarChart-JAKoS4KT.js} +1 -1
  47. package/core/built/admin/assets/{about-BgpmhCuM.js → about-Dyae_UT6.js} +1 -1
  48. package/core/built/admin/assets/account-migration-CESa0mnX.js +1 -0
  49. package/core/built/admin/assets/{action-list-lGzZLHc8.js → action-list-C4v0-du8.js} +1 -1
  50. package/core/built/admin/assets/activitypub/{account-migration-DMHuPnJn.js → account-migration-By69CgCp.js} +16 -16
  51. package/core/built/admin/assets/activitypub/activitypub.js +9 -10
  52. package/core/built/admin/assets/activitypub/{avatar-DhTo5D1B.js → avatar-DLPL3Abs.js} +59 -68
  53. package/core/built/admin/assets/activitypub/{avatar-flipboard-DnVgbEfa.js → avatar-flipboard-C9iDY-QV.js} +2 -2
  54. package/core/built/admin/assets/activitypub/{bluesky-sharing-BT4zAlW7.js → bluesky-sharing-BJcPMrDd.js} +37 -37
  55. package/core/built/admin/assets/activitypub/{content-formatters-BeDZ-DIa.js → content-formatters-3rTHg3mp.js} +18 -18
  56. package/core/built/admin/assets/activitypub/{copy-8sqxUuNd.js → copy-DIAOQoCZ.js} +2 -2
  57. package/core/built/admin/assets/activitypub/{domain-xQDDu1CS.js → domain-DUR4xSkV.js} +121 -121
  58. package/core/built/admin/assets/activitypub/{edit-profile-BXdF_r2G.js → edit-profile-BqtfzxCp.js} +40 -40
  59. package/core/built/admin/assets/activitypub/{explore-CMt7gKlL.js → explore-BxuJd-J4.js} +27 -27
  60. package/core/built/admin/assets/activitypub/{feed-Bwqdddp_.js → feed-BM1TcksA.js} +51 -51
  61. package/core/built/admin/assets/activitypub/{field-4co_8FVg.js → field-Dn7HHx2-.js} +3 -3
  62. package/core/built/admin/assets/activitypub/{hash-DwakMs4X.js → hash-Bm3WxYN4.js} +2 -2
  63. package/core/built/admin/assets/activitypub/inbox-CCjkuow2.js +1284 -0
  64. package/core/built/admin/assets/activitypub/{inbox-ckD4wo_r.js → inbox-d8oJRTf4.js} +2 -2
  65. package/core/built/admin/assets/activitypub/label-1AA_s9Fa.js +16 -0
  66. package/core/built/admin/assets/activitypub/layout-2-0bw6HN.js +1 -0
  67. package/core/built/admin/assets/activitypub/{moderation-KCCO7L2J.js → moderation-CnmxEB8w.js} +91 -91
  68. package/core/built/admin/assets/activitypub/{note-BX_Bz5A0.js → note-ZKc_Bnba.js} +24 -24
  69. package/core/built/admin/assets/activitypub/{notifications-BQOYGvRv.js → notifications-CB2tJZau.js} +51 -51
  70. package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-BsJ9E5qf.js} +2 -2
  71. package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-CSUJJIlh.js} +2 -2
  72. package/core/built/admin/assets/activitypub/{preferences-6h43G9_q.js → preferences-0-JZnUkI.js} +1519 -1519
  73. package/core/built/admin/assets/activitypub/{profile-BMN9VVZ2.js → profile-C35cFIhM.js} +256 -256
  74. package/core/built/admin/assets/activitypub/{reply-ZNo04xsO.js → reply-DYK5vVqb.js} +2 -2
  75. package/core/built/admin/assets/activitypub/{routes-3B9mUQ7i.js → routes-BD4vscyc.js} +796 -790
  76. package/core/built/admin/assets/activitypub/{separator-D9taVCCa.js → separator-BbQqTm-p.js} +3 -3
  77. package/core/built/admin/assets/activitypub/settings-BsMROdqh.js +315 -0
  78. package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-O0RL9YCN.js} +2 -2
  79. package/core/built/admin/assets/activitypub/{step-1-BsGGnBuT.js → step-1-BMSx7c_X.js} +6 -6
  80. package/core/built/admin/assets/activitypub/{step-2-teosIS0k.js → step-2-DtPQzlTH.js} +6 -6
  81. package/core/built/admin/assets/activitypub/{step-3-BjD5TokC.js → step-3-CLlOZTyt.js} +11 -11
  82. package/core/built/admin/assets/activitypub/{tabs-Cvwl1wXU.js → tabs-Dxk-b9M-.js} +306 -306
  83. package/core/built/admin/assets/activitypub/{topic-filter-C3LZJc2X.js → topic-filter-5yZH6tId.js} +3 -3
  84. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-Dp9f0gov.js → use-activity-pub-queries-CV50qe03.js} +3 -3
  85. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-C4RI0sa9.js → use-navigate-with-base-path-Bmk5h4lW.js} +220 -220
  86. package/core/built/admin/assets/activitypub/{use-reply-chain-data-C2oNDMUH.js → use-reply-chain-data-Cbvzgjzd.js} +30 -30
  87. package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-BjcoP_HC.js} +7 -5
  88. package/core/built/admin/assets/activitypub/{x-Dxm6pV9X.js → x-DbQZOLiI.js} +2 -2
  89. package/core/built/admin/assets/add-integration-modal-BlF6rs_f.js +1 -0
  90. package/core/built/admin/assets/add-newsletter-modal-CglVQqah.js +1 -0
  91. package/core/built/admin/assets/add-recommendation-modal-wz7BsuaG.js +1 -0
  92. package/core/built/admin/assets/analytics-C4HE1gBg.js +1 -0
  93. package/core/built/admin/assets/{announcement-bar-modal-BTHiy1ZO.js → announcement-bar-modal-Ci4zz8jO.js} +1 -1
  94. package/core/built/admin/assets/{api-keys-Boy5pLbD.js → api-keys-Ck-Yteiv.js} +1 -1
  95. package/core/built/admin/assets/audience-CtbA54Sn.js +1 -0
  96. package/core/built/admin/assets/{automated-emails-te1D5kq-.js → automated-emails-D5VVMND9.js} +1 -1
  97. package/core/built/admin/assets/automations-CzKt5fb8.js +1 -0
  98. package/core/built/admin/assets/bluesky-sharing-BEtJ_gL_.js +1 -0
  99. package/core/built/admin/assets/{box-By_EgGtm.js → box-CdfQAP_F.js} +1 -1
  100. package/core/built/admin/assets/{brand-icon-09YqFZjV.js → brand-icon-CrIGOA3Z.js} +1 -1
  101. package/core/built/admin/assets/{breadcrumb-CcFr_ltt.js → breadcrumb-zUrZrBtW.js} +1 -1
  102. package/core/built/admin/assets/{button-BshWPHvn.js → button-eNMKQWXr.js} +1 -1
  103. package/core/built/admin/assets/{card-CiiE7QfM.js → card--VNbfgo3.js} +1 -1
  104. package/core/built/admin/assets/{chart-BnXyfH11.js → chart-BrhA41Zi.js} +1 -1
  105. package/core/built/admin/assets/chart-helpers-CfBKt0vT.js +1 -0
  106. package/core/built/admin/assets/{checkbox-Dwwr_3Py.js → checkbox-CgOn_tKW.js} +1 -1
  107. package/core/built/admin/assets/{chunk.524.91ecb33e6afc3bd8949b.js → chunk.524.a697dee88db67fdf6021.js} +4 -4
  108. package/core/built/admin/assets/{chunk.582.512549909741883f960c.js → chunk.582.5ed5d124cfca9c259b9c.js} +6 -6
  109. package/core/built/admin/assets/{chunk.16.f76a6314082d813d67e0.js → chunk.598.7e056fabb47ce7dbd73f.js} +14 -14
  110. package/core/built/admin/assets/{code-editor-view-BwIdPy_k.js → code-editor-view-BYNoAoNV.js} +1 -1
  111. package/core/built/admin/assets/{code-editor-view-CtkF82Fv.js → code-editor-view-K2wI-I5f.js} +1 -1
  112. package/core/built/admin/assets/color-picker-Ddw80xX6.js +3 -0
  113. package/core/built/admin/assets/color-picker-field-D9nUhvA7.js +1 -0
  114. package/core/built/admin/assets/combobox-w9j8PPQT.js +1 -0
  115. package/core/built/admin/assets/command-BfpHORBv.js +1 -0
  116. package/core/built/admin/assets/comments-BLmCmyCs.js +1 -0
  117. package/core/built/admin/assets/confirmation-context-CBM8G0Vj.js +1 -0
  118. package/core/built/admin/assets/{container-LiZf3XdY.js → container-BuQG1wuP.js} +1 -1
  119. package/core/built/admin/assets/{content-api-modal-BtpNI92-.js → content-api-modal-TXRz3U7S.js} +1 -1
  120. package/core/built/admin/assets/context-menu-_QMdd3kp.js +1 -0
  121. package/core/built/admin/assets/{copy-field-CglgRZyG.js → copy-field-6N01S07E.js} +1 -1
  122. package/core/built/admin/assets/create-ghost-browse-value-source-qIBymvvf.js +1 -0
  123. package/core/built/admin/assets/custom-field-type-option-BddFlJFa.js +1 -0
  124. package/core/built/admin/assets/custom-integration-modal-DmNquxUV.js +1 -0
  125. package/core/built/admin/assets/{data-list-CupF7bjM.js → data-list-CA2jYGPq.js} +1 -1
  126. package/core/built/admin/assets/{date-range-select-JPwM0yUj.js → date-range-select-uvz_DtPh.js} +1 -1
  127. package/core/built/admin/assets/design-and-theme-modal-BSmo12Op.js +2 -0
  128. package/core/built/admin/assets/{detail-page-D8lx2SdP.js → detail-page-Dnv-CdR1.js} +1 -1
  129. package/core/built/admin/assets/dirty-confirm-dialog-BZ1iytEd.js +1 -0
  130. package/core/built/admin/assets/{disabled-sources-indicator-BTJ2ClQu.js → disabled-sources-indicator-DMRrxsiJ.js} +1 -1
  131. package/core/built/admin/assets/{dist-DzcfoDJ3.js → dist-8YJUlf3B.js} +1 -1
  132. package/core/built/admin/assets/{dist-Cb5RSHSg.js → dist-B3keLvjj.js} +1 -1
  133. package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
  134. package/core/built/admin/assets/{dist-BT_Z-eCn.js → dist-Dgt2cr6a.js} +1 -1
  135. package/core/built/admin/assets/domain-BNYrt0aD.js +1 -0
  136. package/core/built/admin/assets/dropzone-D7nFdAe5.js +5 -0
  137. package/core/built/admin/assets/edit-profile-C5Asm4LA.js +1 -0
  138. package/core/built/admin/assets/editor-REokrzci.js +8 -0
  139. package/core/built/admin/assets/{embed-signup-form-modal-BFTPf04i.js → embed-signup-form-modal-Ds6mPEi5.js} +1 -1
  140. package/core/built/admin/assets/{empty-indicator-WB1WgT9h.js → empty-indicator-D9QdpuNX.js} +1 -1
  141. package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
  142. package/core/built/admin/assets/explore-UY10Egsp.js +1 -0
  143. package/core/built/admin/assets/feature-image-placeholder-D1iF_8bc.js +1 -0
  144. package/core/built/admin/assets/feed-81C8mJWR.js +1 -0
  145. package/core/built/admin/assets/{field-LmNk7wZh.js → field-Dihp5p18.js} +1 -1
  146. package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
  147. package/core/built/admin/assets/filter-sources-BO9xUPj7.js +1 -0
  148. package/core/built/admin/assets/filters-CRUWecfY.js +1 -0
  149. package/core/built/admin/assets/filters-DirqNXjH.js +1 -0
  150. package/core/built/admin/assets/first-promoter-modal-CT6MxYZb.js +1 -0
  151. package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8eabfc1ece81b03cf7b90780d31487e8.css} +1 -1
  152. package/core/built/admin/assets/{ghost-403cb39badad3df411fc0ba27d220047.js → ghost-c2848508292937415f20f5a830eea59e.js} +31 -28
  153. package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-a7bebe2c561f55369dcf29f4c820f7ff.css} +1 -1
  154. package/core/built/admin/assets/gift-link-modal-CQVAye17.js +1 -0
  155. package/core/built/admin/assets/{grid-CUciBfjf.js → grid-Dj29PY05.js} +1 -1
  156. package/core/built/admin/assets/growth-BWIu-6xj.js +3 -0
  157. package/core/built/admin/assets/growth-DU29oxeA.js +1 -0
  158. package/core/built/admin/assets/{heading-CRZZ2FUe.js → heading-Dh5SFVjL.js} +1 -1
  159. package/core/built/admin/assets/history-modal-CFd1Hvx6.js +1 -0
  160. package/core/built/admin/assets/html-field-CJBCLTvv.js +1 -0
  161. package/core/built/admin/assets/{images-C0XvUYMb.js → images-scfkWZiK.js} +1 -1
  162. package/core/built/admin/assets/{inbox-DZXDUt4s.js → inbox-Mcp4DXZN.js} +14 -14
  163. package/core/built/admin/assets/index-6MkPdCtr.js +4 -0
  164. package/core/built/admin/assets/index-Bn7QhcZu.css +2 -0
  165. package/core/built/admin/assets/index.es-CNnuNH0d.js +1 -0
  166. package/core/built/admin/assets/{inline-Cw-gigDW.js → inline-BWSs_VzR.js} +1 -1
  167. package/core/built/admin/assets/{input-group-BPAxETpQ.js → input-group-CMhe2DvY.js} +1 -1
  168. package/core/built/admin/assets/{input-surface-BdOe4KzO.js → input-surface-BsrIZeSF.js} +1 -1
  169. package/core/built/admin/assets/{integration-header-B4DyXV06.js → integration-header-Bm6IDb1A.js} +1 -1
  170. package/core/built/admin/assets/invite-user-modal-DfheMXs0.js +1 -0
  171. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
  172. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
  173. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  174. package/core/built/admin/assets/{koenig-lexical-60O_8aiO.js → koenig-lexical-DBSqAuiI.js} +3 -3
  175. package/core/built/admin/assets/koenig-loader-aFQNlJlD.js +2 -0
  176. package/core/built/admin/assets/kpi-card-DBRMfGOW.js +1 -0
  177. package/core/built/admin/assets/{kpi-card-fUHZlzBX.js → kpi-card-DFafD1qq.js} +1 -1
  178. package/core/built/admin/assets/kpi-helpers-Cv8i8hns.js +1 -0
  179. package/core/built/admin/assets/kpi-tabs-BJItvLYm.js +1 -0
  180. package/core/built/admin/assets/{label-VIG969IC.js → label-BnSCvffu.js} +1 -1
  181. package/core/built/admin/assets/label-picker-KVoo91sh.js +1 -0
  182. package/core/built/admin/assets/layout-Bjv2Ll-5.js +1 -0
  183. package/core/built/admin/assets/{link-helpers-Dtq9fxQg.js → link-helpers-MVDdnFCY.js} +1 -1
  184. package/core/built/admin/assets/{list-page-CdsnQR9N.js → list-page-BucXJ0hi.js} +1 -1
  185. package/core/built/admin/assets/member-custom-fields-DDQV6QeG.js +1 -0
  186. package/core/built/admin/assets/member-detail-CdJF6Agw.js +1 -0
  187. package/core/built/admin/assets/members-DjQbq9Z2.js +4 -0
  188. package/core/built/admin/assets/{modal-page-BMTzFHVO.js → modal-page-xCivTMvI.js} +1 -1
  189. package/core/built/admin/assets/moderation-AgCIEso4.js +1 -0
  190. package/core/built/admin/assets/{multi-select-combobox-CGohnsxJ.js → multi-select-combobox-BcITkUVr.js} +1 -1
  191. package/core/built/admin/assets/navigation-modal-BkT7b1M2.js +1 -0
  192. package/core/built/admin/assets/newsletter-BMMAuvgq.js +1 -0
  193. package/core/built/admin/assets/newsletter-detail-modal-0SCJ7Zpm.js +1 -0
  194. package/core/built/admin/assets/{newsletter-emails-D5ql1rud.js → newsletter-emails-DKzwafuh.js} +1 -1
  195. package/core/built/admin/assets/newsletters-BRBb_uQC.js +1 -0
  196. package/core/built/admin/assets/note-DyGHtS9a.js +1 -0
  197. package/core/built/admin/assets/notifications-ZgWniKna.js +1 -0
  198. package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
  199. package/core/built/admin/assets/offers-container-modal-B-E8TIWr.js +1 -0
  200. package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-CzIsre-d.js} +1 -1
  201. package/core/built/admin/assets/onboarding-qg8Akovm.js +1 -0
  202. package/core/built/admin/assets/{onboarding-route-Cu_ROWPn.js → onboarding-route-CaavZulg.js} +1 -1
  203. package/core/built/admin/assets/overview-BW8GLeYi.js +1 -0
  204. package/core/built/admin/assets/overview-BkXZNzaZ.js +1 -0
  205. package/core/built/admin/assets/{page-header-Cfds8pCg.js → page-header-De0VzKBi.js} +1 -1
  206. package/core/built/admin/assets/pagemenu-B5KKCpbA.js +1 -0
  207. package/core/built/admin/assets/pages-jgaFm69d.js +1 -0
  208. package/core/built/admin/assets/pages-route-CIUAQxtY.js +1 -0
  209. package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
  210. package/core/built/admin/assets/{pintura-modal-TDTrJ89x.js → pintura-modal-BZ2J9w3n.js} +1 -1
  211. package/core/built/admin/assets/portal-frame-B6Hr9wHc.js +1 -0
  212. package/core/built/admin/assets/portal-modal-D4ceei3t.js +1 -0
  213. package/core/built/admin/assets/post-analytics-header-BYCsT0GP.js +1 -0
  214. package/core/built/admin/assets/post-analytics-ot7f6pih.js +1 -0
  215. package/core/built/admin/assets/{post-analytics-provider-Cu3jNeFh.js → post-analytics-provider-Bo1gmYaP.js} +1 -1
  216. package/core/built/admin/assets/{post-share-modal-P1_M6o-H.js → post-share-modal-C-PaYZ_e.js} +1 -1
  217. package/core/built/admin/assets/posts-DuGazgTb.js +1 -0
  218. package/core/built/admin/assets/posts-list-screen-CBGGgjjj.js +2 -0
  219. package/core/built/admin/assets/posts-route-D6xmS7Vf.js +1 -0
  220. package/core/built/admin/assets/preferences-C5YJLp74.js +5 -0
  221. package/core/built/admin/assets/{preview-chrome-BOVO6_PE.js → preview-chrome-BljUBlOk.js} +1 -1
  222. package/core/built/admin/assets/{preview-modal-MlTjP8UU.js → preview-modal-BfeFqi5y.js} +1 -1
  223. package/core/built/admin/assets/profile-B8mx2yAu.js +1 -0
  224. package/core/built/admin/assets/{radio-group-CjtmsCPl.js → radio-group-DczlLKOn.js} +1 -1
  225. package/core/built/admin/assets/{router-provider-CJC58zTy.js → router-provider-B0gZyiGJ.js} +1 -1
  226. package/core/built/admin/assets/{schemas-CRsC53ls.js → schemas-DppqmpeJ.js} +2 -2
  227. package/core/built/admin/assets/select-cb0t_TAJ.js +1 -0
  228. package/core/built/admin/assets/settings-DZqxR0Da.js +1 -0
  229. package/core/built/admin/assets/settings-DvfTNdHQ.js +4 -0
  230. package/core/built/admin/assets/{settings-breadcrumbs-sLDNedBW.js → settings-breadcrumbs-DLzbRRSt.js} +1 -1
  231. package/core/built/admin/assets/{shade-app-F7WxOyfk-nufqw1hd.js → shade-app-CcS3f8MZ-vwURazk8.js} +2 -2
  232. package/core/built/admin/assets/share-modal-D2-Bz1_I.js +1 -0
  233. package/core/built/admin/assets/{skeleton-D7hwjdry.js → skeleton-Ce9GgUpf.js} +1 -1
  234. package/core/built/admin/assets/slack-modal-DYDTUria.js +1 -0
  235. package/core/built/admin/assets/sort-button-VVeQjjbu.js +1 -0
  236. package/core/built/admin/assets/{source-icon-BPsD5ees.js → source-icon-Ck5_5Kgq.js} +1 -1
  237. package/core/built/admin/assets/{stack-CIfOAAVf.js → stack-B2eszIiq.js} +1 -1
  238. package/core/built/admin/assets/stats-Rjmk5owg.js +1 -0
  239. package/core/built/admin/assets/stats-view-BGGmkmgv.js +1 -0
  240. package/core/built/admin/assets/{step-1-CMta6YFO.js → step-1-CsaBjeN4.js} +1 -1
  241. package/core/built/admin/assets/{step-2-BG04nh5q.js → step-2-D2vnxOOM.js} +1 -1
  242. package/core/built/admin/assets/{step-3-ZnMaVIPj.js → step-3-wBoLdGEb.js} +2 -2
  243. package/core/built/admin/assets/{stripe-button-DDoUKN5a.js → stripe-button-CDgLz0S0.js} +1 -1
  244. package/core/built/admin/assets/stripe-connect-modal-CSjMJetP.js +1 -0
  245. package/core/built/admin/assets/{switch-C9djUIMO.js → switch-CI4gLWqb.js} +1 -1
  246. package/core/built/admin/assets/{table-CrqQtkR2.js → table-Do6iQ83Q.js} +1 -1
  247. package/core/built/admin/assets/{tabs-CGisSbWq.js → tabs-D2yWLMp_.js} +1 -1
  248. package/core/built/admin/assets/tag-detail-BhXlOsCa.js +2 -0
  249. package/core/built/admin/assets/tags-ldukRApe.js +1 -0
  250. package/core/built/admin/assets/testimonials-modal-CtnZBJKl.js +1 -0
  251. package/core/built/admin/assets/{text-DU9Hv33_.js → text-BQDSDsKs.js} +1 -1
  252. package/core/built/admin/assets/{textarea-d9qEkMOP.js → textarea-DJ1Q5V39.js} +1 -1
  253. package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +1 -0
  254. package/core/built/admin/assets/{toggle-group-CtKZURJd.js → toggle-group-ByUJsxwD.js} +1 -1
  255. package/core/built/admin/assets/{topic-filter-D8JT8Tq1.js → topic-filter-BgC3g5_v.js} +1 -1
  256. package/core/built/admin/assets/{transistor-modal-6PUf0idx.js → transistor-modal-Drr0SNfo.js} +1 -1
  257. package/core/built/admin/assets/trend-badge-6ye93YAW.js +1 -0
  258. package/core/built/admin/assets/{unsplash-modal-BPuDBPja.js → unsplash-modal-p6AoQoWp.js} +1 -1
  259. package/core/built/admin/assets/{use-analytics-data--opuzwcz.js → use-analytics-data-CWCMAESo.js} +1 -1
  260. package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
  261. package/core/built/admin/assets/use-check-theme-limit-error-Cw3WQHy8.js +2 -0
  262. package/core/built/admin/assets/use-filter-params-BIni9taJ.js +1 -0
  263. package/core/built/admin/assets/use-growth-stats-DCVG3s9w.js +1 -0
  264. package/core/built/admin/assets/{use-limiter-TDSNiHPB.js → use-limiter-D2WRRx0H.js} +1 -1
  265. package/core/built/admin/assets/{use-navigate-with-base-path-CK989MlC.js → use-navigate-with-base-path-BHPA228f.js} +1 -1
  266. package/core/built/admin/assets/{use-pintura-config-CnCGrDFk.js → use-pintura-config-h-J0Lvta.js} +1 -1
  267. package/core/built/admin/assets/{use-pintura-editor-ntphvtUd.js → use-pintura-editor-BfN1UwzH.js} +1 -1
  268. package/core/built/admin/assets/use-post-referrers-Czg47m8s.js +1 -0
  269. package/core/built/admin/assets/use-reply-chain-data-ns0caK8k.js +1 -0
  270. package/core/built/admin/assets/{use-router-history-entry-BwfQS2mq.js → use-router-history-entry-uldn7zJO.js} +1 -1
  271. package/core/built/admin/assets/{use-setting-group-DQxV42-O.js → use-setting-group-DpcuCUDg.js} +1 -1
  272. package/core/built/admin/assets/use-settings-navigation-CZjGrhsp.js +1 -0
  273. package/core/built/admin/assets/{use-simple-pagination-B2TdNX67.js → use-simple-pagination-DzJWobPR.js} +1 -1
  274. package/core/built/admin/assets/{use-staff-users-QrR9voeC.js → use-staff-users-Csipb-O0.js} +1 -1
  275. package/core/built/admin/assets/use-tinybird-query-CSnGXzZh.js +1 -0
  276. package/core/built/admin/assets/use-tinybird-token-DTOKRR7e.js +1 -0
  277. package/core/built/admin/assets/{use-unsaved-changes-guard-DpYJcj1d.js → use-unsaved-changes-guard-CBzs-KPi.js} +1 -1
  278. package/core/built/admin/assets/{use-url-input-WnIqckzS.js → use-url-input-DFr8lCbS.js} +1 -1
  279. package/core/built/admin/assets/user-detail-modal-B_iUClI6.js +1 -0
  280. package/core/built/admin/assets/users-Cg-OeGzC.js +1 -0
  281. package/core/built/admin/assets/{virtual-list-D3MfPNOh.js → virtual-list-BW-padMe.js} +1 -1
  282. package/core/built/admin/assets/web-C1v33ehA.js +2 -0
  283. package/core/built/admin/assets/web-C4BKzn2T.js +1 -0
  284. package/core/built/admin/assets/{zapier-modal-BO6PS_Vd.js → zapier-modal-BBFfI6Ml.js} +1 -1
  285. package/core/built/admin/index.html +24 -30
  286. package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
  287. package/core/frontend/helpers/cancel_link.js +2 -2
  288. package/core/frontend/helpers/pagination.js +2 -2
  289. package/core/frontend/helpers/social_accounts.js +2 -2
  290. package/core/frontend/public/ghost.css +1 -1
  291. package/core/frontend/public/ghost.min.css +1 -1
  292. package/core/frontend/services/rendering/renderer.js +15 -0
  293. package/core/frontend/services/sitemap/user-map-generator.js +9 -2
  294. package/core/server/adapters/storage/LocalStorageBase.js +8 -5
  295. package/core/server/api/endpoints/db.js +19 -5
  296. package/core/server/api/endpoints/index.js +6 -2
  297. package/core/server/api/endpoints/mail.js +1 -1
  298. package/core/server/api/endpoints/member-metafields.js +89 -0
  299. package/core/server/api/endpoints/members.js +4 -4
  300. package/core/server/api/endpoints/posts.js +4 -3
  301. package/core/server/api/endpoints/tiers-checkout-config.js +59 -0
  302. package/core/server/api/endpoints/utils/serializers/input/members.js +4 -7
  303. package/core/server/api/endpoints/utils/serializers/output/config.js +1 -0
  304. package/core/server/api/endpoints/utils/serializers/output/index.js +6 -2
  305. package/core/server/api/endpoints/utils/serializers/output/{member-custom-fields.js → member-metafields.js} +2 -4
  306. package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
  307. package/core/server/api/endpoints/utils/serializers/output/tiers-checkout-config.js +12 -0
  308. package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
  309. package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
  310. package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
  311. package/core/server/data/exporter/table-lists.js +3 -0
  312. package/core/server/data/importer/content-files.js +57 -0
  313. package/core/server/data/importer/handlers/image.js +2 -2
  314. package/core/server/data/importer/import-archive.js +131 -0
  315. package/core/server/data/importer/import-manager.js +18 -180
  316. package/core/server/data/importer/importers/content-file-importer.js +66 -4
  317. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  318. package/core/server/data/migrations/utils/migrations.js +1 -1
  319. package/core/server/data/migrations/versions/6.61/2026-08-19-14-30-20-add-written-by-to-members-custom-field-values.js +42 -0
  320. package/core/server/data/migrations/versions/6.61/2026-08-19-14-38-53-add-members-custom-field-bindings-table.js +26 -0
  321. package/core/server/data/migrations/versions/6.61/2026-08-19-14-48-06-add-tier-checkout-field-tables.js +35 -0
  322. package/core/server/data/schema/schema.js +90 -0
  323. package/core/server/data/seeders/importers/automation-action-revisions-importer.js +3 -3
  324. package/core/server/data/seeders/importers/automation-actions-importer.js +3 -3
  325. package/core/server/data/seeders/importers/automation-run-steps-importer.js +3 -3
  326. package/core/server/data/seeders/importers/automation-runs-importer.js +5 -5
  327. package/core/server/data/seeders/importers/automations-importer.js +3 -3
  328. package/core/server/data/seeders/importers/comment-reports-importer.js +1 -1
  329. package/core/server/data/seeders/importers/comments-importer.js +1 -1
  330. package/core/server/data/seeders/importers/email-batches-importer.js +1 -1
  331. package/core/server/data/seeders/importers/email-recipients-importer.js +1 -1
  332. package/core/server/data/seeders/importers/emails-importer.js +1 -1
  333. package/core/server/data/seeders/importers/labels-importer.js +1 -1
  334. package/core/server/data/seeders/importers/members-click-events-importer.js +1 -1
  335. package/core/server/data/seeders/importers/members-created-events-importer.js +1 -1
  336. package/core/server/data/seeders/importers/members-feedback-importer.js +1 -1
  337. package/core/server/data/seeders/importers/members-importer.js +1 -1
  338. package/core/server/data/seeders/importers/members-login-events-importer.js +1 -1
  339. package/core/server/data/seeders/importers/members-products-importer.js +1 -1
  340. package/core/server/data/seeders/importers/members-status-events-importer.js +1 -1
  341. package/core/server/data/seeders/importers/members-stripe-customers-importer.js +1 -1
  342. package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +1 -1
  343. package/core/server/data/seeders/importers/members-subscribe-events-importer.js +1 -1
  344. package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +1 -1
  345. package/core/server/data/seeders/importers/offer-redemptions-importer.js +1 -1
  346. package/core/server/data/seeders/importers/offers-importer.js +1 -1
  347. package/core/server/data/seeders/importers/posts-importer.js +1 -1
  348. package/core/server/data/seeders/importers/table-importer.js +2 -2
  349. package/core/server/data/seeders/importers/tags-importer.js +1 -1
  350. package/core/server/data/seeders/importers/users-importer.js +1 -1
  351. package/core/server/data/seeders/importers/web-mentions-importer.js +1 -1
  352. package/core/server/data/seeders/utils/random.js +3 -3
  353. package/core/server/ghost-server.js +3 -2
  354. package/core/server/lib/db-types/boolean.js +18 -0
  355. package/core/server/lib/image/image-size.js +24 -0
  356. package/core/server/lib/package-json/parse.js +2 -2
  357. package/core/server/lib/promise-pool.js +31 -0
  358. package/core/server/models/member.js +6 -17
  359. package/core/server/models/post.js +2 -2
  360. package/core/server/models/relations/authors.js +2 -16
  361. package/core/server/models/user.js +9 -2
  362. package/core/server/services/auth/passwordreset.js +13 -0
  363. package/core/server/services/automations/database-automations-repository.js +26 -26
  364. package/core/server/services/automations/poll.js +1 -0
  365. package/core/server/services/comments/comments-controller.js +30 -9
  366. package/core/server/services/comments/comments-service.js +55 -5
  367. package/core/server/services/content-import/csv/formula.js +12 -0
  368. package/core/server/services/content-import/csv/index.js +6 -1
  369. package/core/server/services/content-import/csv/parse.js +27 -6
  370. package/core/server/services/content-import/csv/serialize.js +13 -0
  371. package/core/server/services/content-import/import/assets.js +74 -0
  372. package/core/server/services/content-import/import/completion-email.js +164 -0
  373. package/core/server/services/content-import/import/errors-file.js +36 -0
  374. package/core/server/services/content-import/import/importer.js +204 -54
  375. package/core/server/services/content-import/import/local-media-url.js +63 -0
  376. package/core/server/services/content-import/import/media.js +254 -0
  377. package/core/server/services/content-import/import/post-data.js +1 -1
  378. package/core/server/services/content-import/import/post-link.js +11 -0
  379. package/core/server/services/content-import/import/post-repository.js +100 -0
  380. package/core/server/services/content-import/import/reader.js +9 -2
  381. package/core/server/services/content-import/import/relations.js +149 -0
  382. package/core/server/services/content-import/import/report.js +34 -0
  383. package/core/server/services/content-import/import/row.js +11 -2
  384. package/core/server/services/content-import/import/schema.js +30 -0
  385. package/core/server/services/content-import/import/source.js +125 -0
  386. package/core/server/services/content-import/import/staged-file.js +29 -0
  387. package/core/server/services/content-import/import/store.js +25 -2
  388. package/core/server/services/content-import/index.js +58 -34
  389. package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
  390. package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
  391. package/core/server/services/custom-redirects/redirects-service.js +1 -1
  392. package/core/server/services/custom-redirects/validation.js +1 -1
  393. package/core/server/services/email-address/email-address-parser.js +30 -38
  394. package/core/server/services/email-address/email-address-service.js +37 -4
  395. package/core/server/services/email-analytics/email-analytics-service.js +8 -1
  396. package/core/server/services/email-analytics/index.js +2 -7
  397. package/core/server/services/email-analytics/lib/queries.js +7 -1
  398. package/core/server/services/email-service/batch-sending-service.js +0 -4
  399. package/core/server/services/email-service/email-renderer.js +14 -4
  400. package/core/server/services/email-service/email-service-wrapper.js +0 -9
  401. package/core/server/services/email-service/mailgun-email-provider.js +20 -9
  402. package/core/server/services/gift-links/schema.js +3 -3
  403. package/core/server/services/gifts/CONTEXT.md +1 -1
  404. package/core/server/services/gifts/constants.js +1 -1
  405. package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
  406. package/core/server/services/gifts/gift-bookshelf-repository.js +2 -2
  407. package/core/server/services/gifts/gift-delivery-bookshelf-repository.js +18 -9
  408. package/core/server/services/gifts/gift-delivery-schema.js +5 -5
  409. package/core/server/services/gifts/gift-delivery-service.js +4 -0
  410. package/core/server/services/gifts/gift-email-service.js +0 -1
  411. package/core/server/services/gifts/gift-schema.js +10 -10
  412. package/core/server/services/gifts/gift-service.js +4 -2
  413. package/core/server/services/gifts/index.js +3 -3
  414. package/core/server/services/gifts/jobs/index.js +4 -4
  415. package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
  416. package/core/server/services/invitations/accept.js +4 -2
  417. package/core/server/services/jobs/job-service.js +0 -9
  418. package/core/server/services/jobs-service/register-job-handlers.js +25 -15
  419. package/core/server/services/lib/mailgun-client.js +44 -8
  420. package/core/server/services/mail/ghost-mailer.js +4 -4
  421. package/core/server/services/media-inliner/external-media-inliner-job.js +12 -0
  422. package/core/server/services/media-inliner/external-media-inliner.js +103 -29
  423. package/core/server/services/media-inliner/service.js +13 -41
  424. package/core/server/services/media-inliner/types.js +2 -0
  425. package/core/server/services/member-welcome-emails/service.js +7 -7
  426. package/core/server/services/members/api.js +1 -0
  427. package/core/server/services/members/import-export/csv/parse.js +0 -7
  428. package/core/server/services/members/import-export/export/exporter.js +4 -6
  429. package/core/server/services/members/import-export/import/completion-email.js +2 -5
  430. package/core/server/services/members/import-export/import/importer.js +21 -5
  431. package/core/server/services/members/import-export/import/row.js +0 -3
  432. package/core/server/services/members/import-export/import/stripe-utils.js +6 -1
  433. package/core/server/services/members/import-export/index.js +10 -12
  434. package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
  435. package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
  436. package/core/server/services/members/jobs/index.js +48 -24
  437. package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
  438. package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
  439. package/core/server/services/members/members-api/members-api.js +9 -6
  440. package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
  441. package/core/server/services/members/members-api/services/member-bread-service.js +53 -63
  442. package/core/server/services/members/members-api/services/payments-service.js +47 -1
  443. package/core/server/services/members/service.js +1 -5
  444. package/core/server/services/members-custom-fields/actions.js +27 -1
  445. package/core/server/services/members-custom-fields/bindings-service.js +120 -0
  446. package/core/server/services/members-custom-fields/codec.js +3 -4
  447. package/core/server/services/members-custom-fields/definitions-service.js +165 -22
  448. package/core/server/services/members-custom-fields/filter.js +75 -93
  449. package/core/server/services/members-custom-fields/index.js +11 -4
  450. package/core/server/services/members-custom-fields/key.js +2 -1
  451. package/core/server/services/members-custom-fields/models.js +1 -1
  452. package/core/server/services/members-custom-fields/queries.js +5 -0
  453. package/core/server/services/members-custom-fields/schema.js +37 -6
  454. package/core/server/services/members-custom-fields/serializers.js +3 -5
  455. package/core/server/services/members-custom-fields/values-service.js +65 -31
  456. package/core/server/services/mentions/mention-controller.js +23 -21
  457. package/core/server/services/mentions/process-webmention-job.js +16 -0
  458. package/core/server/services/mentions/service.js +8 -4
  459. package/core/server/services/public-config/config.js +7 -0
  460. package/core/server/services/route-settings/validation-errors.js +1 -1
  461. package/core/server/services/route-settings/yaml-parser.js +1 -1
  462. package/core/server/services/settings/settings-service.js +1 -8
  463. package/core/server/services/settings-helpers/settings-helpers.js +4 -6
  464. package/core/server/services/slack-ping/slack-ping-service.js +1 -1
  465. package/core/server/services/staff/staff-service-emails.js +2 -2
  466. package/core/server/services/stripe/config.js +14 -8
  467. package/core/server/services/stripe/service.js +10 -1
  468. package/core/server/services/stripe/services/checkout/completed-session.js +68 -0
  469. package/core/server/services/stripe/services/checkout/session-options.js +100 -0
  470. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +71 -1
  471. package/core/server/services/stripe/stripe-api.js +31 -0
  472. package/core/server/services/stripe/stripe-service.js +26 -9
  473. package/core/server/services/stripe/webhook-controller.js +10 -0
  474. package/core/server/services/tier-checkout-config/codec.js +99 -0
  475. package/core/server/services/tier-checkout-config/index.js +26 -0
  476. package/core/server/services/tier-checkout-config/models.js +63 -0
  477. package/core/server/services/tier-checkout-config/queries.js +80 -0
  478. package/core/server/services/tier-checkout-config/schema.js +33 -0
  479. package/core/server/services/tier-checkout-config/serializers.js +128 -0
  480. package/core/server/services/tier-checkout-config/service.js +304 -0
  481. package/core/server/services/tiers/service.js +21 -0
  482. package/core/server/services/update-check/index.js +13 -13
  483. package/core/server/services/update-check/jobs/update-check-job.js +7 -0
  484. package/core/server/services/update-check/update-check-service.js +2 -2
  485. package/core/server/web/admin/controller.js +1 -1
  486. package/core/server/web/api/endpoints/admin/routes.js +34 -20
  487. package/core/server/web/api/middleware/upload.js +2 -2
  488. package/core/server/web/parent/app.js +5 -0
  489. package/core/server/web/parent/middleware/filter-query-parameters.js +94 -0
  490. package/core/server/web/parent/middleware/index.js +1 -0
  491. package/core/server/web/query-parameter-policy/index.js +9 -0
  492. package/core/server/web/query-parameter-policy/policy.json +58 -0
  493. package/core/server/web/query-parameter-policy/schema.js +38 -0
  494. package/core/shared/config/defaults.json +3 -0
  495. package/core/shared/config/env/config.testing-mysql.json +4 -1
  496. package/core/shared/config/env/config.testing.json +3 -0
  497. package/core/shared/config/overrides.json +4 -2
  498. package/core/shared/labs.js +9 -15
  499. package/package.json +25 -25
  500. package/pnpm-lock.yaml +741 -108
  501. package/pnpm-workspace.yaml +12 -9
  502. package/tsconfig.json +2 -3
  503. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  504. package/core/built/admin/assets/Combination-gnJO3vIw.js +0 -41
  505. package/core/built/admin/assets/account-migration-8qTEI1i1.js +0 -1
  506. package/core/built/admin/assets/activitypub/inbox-DQ5CwLma.js +0 -1284
  507. package/core/built/admin/assets/activitypub/label-B72sfvEU.js +0 -16
  508. package/core/built/admin/assets/activitypub/layout-CXajhRsL.js +0 -1
  509. package/core/built/admin/assets/activitypub/settings-71gCm3SO.js +0 -315
  510. package/core/built/admin/assets/add-integration-modal--YpTq3c0.js +0 -1
  511. package/core/built/admin/assets/add-newsletter-modal-C8Ix2hol.js +0 -1
  512. package/core/built/admin/assets/add-recommendation-modal-CScuNFz4.js +0 -1
  513. package/core/built/admin/assets/alert-dialog-wEbVxANM.js +0 -1
  514. package/core/built/admin/assets/analytics-Cnji45H5.js +0 -1
  515. package/core/built/admin/assets/app-utils-D2Wp7ZSS.js +0 -1
  516. package/core/built/admin/assets/audience-DTLMXAFH.js +0 -1
  517. package/core/built/admin/assets/automations-BWpRCZ_f.js +0 -1
  518. package/core/built/admin/assets/bluesky-sharing-DHOpQxff.js +0 -1
  519. package/core/built/admin/assets/chart-helpers-B3OqQ6Ez.js +0 -1
  520. package/core/built/admin/assets/color-picker-Bmo1r9Fc.js +0 -3
  521. package/core/built/admin/assets/color-picker-field-DywowPhF.js +0 -1
  522. package/core/built/admin/assets/combobox-C4QCh6Yw.js +0 -1
  523. package/core/built/admin/assets/command-DcLbSifC.js +0 -1
  524. package/core/built/admin/assets/comments-Bxy_3WyE.js +0 -1
  525. package/core/built/admin/assets/confirmation-context-CLFHhyyH.js +0 -1
  526. package/core/built/admin/assets/custom-field-type-option-D0PXoSnP.js +0 -10
  527. package/core/built/admin/assets/custom-integration-modal-DCIHKN33.js +0 -1
  528. package/core/built/admin/assets/design-and-theme-modal-CZ-PkW7o.js +0 -23
  529. package/core/built/admin/assets/dialog-Db7c164G.js +0 -1
  530. package/core/built/admin/assets/dirty-confirm-dialog-CmARpZQS.js +0 -1
  531. package/core/built/admin/assets/dist-QLZuGq7o2.js +0 -1
  532. package/core/built/admin/assets/domain-D0SAtc-T.js +0 -1
  533. package/core/built/admin/assets/dropzone-CaPOeDRZ.js +0 -5
  534. package/core/built/admin/assets/edit-profile-By7v5XW5.js +0 -1
  535. package/core/built/admin/assets/editor-COXn4Atu.js +0 -8
  536. package/core/built/admin/assets/explore-BsNYrubV.js +0 -1
  537. package/core/built/admin/assets/feed-8RR1O1bK.js +0 -1
  538. package/core/built/admin/assets/filter-sources-4C0kF1NU.js +0 -1
  539. package/core/built/admin/assets/filters-CV5jCb9n.js +0 -1
  540. package/core/built/admin/assets/filters-Dmr0PoqU.js +0 -1
  541. package/core/built/admin/assets/first-promoter-modal-OCzSaL3B.js +0 -1
  542. package/core/built/admin/assets/gift-link-modal-0mzjn5oF.js +0 -1
  543. package/core/built/admin/assets/growth-55vWlGT_.js +0 -1
  544. package/core/built/admin/assets/growth-DA5AluYw.js +0 -3
  545. package/core/built/admin/assets/history-modal-G1s5hHz7.js +0 -1
  546. package/core/built/admin/assets/html-field-BegxsWpw.js +0 -1
  547. package/core/built/admin/assets/index-CDP9tIOk.js +0 -4
  548. package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
  549. package/core/built/admin/assets/index.es-BMUCj9TR.js +0 -1
  550. package/core/built/admin/assets/input-UHrKuvBT.js +0 -1
  551. package/core/built/admin/assets/invite-user-modal-BrAkxEO3.js +0 -1
  552. package/core/built/admin/assets/koenig-loader-DwVY_V-H.js +0 -1
  553. package/core/built/admin/assets/kpi-card-LERqWBoY.js +0 -1
  554. package/core/built/admin/assets/kpi-helpers-DB3ouhYF.js +0 -1
  555. package/core/built/admin/assets/kpi-tabs-BGvtMD8S.js +0 -1
  556. package/core/built/admin/assets/label-picker-BBWykUeA.js +0 -1
  557. package/core/built/admin/assets/layout-Di5K7doM.js +0 -1
  558. package/core/built/admin/assets/loading-indicator-SFTqyYVE.js +0 -1
  559. package/core/built/admin/assets/member-custom-fields-gOv6Hoh3.js +0 -1
  560. package/core/built/admin/assets/member-detail-D7mZDDp3.js +0 -1
  561. package/core/built/admin/assets/member-route-0Aa52Ntz.js +0 -1
  562. package/core/built/admin/assets/members-DvZG9t69.js +0 -2
  563. package/core/built/admin/assets/moderation-DzzPLDyl.js +0 -1
  564. package/core/built/admin/assets/navigation-modal-CI8Bx5vn.js +0 -1
  565. package/core/built/admin/assets/newsletter-Bg3cq5U-.js +0 -1
  566. package/core/built/admin/assets/newsletter-detail-modal-DQU3r4g2.js +0 -1
  567. package/core/built/admin/assets/newsletters-DMDfZbMS.js +0 -1
  568. package/core/built/admin/assets/note-i8k6pjaw.js +0 -1
  569. package/core/built/admin/assets/notifications-psA_2Ph4.js +0 -1
  570. package/core/built/admin/assets/offers-container-modal-BWfjSdyg.js +0 -1
  571. package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
  572. package/core/built/admin/assets/overview-C-6xOLaf.js +0 -1
  573. package/core/built/admin/assets/overview-DaLhpRrC.js +0 -1
  574. package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
  575. package/core/built/admin/assets/popover-CFgqFDvC.js +0 -1
  576. package/core/built/admin/assets/portal-frame-DjBF-uy2.js +0 -1
  577. package/core/built/admin/assets/portal-modal-Cf0pBAk8.js +0 -1
  578. package/core/built/admin/assets/post-analytics-Buz1COoY.js +0 -1
  579. package/core/built/admin/assets/post-analytics-header-B-P0eFnT.js +0 -1
  580. package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
  581. package/core/built/admin/assets/preferences-Cq1aOiLy.js +0 -5
  582. package/core/built/admin/assets/profile-D6dHYf2o.js +0 -1
  583. package/core/built/admin/assets/select-D_RQaXgt.js +0 -1
  584. package/core/built/admin/assets/settings-B5hJKZ5C.js +0 -1
  585. package/core/built/admin/assets/settings-DIo_F-MF.js +0 -4
  586. package/core/built/admin/assets/share-modal-CLBfj377.js +0 -1
  587. package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
  588. package/core/built/admin/assets/slack-modal-Bt9I_tEo.js +0 -1
  589. package/core/built/admin/assets/sort-button-DMBXF7tP.js +0 -1
  590. package/core/built/admin/assets/stats-B_YkF7bp.js +0 -1
  591. package/core/built/admin/assets/stats-view-BOCp9RG8.js +0 -1
  592. package/core/built/admin/assets/stripe-connect-modal-BeSukI8q.js +0 -1
  593. package/core/built/admin/assets/tag-detail-2a3BfzTW.js +0 -2
  594. package/core/built/admin/assets/tags-Dp2_8UzL.js +0 -1
  595. package/core/built/admin/assets/testimonials-modal-C9nrypNo.js +0 -1
  596. package/core/built/admin/assets/tier-detail-modal-CxRwgTPR.js +0 -1
  597. package/core/built/admin/assets/use-check-theme-limit-error-C9-QhGdV.js +0 -1
  598. package/core/built/admin/assets/use-filter-params-CSpAvgD2.js +0 -1
  599. package/core/built/admin/assets/use-growth-stats-BOmoPDHJ.js +0 -1
  600. package/core/built/admin/assets/use-post-referrers-CbXLFIex.js +0 -1
  601. package/core/built/admin/assets/use-reply-chain-data-JYFKSO83.js +0 -1
  602. package/core/built/admin/assets/use-settings-navigation-BBzro2-V.js +0 -1
  603. package/core/built/admin/assets/use-tinybird-query-D2Aeoty5.js +0 -39
  604. package/core/built/admin/assets/use-tinybird-token-DBuwMmln.js +0 -1
  605. package/core/built/admin/assets/user-detail-modal-59mBJqxN.js +0 -1
  606. package/core/built/admin/assets/users-5msE1WMs.js +0 -1
  607. package/core/built/admin/assets/web-DUuX7nE2.js +0 -2
  608. package/core/built/admin/assets/web-N8ucs2aG.js +0 -1
  609. package/core/server/api/endpoints/member-custom-fields.js +0 -100
  610. package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
  611. package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
  612. package/core/server/services/update-check/run-update-check.js +0 -63
  613. /package/core/server/lib/{db-date.js → db-types/date.js} +0 -0
@@ -37,25 +37,35 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.default = registerJobHandlers;
40
- const errors_1 = __importDefault(require("@tryghost/errors"));
41
- const index_1 = require("./index");
42
40
  const clean_tokens_job_1 = __importDefault(require("../members/jobs/clean-tokens-job"));
43
- const clean_tokens_task_1 = __importDefault(require("../members/jobs/clean-tokens-task"));
44
- const gifts = __importStar(require("../gifts"));
41
+ const clean_expired_comped_job_1 = __importDefault(require("../members/jobs/clean-expired-comped-job"));
45
42
  const clean_gifts_job_1 = __importDefault(require("../gifts/jobs/clean-gifts-job"));
46
- const logging = require('@tryghost/logging');
47
- function registerJobHandlers() {
48
- const jobsService = (0, index_1.getInstance)();
49
- const db = require('../../data/db');
43
+ const external_media_inliner_job_1 = __importDefault(require("../media-inliner/external-media-inliner-job"));
44
+ const content_csv_import_job_1 = __importDefault(require("../content-import/jobs/content-csv-import-job"));
45
+ const contentImport = __importStar(require("../content-import"));
46
+ const update_check_job_1 = __importDefault(require("../update-check/jobs/update-check-job"));
47
+ const process_webmention_job_1 = __importDefault(require("../mentions/process-webmention-job"));
48
+ const updateCheck = require('../update-check');
49
+ function registerJobHandlers({ jobsService, memberJobs, giftService, mediaInliner, mentionsController, }) {
50
50
  jobsService.handle(clean_tokens_job_1.default, async () => {
51
- await (0, clean_tokens_task_1.default)({ db, logging });
51
+ await memberJobs.cleanTokens();
52
+ });
53
+ jobsService.handle(clean_expired_comped_job_1.default, async () => {
54
+ await memberJobs.cleanExpiredComped();
52
55
  });
53
56
  jobsService.handle(clean_gifts_job_1.default, async () => {
54
- if (!gifts.service) {
55
- throw new errors_1.default.IncorrectUsageError({
56
- message: 'clean-gifts ran before the gifts service was initialised',
57
- });
58
- }
59
- await gifts.service.cleanup();
57
+ await giftService.cleanup();
58
+ });
59
+ jobsService.handle(external_media_inliner_job_1.default, async (job) => {
60
+ await mediaInliner.inline(job.domains);
61
+ });
62
+ jobsService.handle(content_csv_import_job_1.default, async (job) => {
63
+ await contentImport.handleJob(job);
64
+ });
65
+ jobsService.handle(update_check_job_1.default, async () => {
66
+ await updateCheck({ rethrowErrors: true });
67
+ });
68
+ jobsService.handle(process_webmention_job_1.default, async (job) => {
69
+ await mentionsController.processWebmention(job);
60
70
  });
61
71
  }
@@ -165,8 +165,8 @@ module.exports = class MailgunClient {
165
165
  * @param {Object} mailgunOptions
166
166
  * @param {Function} batchHandler
167
167
  * @param {Object} options
168
- * @param {number} [options.maxEvents] Not a strict maximum. We stop fetching after we reached the maximum AND received at least one event after begin (not equal) to prevent deadlocks.
169
- * @returns {Promise<void>}
168
+ * @param {number} [options.maxEvents] Per-domain soft maximum. We stop fetching a domain after we reached the maximum AND received at least one event after begin (not equal) to prevent deadlocks.
169
+ * @returns {Promise<{safeCursor?: Date} | void>}
170
170
  */
171
171
  async fetchEvents(mailgunOptions, batchHandler, { maxEvents = Infinity } = {}) {
172
172
  const mailgunInstance = this.getInstance();
@@ -184,12 +184,33 @@ module.exports = class MailgunClient {
184
184
  // Determine which domains to fetch from
185
185
  const domains = this.#getDomainsToFetch(mailgunConfig);
186
186
 
187
+ const cappedDomainCursors = [];
188
+
187
189
  // Fetch events from each domain
188
190
  for (const domain of domains) {
189
- await this.#fetchEventsFromDomain(domain, mailgunInstance, mailgunOptions, batchHandler, {
190
- maxEvents,
191
- });
191
+ const result = await this.#fetchEventsFromDomain(
192
+ domain,
193
+ mailgunInstance,
194
+ mailgunOptions,
195
+ batchHandler,
196
+ { maxEvents },
197
+ );
198
+
199
+ if (
200
+ result.capped &&
201
+ result.lastEventTimestamp &&
202
+ Number.isFinite(result.lastEventTimestamp.getTime())
203
+ ) {
204
+ cappedDomainCursors.push(result.lastEventTimestamp);
205
+ }
192
206
  }
207
+
208
+ const safeCursor = cappedDomainCursors.reduce(
209
+ (earliest, cursor) => (!earliest || cursor < earliest ? cursor : earliest),
210
+ undefined,
211
+ );
212
+
213
+ return { safeCursor };
193
214
  }
194
215
 
195
216
  /**
@@ -220,7 +241,7 @@ module.exports = class MailgunClient {
220
241
  * @param {Function} batchHandler
221
242
  * @param {Object} options
222
243
  * @param {number} options.maxEvents
223
- * @returns {Promise<void>}
244
+ * @returns {Promise<{capped: boolean, eventCount: number, lastEventTimestamp?: Date}>}
224
245
  */
225
246
  async #fetchEventsFromDomain(
226
247
  domain,
@@ -235,6 +256,9 @@ module.exports = class MailgunClient {
235
256
 
236
257
  let batchCount = 0;
237
258
  let totalBatchTime = 0;
259
+ let eventCount = 0;
260
+ let lastEventTimestamp;
261
+ let capped = false;
238
262
 
239
263
  try {
240
264
  let page = await this.getEventsFromMailgun(mailgunInstance, domain, mailgunOptions);
@@ -248,7 +272,6 @@ module.exports = class MailgunClient {
248
272
  `[MailgunClient fetchEventsFromDomain ${domain}]: finished fetching first page with ${events.length} events`,
249
273
  );
250
274
 
251
- let eventCount = 0;
252
275
  const beginTimestamp = mailgunOptions.begin
253
276
  ? Math.ceil(mailgunOptions.begin * 1000)
254
277
  : undefined; // ceil here if we have rounding errors
@@ -263,6 +286,13 @@ module.exports = class MailgunClient {
263
286
  totalBatchTime += batchDuration;
264
287
 
265
288
  eventCount += events.length;
289
+ const batchLastEventTimestamp = events[events.length - 1].timestamp;
290
+ if (
291
+ batchLastEventTimestamp &&
292
+ (!lastEventTimestamp || batchLastEventTimestamp > lastEventTimestamp)
293
+ ) {
294
+ lastEventTimestamp = batchLastEventTimestamp;
295
+ }
266
296
 
267
297
  if (
268
298
  eventCount >= maxEvents &&
@@ -270,6 +300,7 @@ module.exports = class MailgunClient {
270
300
  !events[events.length - 1].timestamp ||
271
301
  events[events.length - 1].timestamp.getTime() > beginTimestamp)
272
302
  ) {
303
+ capped = true;
273
304
  break;
274
305
  }
275
306
 
@@ -294,10 +325,15 @@ module.exports = class MailgunClient {
294
325
  const overallEndTime = Date.now();
295
326
  const totalDuration = overallEndTime - overallStartTime;
296
327
  const averageBatchTime = batchCount > 0 ? totalBatchTime / batchCount : 0;
328
+ const cursor = Number.isFinite(lastEventTimestamp?.getTime())
329
+ ? lastEventTimestamp.toISOString()
330
+ : 'none';
297
331
 
298
332
  logging.info(
299
- `[MailgunClient fetchEventsFromDomain ${domain}]: Processed ${batchCount} batches in ${(totalDuration / 1000).toFixed(2)}s. Average batch time: ${(averageBatchTime / 1000).toFixed(2)}s`,
333
+ `[MailgunClient fetchEventsFromDomain ${domain}]: Processed ${eventCount} events in ${batchCount} batches in ${(totalDuration / 1000).toFixed(2)}s. Average batch time: ${(averageBatchTime / 1000).toFixed(2)}s. Status: ${capped ? 'capped' : 'exhausted'}. Cursor: ${cursor}`,
300
334
  );
335
+
336
+ return { capped, eventCount, lastEventTimestamp };
301
337
  } catch (error) {
302
338
  logging.error(`[MailgunClient fetchEventsFromDomain ${domain}]: Error fetching events`);
303
339
  logging.error(error);
@@ -17,7 +17,7 @@ const messages = {
17
17
  reason: ' Reason: {reason}.',
18
18
  messageSent: 'Message sent. Double check inbox and spam folder!',
19
19
  };
20
- const EmailAddressParser = require('../email-address/email-address-parser');
20
+ const emailAddressParser = require('../email-address/email-address-parser');
21
21
  const DEFAULT_TAGS = ['ghost-email', 'transactional-email'];
22
22
  const MAX_MAILGUN_TAGS = 10;
23
23
 
@@ -54,8 +54,8 @@ function getFromAddress(requestedFromAddress, requestedReplyToAddress) {
54
54
  }
55
55
 
56
56
  return {
57
- from: EmailAddressParser.stringify(addresses.from),
58
- replyTo: addresses.replyTo ? EmailAddressParser.stringify(addresses.replyTo) : null,
57
+ from: emailAddressParser.stringify(addresses.from),
58
+ replyTo: addresses.replyTo ? emailAddressParser.stringify(addresses.replyTo) : null,
59
59
  };
60
60
  }
61
61
 
@@ -100,7 +100,7 @@ function createMessage(message) {
100
100
  */
101
101
  function createMailError({ message, err, ignoreDefaultMessage } = { message: '' }) {
102
102
  const helpMessage = tpl(messages.checkEmailConfigInstructions, {
103
- url: 'https://ghost.org/docs/config/#mail',
103
+ url: 'https://docs.ghost.org/config/#mail',
104
104
  });
105
105
  const defaultErrorMessage = tpl(messages.failedSendingEmailError);
106
106
 
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const job_1 = require("../jobs-service/job");
4
+ class ExternalMediaInlinerJob extends job_1.Job {
5
+ static type = 'external-media-inliner';
6
+ domains;
7
+ constructor({ domains }) {
8
+ super();
9
+ this.domains = domains;
10
+ }
11
+ }
12
+ exports.default = ExternalMediaInlinerJob;
@@ -177,6 +177,96 @@ class ExternalMediaInliner {
177
177
  }
178
178
  }
179
179
 
180
+ /**
181
+ * Download and store one external media URL without deciding where it came from
182
+ * or where its replacement belongs. Callers own discovery and replacement.
183
+ *
184
+ * @param {string} sourceUrl
185
+ * @returns {Promise<import('./types').ExternalMediaImportResult>}
186
+ */
187
+ async importUrl(sourceUrl) {
188
+ let response;
189
+ try {
190
+ response = await this.getRemoteMedia(sourceUrl);
191
+ } catch (error) {
192
+ return {
193
+ status: 'failed',
194
+ sourceUrl,
195
+ stage: 'download',
196
+ reason: 'The media file could not be downloaded.',
197
+ error,
198
+ };
199
+ }
200
+
201
+ if (!response) {
202
+ return {
203
+ status: 'failed',
204
+ sourceUrl,
205
+ stage: 'download',
206
+ reason: 'The media file could not be downloaded.',
207
+ };
208
+ }
209
+
210
+ let media;
211
+ try {
212
+ media = await this.extractFileDataFromResponse(sourceUrl, response);
213
+ } catch (error) {
214
+ return {
215
+ status: 'failed',
216
+ sourceUrl,
217
+ stage: 'extract',
218
+ reason: 'The downloaded media file could not be read.',
219
+ error,
220
+ };
221
+ }
222
+
223
+ try {
224
+ const storedUrl = await this.storeMediaLocally(media);
225
+ if (!storedUrl) {
226
+ return {
227
+ status: 'failed',
228
+ sourceUrl,
229
+ stage: 'unsupported',
230
+ reason: 'No configured storage accepts this media file.',
231
+ };
232
+ }
233
+
234
+ return {
235
+ status: 'stored',
236
+ sourceUrl,
237
+ storedUrl,
238
+ };
239
+ } catch (error) {
240
+ return {
241
+ status: 'failed',
242
+ sourceUrl,
243
+ stage: 'storage',
244
+ reason: 'The media file could not be stored in Ghost.',
245
+ error,
246
+ };
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Convert an import result into the replacement URL expected by the existing
252
+ * content and field processing. Expected download and unsupported-file failures
253
+ * return null so the original URL remains unchanged. Results containing an
254
+ * underlying processing error are rethrown so the established per-resource
255
+ * catch boundary continues to log and isolate them.
256
+ *
257
+ * @param {import('./types').ExternalMediaImportResult} result
258
+ * @returns {string|null}
259
+ */
260
+ #replacementUrlFromImportResult(result) {
261
+ if (result.status === 'stored') {
262
+ return result.storedUrl;
263
+ }
264
+ if ('error' in result) {
265
+ throw result.error;
266
+ }
267
+ return null;
268
+ }
269
+
180
270
  static findMatches(content, domain) {
181
271
  // NOTE: the src could end with a quote, bracket, apostrophe, double-backslash, or encoded quote.
182
272
  // Backlashes are added to content as an escape character
@@ -208,22 +298,14 @@ class ExternalMediaInliner {
208
298
  const matches = this.constructor.findMatches(content, domain);
209
299
 
210
300
  for (const src of matches) {
211
- const response = await this.getRemoteMedia(src);
212
-
213
- let media;
214
- if (response) {
215
- media = await this.extractFileDataFromResponse(src, response);
216
- }
217
-
218
- if (media) {
219
- const inlinedSrc = await this.storeMediaLocally(media);
220
-
221
- if (inlinedSrc) {
222
- // NOTE: does not account for duplicate images in content
223
- // in those cases would be processed twice
224
- content = content.replace(src, inlinedSrc);
225
- logging.info(`Inlined media: ${src} -> ${inlinedSrc}`);
226
- }
301
+ const result = await this.importUrl(src);
302
+ const replacementUrl = this.#replacementUrlFromImportResult(result);
303
+
304
+ if (replacementUrl) {
305
+ // NOTE: does not account for duplicate images in content
306
+ // in those cases would be processed twice
307
+ content = content.replace(src, replacementUrl);
308
+ logging.info(`Inlined media: ${src} -> ${replacementUrl}`);
227
309
  }
228
310
  }
229
311
  }
@@ -246,20 +328,12 @@ class ExternalMediaInliner {
246
328
  const src = resourceModel.get(field);
247
329
 
248
330
  if (src && src.startsWith(domain)) {
249
- const response = await this.getRemoteMedia(src);
250
-
251
- let media;
252
- if (response) {
253
- media = await this.extractFileDataFromResponse(src, response);
254
- }
255
-
256
- if (media) {
257
- const inlinedSrc = await this.storeMediaLocally(media);
331
+ const result = await this.importUrl(src);
332
+ const replacementUrl = this.#replacementUrlFromImportResult(result);
258
333
 
259
- if (inlinedSrc) {
260
- updatedFields[field] = inlinedSrc;
261
- logging.info(`Added media to inline: ${src} -> ${inlinedSrc}`);
262
- }
334
+ if (replacementUrl) {
335
+ updatedFields[field] = replacementUrl;
336
+ logging.info(`Added media to inline: ${src} -> ${replacementUrl}`);
263
337
  }
264
338
  }
265
339
  }
@@ -1,10 +1,11 @@
1
+ const errors = require('@tryghost/errors');
2
+
3
+ let instance;
4
+
1
5
  module.exports = {
2
6
  async init() {
3
- const debug = require('@tryghost/debug')('mediaInliner');
4
7
  const MediaInliner = require('./external-media-inliner');
5
- const logging = require('@tryghost/logging');
6
8
  const models = require('../../models');
7
- const jobsService = require('../jobs');
8
9
  const adapterManager = require('../../services/adapter-manager').default;
9
10
 
10
11
  const mediaStorage = adapterManager.getAdapter('storage:media');
@@ -31,45 +32,16 @@ module.exports = {
31
32
  },
32
33
  });
33
34
 
34
- this.api = {
35
- startMediaInliner: async (domains) => {
36
- if (!domains || !domains.length) {
37
- // default domains to inline from if none are provided
38
- domains = ['https://s3.amazonaws.com/revue', 'https://substackcdn.com'];
39
- }
40
-
41
- debug('[Inliner] Starting media inlining job for domains: ', domains);
35
+ instance = mediaInliner;
36
+ },
42
37
 
43
- // @NOTE: the job is "inline" (aka non-offloaded into a thread), because usecases are currently
44
- // limited to migrational, so there is no expectations for site's availability etc.
45
- logging.info('[Background Job] external-media-inliner queued');
46
- await jobsService.addJob({
47
- name: 'external-media-inliner',
48
- job: async (data) => {
49
- const startedAt = Date.now();
50
- logging.info('[Background Job] external-media-inliner started');
51
- try {
52
- const result = await mediaInliner.inline(data.domains);
53
- logging.info(
54
- `[Background Job] external-media-inliner completed in ${Date.now() - startedAt}ms`,
55
- );
56
- return result;
57
- } catch (err) {
58
- logging.error(
59
- err,
60
- `[Background Job] external-media-inliner failed after ${Date.now() - startedAt}ms`,
61
- );
62
- throw err;
63
- }
64
- },
65
- data: { domains },
66
- offloaded: false,
67
- });
38
+ getInstance() {
39
+ if (!instance) {
40
+ throw new errors.IncorrectUsageError({
41
+ message: 'Media inliner used before init(). Call init() from boot first.',
42
+ });
43
+ }
68
44
 
69
- return {
70
- status: 'success',
71
- };
72
- },
73
- };
45
+ return instance;
74
46
  },
75
47
  };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -7,7 +7,7 @@ const MagicLink = require('../lib/magic-link/magic-link');
7
7
  const sentry = require('../../../shared/sentry');
8
8
  const emailAddressService = require('../email-address');
9
9
  const settingsHelpers = require('../settings-helpers');
10
- const EmailAddressParser = require('../email-address/email-address-parser');
10
+ const emailAddressParser = require('../email-address/email-address-parser');
11
11
  const mail = require('../mail');
12
12
  const MailgunClient = require('../lib/mailgun-client');
13
13
  const config = require('../../../shared/config');
@@ -152,7 +152,7 @@ class MemberWelcomeEmailService {
152
152
  },
153
153
  });
154
154
 
155
- const from = EmailAddressParser.stringify(fromAddresses.from);
155
+ const from = emailAddressParser.stringify(fromAddresses.from);
156
156
  const replyToSetting = newsletter.get('sender_reply_to');
157
157
  let replyTo = null;
158
158
 
@@ -173,7 +173,7 @@ class MemberWelcomeEmailService {
173
173
  });
174
174
 
175
175
  if (addresses.replyTo) {
176
- replyTo = EmailAddressParser.stringify(addresses.replyTo);
176
+ replyTo = emailAddressParser.stringify(addresses.replyTo);
177
177
  }
178
178
  }
179
179
 
@@ -199,10 +199,10 @@ class MemberWelcomeEmailService {
199
199
  async #getEffectiveSenderOptions(automatedSender = {}) {
200
200
  const defaultOptions = await this.#getSenderOptions();
201
201
  const defaultFrom =
202
- EmailAddressParser.parse(defaultOptions.from || '') ||
202
+ emailAddressParser.parse(defaultOptions.from || '') ||
203
203
  emailAddressService.service.defaultFromEmail;
204
204
  const defaultReplyTo = defaultOptions.replyTo
205
- ? EmailAddressParser.parse(defaultOptions.replyTo)
205
+ ? emailAddressParser.parse(defaultOptions.replyTo)
206
206
  : undefined;
207
207
 
208
208
  const senderName = trimValue(automatedSender.senderName) || defaultFrom?.name || undefined;
@@ -218,10 +218,10 @@ class MemberWelcomeEmailService {
218
218
  });
219
219
 
220
220
  return {
221
- from: EmailAddressParser.stringify(addresses.from),
221
+ from: emailAddressParser.stringify(addresses.from),
222
222
  ...(addresses.replyTo
223
223
  ? {
224
- replyTo: EmailAddressParser.stringify(addresses.replyTo),
224
+ replyTo: emailAddressParser.stringify(addresses.replyTo),
225
225
  }
226
226
  : {}),
227
227
  };
@@ -274,6 +274,7 @@ function createApiInstance(config) {
274
274
  // two together in boot order. Custom fields is initialised in initCore, the
275
275
  // members API is built in initServices, so this is always the live instance.
276
276
  customFieldValues: customFieldsService.values,
277
+ customFieldDefinitions: customFieldsService.definitions,
277
278
  });
278
279
 
279
280
  return membersApiInstance;
@@ -43,19 +43,12 @@ function parse(path, headerMapping) {
43
43
  // hasOwn, not `in`: a prototype-named header would otherwise match an
44
44
  // inherited method on the mapping and take a function as its mapped name.
45
45
  if (headerMapping && Object.hasOwn(headerMapping, header)) {
46
- // An empty target is the caller naming a column to leave out, which
47
- // it has to name: an unnamed column carries through below, and for a
48
- // custom_fields.* column carrying through means being imported. So
49
- // omitting a column from the mapping is the opposite of excluding it.
50
46
  if (!headerMapping[header]) {
51
47
  continue;
52
48
  }
53
49
  row[headerMapping[header]] = value;
54
50
  }
55
51
  else if (isSafeColumnName(header)) {
56
- // Carry any unmapped column through untouched, so the import is not
57
- // constrained to a known vocabulary: a custom_fields.* column
58
- // survives parsing even though nothing consumes it yet.
59
52
  row[header] = value;
60
53
  }
61
54
  }
@@ -54,14 +54,14 @@ class MembersCSVExporter {
54
54
  const hasFilter = options.limit !== 'all' || options.filter || options.search;
55
55
  const ids = hasFilter ? await this._members.findFilteredIds(options) : null;
56
56
  if (ids) {
57
- logging.info(`[MembersExporter] Found ${ids.length} members matching filter criteria`);
57
+ logging.info({ event: { name: 'members-export.filtered' }, matched: ids.length }, 'Found members matching the export filter');
58
58
  }
59
59
  const reference = await this.fetchReferenceData();
60
60
  const membersQuery = this._knex('members').select(...MEMBER_COLUMNS);
61
61
  if (ids) {
62
62
  membersQuery.whereIn('id', ids);
63
63
  }
64
- logging.info('[MembersExporter] Starting streaming export of members');
64
+ logging.info({ event: { name: 'members-export.started' } }, 'Starting streaming export of members');
65
65
  const batchingTransform = this.createBatchingTransform();
66
66
  const processingTransform = this.createProcessingTransform(reference);
67
67
  (0, node_stream_1.pipeline)(membersQuery.stream(), batchingTransform, processingTransform, (err) => {
@@ -69,9 +69,7 @@ class MembersCSVExporter {
69
69
  logging.error({ event: { name: 'members-export.stream.error' }, err }, 'Members export stream failed');
70
70
  }
71
71
  else {
72
- logging.info('[MembersExporter] Total time taken for member export: ' +
73
- (Date.now() - start) / 1000 +
74
- 's');
72
+ logging.info({ event: { name: 'members-export.completed' }, durationMs: Date.now() - start }, 'Members export completed');
75
73
  }
76
74
  });
77
75
  return processingTransform;
@@ -95,7 +93,7 @@ class MembersCSVExporter {
95
93
  acc[label.id] = label.name;
96
94
  return acc;
97
95
  }, {}));
98
- logging.info('[MembersExporter] Fetched products and labels in ' + (Date.now() - start) + 'ms');
96
+ logging.info({ event: { name: 'members-export.reference_data_read' }, durationMs: Date.now() - start }, 'Read the products and labels an export names');
99
97
  const activeCustomFields = await this._customFields.activeDefinitions();
100
98
  return { allProducts, allLabels, activeCustomFields };
101
99
  }
@@ -55,8 +55,6 @@ function humaniseError(row) {
55
55
  function stringifyLabels(labels) {
56
56
  return labels.map((label) => (typeof label === 'string' ? label : label.name)).join(',');
57
57
  }
58
- // The custom_fields.* cells a submitted row carried, echoed untouched so a manager can
59
- // fix a failed row and re-upload the values they mapped.
60
58
  function customFieldCells(row) {
61
59
  return Object.fromEntries(Object.entries(row).filter(([column]) => (0, csv_2.isCustomFieldColumn)(column)));
62
60
  }
@@ -82,9 +80,8 @@ function toErrorReportRow(row) {
82
80
  }
83
81
  // The error report attached to the completion email: the failed rows as CSV, called only
84
82
  // when there are rows to list. It shares the serialiser with the export but not the
85
- // shaping -- the export writes db members, this echoes submitted rows. Member columns come from the shaper's keys (so the type
86
- // stays the single source); the custom_fields.* columns across the rows are threaded in
87
- // before the last error column, and each row's custom cells merged on.
83
+ // shaping -- the export writes db members, this echoes submitted rows. Member columns
84
+ // come from the shaper's keys, so the type stays the single source.
88
85
  function buildErrorReport(errors) {
89
86
  const memberColumns = Object.keys(toErrorReportRow(errors[0])).filter((column) => column !== 'error');
90
87
  const customColumns = [...new Set(errors.flatMap((row) => Object.keys(customFieldCells(row))))];
@@ -17,6 +17,7 @@ const messages = {
17
17
  giftCannotCombineWithImportTier: 'Cannot specify both gift_id and import_tier.',
18
18
  giftCannotCombineWithComplimentary: 'Cannot specify both gift_id and complimentary_plan.',
19
19
  giftReassignFailed: 'Failed to reassign gift to member.',
20
+ customFieldWriteFailed: 'Failed to save the custom field values for this member.',
20
21
  };
21
22
  // Columns whose presence makes a row slow to import (they reach out to Stripe), so
22
23
  // a file carrying any of them is deferred regardless of size. The routing decision
@@ -90,7 +91,7 @@ class MembersCSVImporter {
90
91
  // a request without a user actually reaches the deferred path.
91
92
  const emailRecipient = requestUserEmail ?? (await this._email.getDefaultRecipient());
92
93
  const spooled = await this._spool.write(rows);
93
- logging.info('[Background Job] members-import queued');
94
+ logging.info({ event: { name: 'members.import.queued' }, rows: rows.length }, 'Members import queued');
94
95
  this._addJob({
95
96
  job: () => this.runImportJob(spooled, { labelName, extraLabels, emailRecipient }, verificationTrigger),
96
97
  offloaded: false,
@@ -101,7 +102,7 @@ class MembersCSVImporter {
101
102
  // in the job itself, and there is no retry behind it.
102
103
  async runImportJob(spooled, { labelName, extraLabels, emailRecipient, }, verificationTrigger) {
103
104
  const startedAt = Date.now();
104
- logging.info('[Background Job] members-import started');
105
+ logging.info({ event: { name: 'members.import.started' } }, 'Members import started');
105
106
  // Null until the import produces one: parsing and mapping already happened inside
106
107
  // the request, so anything failing from here is ours rather than the file's.
107
108
  let result = null;
@@ -125,10 +126,15 @@ class MembersCSVImporter {
125
126
  links: this._email.links,
126
127
  })));
127
128
  if (result) {
128
- logging.info(`[Background Job] members-import completed in ${Date.now() - startedAt}ms: imported ${result.imported}, ${result.errors.length} row(s) rejected`);
129
+ logging.info({
130
+ event: { name: 'members.import.completed' },
131
+ durationMs: Date.now() - startedAt,
132
+ imported: result.imported,
133
+ rejected: result.errors.length,
134
+ }, 'Members import completed');
129
135
  }
130
136
  else {
131
- logging.info(`[Background Job] members-import failed after ${Date.now() - startedAt}ms`);
137
+ logging.info({ event: { name: 'members.import.failed' }, durationMs: Date.now() - startedAt }, 'Members import failed');
132
138
  }
133
139
  }
134
140
  // Only the write itself may throw. Callers rely on that to tell an import that never
@@ -300,7 +306,17 @@ class MembersCSVImporter {
300
306
  }
301
307
  }
302
308
  // On the row's transaction, so the values commit or roll back with the member.
303
- await this._customFields.applyWrite(member.id, customFieldPlan, trx);
309
+ try {
310
+ await this._customFields.applyWrite(member.id, customFieldPlan, trx);
311
+ }
312
+ catch (writeError) {
313
+ // planWrite passed every value before the transaction opened, so a failure
314
+ // here is ours and not the row's. Operators get the original, which a driver
315
+ // will have written a query into; the publisher gets a sentence instead, in a
316
+ // file they open next to a spreadsheet.
317
+ this._report(writeError);
318
+ throw new errors.DataImportError({ message: tpl(messages.customFieldWriteFailed) });
319
+ }
304
320
  await trx.commit();
305
321
  imported += 1;
306
322
  }
@@ -16,9 +16,6 @@ const optionalCell = zod_1.z
16
16
  // not defaulted), so a CSV lacking these columns leaves the member's state untouched.
17
17
  const isSubscribed = (cell) => cell.toLowerCase() !== 'false';
18
18
  const isComplimentary = (cell) => cell.toLowerCase() === 'true';
19
- // The member import vocabulary as a schema: the single source of truth that coerces the
20
- // raw string Row into typed member fields. Unknown columns (custom_fields.*, and anything
21
- // else a source carries) pass through via .loose() so nothing is lost before the kernel.
22
19
  exports.memberImportRowSchema = zod_1.z
23
20
  .object({
24
21
  id: optionalCell,