ghost 6.53.0 → 6.54.1

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 (639) 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-scheduling-0.2.0.tgz +0 -0
  4. package/components/tryghost-adapter-base-sso-0.1.1.tgz +0 -0
  5. package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
  6. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  7. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  8. package/components/tryghost-kg-converters-1.2.3.tgz +0 -0
  9. package/components/tryghost-kg-default-nodes-2.1.3.tgz +0 -0
  10. package/components/tryghost-kg-lexical-html-renderer-1.4.3.tgz +0 -0
  11. package/core/boot.js +9 -6
  12. package/core/built/admin/assets/Combination-CJG7Flp-.js +41 -0
  13. package/core/built/admin/assets/Growth-BTP1LthE.js +3 -0
  14. package/core/built/admin/assets/Newsletters-CSEX0myc.js +1 -0
  15. package/core/built/admin/assets/Overview-BjACEsJF.js +1 -0
  16. package/core/built/admin/assets/{PolarAngleAxis-pciQ0MOy.js → PolarAngleAxis-BGjf7sBu.js} +1 -1
  17. package/core/built/admin/assets/{RadialBarChart-DWmw2PcX.js → RadialBarChart-zeFf9mBz.js} +1 -1
  18. package/core/built/admin/assets/Web-CxxxjCcv.js +2 -0
  19. package/core/built/admin/assets/account-migration-BklF2I_I.js +1 -0
  20. package/core/built/admin/assets/activitypub/{account-migration-BPZG37DJ.js → account-migration-CNovr6W-.js} +13 -13
  21. package/core/built/admin/assets/activitypub/activitypub.js +8 -8
  22. package/core/built/admin/assets/activitypub/{avatar-ZYco0ITb.js → avatar-B3DEDB1l.js} +10 -10
  23. package/core/built/admin/assets/activitypub/{avatar-flipboard-D541lc4F.js → avatar-flipboard-Cqrg0XMx.js} +3 -3
  24. package/core/built/admin/assets/activitypub/{bluesky-sharing-NOHUtHjl.js → bluesky-sharing-Ceslb1_M.js} +38 -37
  25. package/core/built/admin/assets/activitypub/{chunk-KS7C4IRE-B-GOFDPZ.js → chunk-KS7C4IRE-D4HEcEwi.js} +716 -710
  26. package/core/built/admin/assets/activitypub/{content-formatters-bwrp4iEO.js → content-formatters-BpQARh28.js} +229 -181
  27. package/core/built/admin/assets/activitypub/{copy-C7m7ovHw.js → copy-D9UWIAan.js} +2 -2
  28. package/core/built/admin/assets/activitypub/{dist-BqkDUQxJ2.js → dist-ByFmDSNP2.js} +64 -63
  29. package/core/built/admin/assets/activitypub/{dist-B5ira32t.js → dist-DHAjBcV3.js} +5 -5
  30. package/core/built/admin/assets/activitypub/{domain-iqE4YXwD.js → domain-C1qQvJ8C.js} +33 -33
  31. package/core/built/admin/assets/activitypub/{edit-profile-B8MFYh28.js → edit-profile-BcH-jEfM.js} +46 -45
  32. package/core/built/admin/assets/activitypub/{explore-BbdKodp3.js → explore-AxwBh9dI.js} +20 -20
  33. package/core/built/admin/assets/activitypub/{feed-Cl3A5owG.js → feed-BaOlbh7a.js} +15 -15
  34. package/core/built/admin/assets/activitypub/{field-DL6WyR-c.js → field-B7mYYQpN.js} +13 -13
  35. package/core/built/admin/assets/activitypub/{hash-6G3DzwL9.js → hash-BC9Q0N4c.js} +2 -2
  36. package/core/built/admin/assets/activitypub/{inbox-YmhuBice.js → inbox-DQ4ZnC1m.js} +2 -2
  37. package/core/built/admin/assets/activitypub/inbox-vXez-5uJ.js +1221 -0
  38. package/core/built/admin/assets/activitypub/{label-DGbLjDvE.js → label-Chv5T8bw.js} +6 -6
  39. package/core/built/admin/assets/activitypub/layout-CziktJXo.js +1 -0
  40. package/core/built/admin/assets/activitypub/{moderation-qnBtk1zS.js → moderation-DtSM2i1I.js} +32 -31
  41. package/core/built/admin/assets/activitypub/{note-C7ZRoSJv.js → note-Dckp4S-2.js} +21 -21
  42. package/core/built/admin/assets/activitypub/{notifications-DiEA4b1o.js → notifications-CG5T22vg.js} +17 -17
  43. package/core/built/admin/assets/activitypub/{onboarding-_JVgEwgV.js → onboarding-BFDkzeR2.js} +2 -2
  44. package/core/built/admin/assets/activitypub/{onboarding-DG4zu3qM.js → onboarding-D6rcBdPe.js} +5 -5
  45. package/core/built/admin/assets/activitypub/{preferences-B3FtocnP.js → preferences-D_799jdl.js} +1607 -1606
  46. package/core/built/admin/assets/activitypub/{profile-D8ZJfYXB.js → profile-D2JfXBQl.js} +264 -263
  47. package/core/built/admin/assets/activitypub/{reply-C1vggenw.js → reply-CpdMeAO5.js} +2 -2
  48. package/core/built/admin/assets/activitypub/{routes-BOii-V9n.js → routes-CCHe2dQp.js} +1317 -1298
  49. package/core/built/admin/assets/activitypub/{separator-1gNokN5S.js → separator-BI1FLsYM.js} +4 -4
  50. package/core/built/admin/assets/activitypub/{settings--9Sb0nbl.js → settings-kx-9Enkz.js} +14 -14
  51. package/core/built/admin/assets/activitypub/{site-fkMmqv0V.js → site-x4_IjVJ0.js} +10 -10
  52. package/core/built/admin/assets/activitypub/{step-1-QhivSMw2.js → step-1-DIDg4aHb.js} +15 -15
  53. package/core/built/admin/assets/activitypub/{step-2-pMk9YwqD.js → step-2-BfGe8BYt.js} +7 -7
  54. package/core/built/admin/assets/activitypub/{step-3-DvmVC1fo.js → step-3-mE9spAqw.js} +12 -12
  55. package/core/built/admin/assets/activitypub/{tabs-Dc0FEEYD.js → tabs-CyPRQQ1N.js} +241 -237
  56. package/core/built/admin/assets/activitypub/{topic-filter-CuDyM5bD.js → topic-filter-DLHBZT93.js} +4 -4
  57. package/core/built/admin/assets/activitypub/use-activity-pub-queries-VzbN99u_.js +1957 -0
  58. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Drx1kdAK.js → use-navigate-with-base-path-CAwXTmqH.js} +165 -175
  59. package/core/built/admin/assets/activitypub/{use-reply-chain-data-BHkCHcW5.js → use-reply-chain-data-BAB6fNGt.js} +8 -8
  60. package/core/built/admin/assets/activitypub/users-BLeiOTHc.js +1464 -0
  61. package/core/built/admin/assets/activitypub/{x-BHCEe-c2.js → x-C8tAnXly.js} +2 -2
  62. package/core/built/admin/assets/{audience-adiFehTD.js → audience-X_XsZivI.js} +1 -1
  63. package/core/built/admin/assets/{automated-emails-UWM02CMr.js → automated-emails-of1MvVsv.js} +1 -1
  64. package/core/built/admin/assets/automations-B7-y3dXt.js +1 -0
  65. package/core/built/admin/assets/automations-DRFjW5fw.js +1 -0
  66. package/core/built/admin/assets/{avatar-flipboard-Lz3F9fNT.js → avatar-flipboard-C6Kj3Awu.js} +1 -1
  67. package/core/built/admin/assets/bluesky-sharing-BbbjWdzs.js +1 -0
  68. package/core/built/admin/assets/box-BWbhXh21.js +1 -0
  69. package/core/built/admin/assets/breadcrumb-B-M9Ip_2.js +1 -0
  70. package/core/built/admin/assets/card-DGoDJzrn.js +1 -0
  71. package/core/built/admin/assets/{chart-ChpW-NzQ.js → chart-BuRT2Y6p.js} +14 -14
  72. package/core/built/admin/assets/chart-helpers-xiSsW8r0.js +1 -0
  73. package/core/built/admin/assets/checkbox-EhJKHFdZ.js +1 -0
  74. package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js → chunk.211.6f7328d63c41536451b3.js} +2025 -2819
  75. package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js.LICENSE.txt → chunk.211.6f7328d63c41536451b3.js.LICENSE.txt} +1 -62
  76. package/core/built/admin/assets/{chunk.831.0703a12e49f51cec3f3a.js → chunk.361.3cdb584b973959e52ccc.js} +78 -85
  77. package/core/built/admin/assets/chunk.524.8365cd9280405c0f6216.js +25 -0
  78. package/core/built/admin/assets/chunk.582.61d078937e6102769f2c.js +27 -0
  79. package/core/built/admin/assets/code-editor-view-CZtJFGhR.js +1 -0
  80. package/core/built/admin/assets/comments-CvyXxOyN.js +1 -0
  81. package/core/built/admin/assets/container-BYz2Ed39.js +1 -0
  82. package/core/built/admin/assets/data-list-16rkJYYi.js +1 -0
  83. package/core/built/admin/assets/date-range-select-CTlyo8zW.js +1 -0
  84. package/core/built/admin/assets/disabled-sources-indicator-qs2GfLvl.js +1 -0
  85. package/core/built/admin/assets/{dist-DJ6c4_De.js → dist-2Tnz2Yfq.js} +1 -1
  86. package/core/built/admin/assets/{dist-CsekE4FL.js → dist-CQJY6SVY.js} +1 -1
  87. package/core/built/admin/assets/dist-CjY-f5Z1.js +1 -0
  88. package/core/built/admin/assets/dist-DGzPJ_bO.js +4 -0
  89. package/core/built/admin/assets/dist-DIC8yz5C.js +1 -0
  90. package/core/built/admin/assets/{dist-BbGrW05X.js → dist-DyViJwIy.js} +1 -1
  91. package/core/built/admin/assets/dist-Ndy-PuGN.js +1 -0
  92. package/core/built/admin/assets/dist-P_ohUlTi.js +1 -0
  93. package/core/built/admin/assets/domain-CPNXKVOV.js +1 -0
  94. package/core/built/admin/assets/dropzone-BmCXnw6J.js +5 -0
  95. package/core/built/admin/assets/edit-profile-SGrJve5M.js +1 -0
  96. package/core/built/admin/assets/editor-BOG2YPUm.js +8 -0
  97. package/core/built/admin/assets/empty-indicator-oX1u1Pkn.js +1 -0
  98. package/core/built/admin/assets/esm-CFX93H5M.js +2 -0
  99. package/core/built/admin/assets/explore-CUYLv9G9.js +1 -0
  100. package/core/built/admin/assets/feed-CPdJMttL.js +1 -0
  101. package/core/built/admin/assets/field-D0XISCK2.js +1 -0
  102. package/core/built/admin/assets/{filter-sources-v39ihhhV.js → filter-sources-Bieps75g.js} +1 -1
  103. package/core/built/admin/assets/filters-CuB-A7ma.js +1 -0
  104. package/core/built/admin/assets/filters-bXkkWro8.js +1 -0
  105. package/core/built/admin/assets/framework-provider-CmtnPXIT.js +4 -0
  106. package/core/built/admin/assets/{ghost-b57f077997b739a8ae9a70772dc016cb.js → ghost-05f9a7182ed56903dba05878a5b8422b.js} +46 -41
  107. package/core/built/admin/assets/ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css +1 -0
  108. package/core/built/admin/assets/gift-link-modal-su8MsRdg.js +1 -0
  109. package/core/built/admin/assets/{gift-links-CY3GwiVi.js → gift-links-nBxJjZiQ.js} +1 -1
  110. package/core/built/admin/assets/growth-Ba6S5FQX.js +1 -0
  111. package/core/built/admin/assets/hooks-BApwwBE0.js +2 -0
  112. package/core/built/admin/assets/{inbox-TEISAmth.js → inbox-Xx1CdnfO.js} +38 -38
  113. package/core/built/admin/assets/index-D8PbzuT9.css +1 -0
  114. package/core/built/admin/assets/index-ukW_0Uie.js +67 -0
  115. package/core/built/admin/assets/inline-EMAm3okk.js +1 -0
  116. package/core/built/admin/assets/input-group-CGOXcy4l.js +1 -0
  117. package/core/built/admin/assets/input-surface-BpAjZXY5.js +1 -0
  118. package/core/built/admin/assets/{react-dom-C6aoWSfl.js → jsx-runtime-DX3WBWVO.js} +1 -1
  119. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +5 -2
  120. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +2 -2
  121. package/core/built/admin/assets/{koenig-lexical-Di7b48ED.js → koenig-lexical-B61IALf5.js} +2 -2
  122. package/core/built/admin/assets/kpi-card-BlZaG1Lo.js +1 -0
  123. package/core/built/admin/assets/kpi-card-DCdlyaSS.js +1 -0
  124. package/core/built/admin/assets/kpi-helpers-DpAuS1Nb.js +1 -0
  125. package/core/built/admin/assets/kpi-tabs-Dme44bQS.js +1 -0
  126. package/core/built/admin/assets/label-dSs5aepE.js +1 -0
  127. package/core/built/admin/assets/label-picker-Uq91atex.js +1 -0
  128. package/core/built/admin/assets/{labels-GbxlXWtf.js → labels-Cyayfd-e.js} +1 -1
  129. package/core/built/admin/assets/layout-WUcz6tu1.js +1 -0
  130. package/core/built/admin/assets/limit-service-9fwD33lU.js +20 -0
  131. package/core/built/admin/assets/link-helpers-tOlxmuH5.js +1 -0
  132. package/core/built/admin/assets/list-page-B6ANtzkd.js +1 -0
  133. package/core/built/admin/assets/mailchimp-Ds_NQ04w.svg +9 -0
  134. package/core/built/admin/assets/member-custom-fields-NCzrMuba.js +1 -0
  135. package/core/built/admin/assets/member-detail-DPWDtYnN.js +1 -0
  136. package/core/built/admin/assets/members-B9rO7qr4.js +10 -0
  137. package/core/built/admin/assets/modals-CxRaan1J.js +31 -0
  138. package/core/built/admin/assets/moderation-D8zon60E.js +1 -0
  139. package/core/built/admin/assets/multi-select-combobox-1wYm3nle.js +1 -0
  140. package/core/built/admin/assets/newsletter-DbYMRxRS.js +1 -0
  141. package/core/built/admin/assets/{newsletters-DZm3yLj8.js → newsletters-D1jbtV-h.js} +1 -1
  142. package/core/built/admin/assets/note-PiWPnnrh.js +1 -0
  143. package/core/built/admin/assets/notifications-DEgqqB9G.js +1 -0
  144. package/core/built/admin/assets/nql-lang-B7faUf8D.js +19 -0
  145. package/core/built/admin/assets/{offers-D11QtPXX.js → offers-CrY6nSRR.js} +1 -1
  146. package/core/built/admin/assets/onboarding-route-BzF6HeVn.js +1 -0
  147. package/core/built/admin/assets/overview-DixLeIqY.js +1 -0
  148. package/core/built/admin/assets/page-header-op0eN36I.js +1 -0
  149. package/core/built/admin/assets/{pages-BnObVRrf.js → pages-BbNWFcGj.js} +1 -1
  150. package/core/built/admin/assets/pintura-CXOmq-5H.svg +15 -0
  151. package/core/built/admin/assets/post-analytics-WwRDEnrV.js +1 -0
  152. package/core/built/admin/assets/post-analytics-header-DsMoLx0R.js +1 -0
  153. package/core/built/admin/assets/{post-analytics-provider-DSfBCtnj.js → post-analytics-provider-BJCPLMIb.js} +1 -1
  154. package/core/built/admin/assets/post-share-modal-Dx-MEjhI.js +1 -0
  155. package/core/built/admin/assets/{posts-CwH8VJvB.js → posts-EWpZIjkr.js} +1 -1
  156. package/core/built/admin/assets/preferences-D7-j6A4C.js +5 -0
  157. package/core/built/admin/assets/profile-Dl69QPp0.js +1 -0
  158. package/core/built/admin/assets/{referrers-nxR52jPI.js → referrers-BCfFYSHc.js} +1 -1
  159. package/core/built/admin/assets/router-provider-C1R4AZ2o.js +1 -0
  160. package/core/built/admin/assets/select-C1qDZnW4.js +1 -0
  161. package/core/built/admin/assets/settings-BbmC_Iqq.js +4 -0
  162. package/core/built/admin/assets/settings-H6HxFgfI.js +1 -0
  163. package/core/built/admin/assets/shade-app-B3heOAfz-CGXQwWeO.js +3 -0
  164. package/core/built/admin/assets/share-modal-BJCadJyp.js +1 -0
  165. package/core/built/admin/assets/social-urls-BPL1nADp.js +8 -0
  166. package/core/built/admin/assets/sort-button-DyYlfYp7.js +1 -0
  167. package/core/built/admin/assets/source-icon-_ubRDbg_.js +1 -0
  168. package/core/built/admin/assets/stack-xiN0eQ6Z.js +1 -0
  169. package/core/built/admin/assets/stats-BQZMGMvn.js +1 -0
  170. package/core/built/admin/assets/stats-view-Doei-qCX.js +1 -0
  171. package/core/built/admin/assets/step-1-IKiLBPoC.js +1 -0
  172. package/core/built/admin/assets/step-2-jJ41PsDN.js +1 -0
  173. package/core/built/admin/assets/step-3-CaqFAEqf.js +2 -0
  174. package/core/built/admin/assets/switch-t-WyENU2.js +1 -0
  175. package/core/built/admin/assets/table-DxUL78jU.js +1 -0
  176. package/core/built/admin/assets/tabs-BQcJQ1ke.js +1 -0
  177. package/core/built/admin/assets/tags-CNujGwkT.js +1 -0
  178. package/core/built/admin/assets/text-DwtjwGkh.js +1 -0
  179. package/core/built/admin/assets/textarea-Bjccvh_E.js +1 -0
  180. package/core/built/admin/assets/{tiers-EghDzCKc.js → tiers-BgYLWRJv.js} +1 -1
  181. package/core/built/admin/assets/toggle-group-BeEpQ69p.js +1 -0
  182. package/core/built/admin/assets/topic-filter-Bb5MOD-1.js +1 -0
  183. package/core/built/admin/assets/{use-analytics-data-0l_OHtnR.js → use-analytics-data-Cds6XDjg.js} +1 -1
  184. package/core/built/admin/assets/use-filter-params-DjXkhO54.js +1 -0
  185. package/core/built/admin/assets/use-growth-stats-D8uf98-G.js +1 -0
  186. package/core/built/admin/assets/{use-post-referrers-DwI31Ril.js → use-post-referrers-CRtgyuXB.js} +1 -1
  187. package/core/built/admin/assets/use-reply-chain-data-DbKYX50v.js +1 -0
  188. package/core/built/admin/assets/use-simple-pagination-DC01kpo0.js +1 -0
  189. package/core/built/admin/assets/{use-tinybird-query-DvZBBMG7.js → use-tinybird-query-C7bQRJWw.js} +1 -1
  190. package/core/built/admin/assets/{use-tinybird-token-CQtebkvU.js → use-tinybird-token-Az4tam7_.js} +1 -1
  191. package/core/built/admin/assets/{users-Pc8IRjk9.js → users-CcSCQFcQ.js} +1 -1
  192. package/core/built/admin/assets/virtual-list-Dhuh9fGx.js +1 -0
  193. package/core/built/admin/assets/web-LtHNiNBV.js +1 -0
  194. package/core/built/admin/index.html +22 -22
  195. package/core/frontend/apps/private-blogging/index.js +1 -1
  196. package/core/frontend/apps/private-blogging/lib/middleware.js +1 -1
  197. package/core/frontend/helpers/split.js +2 -1
  198. package/core/frontend/meta/asset-url.js +1 -1
  199. package/core/frontend/meta/author-image.js +1 -1
  200. package/core/frontend/meta/blog-logo.js +1 -1
  201. package/core/frontend/meta/canonical-url.js +1 -1
  202. package/core/frontend/meta/cover-image.js +1 -1
  203. package/core/frontend/meta/get-meta.js +1 -1
  204. package/core/frontend/meta/og-image.js +1 -1
  205. package/core/frontend/meta/paginated-url.js +1 -1
  206. package/core/frontend/meta/twitter-image.js +1 -1
  207. package/core/frontend/meta/url.js +1 -1
  208. package/core/frontend/services/assets-minification/admin-auth-assets.js +1 -1
  209. package/core/frontend/services/llms/handler.js +1 -1
  210. package/core/frontend/services/proxy.js +42 -3
  211. package/core/frontend/services/routing/collection-router.js +1 -1
  212. package/core/frontend/services/routing/controllers/email-post.js +1 -1
  213. package/core/frontend/services/routing/controllers/entry/markdown.js +1 -1
  214. package/core/frontend/services/routing/controllers/entry/markdown.ts +1 -1
  215. package/core/frontend/services/routing/controllers/entry.js +1 -1
  216. package/core/frontend/services/routing/controllers/entry.ts +1 -1
  217. package/core/frontend/services/routing/controllers/previews.js +6 -7
  218. package/core/frontend/services/routing/controllers/unsubscribe.js +7 -3
  219. package/core/frontend/services/routing/email-router.js +1 -1
  220. package/core/frontend/services/routing/events.js +12 -0
  221. package/core/frontend/services/routing/middleware/page-param.js +1 -1
  222. package/core/frontend/services/routing/parent-router.js +1 -1
  223. package/core/frontend/services/routing/preview-router.js +1 -1
  224. package/core/frontend/services/routing/router-manager.js +4 -8
  225. package/core/frontend/services/routing/rss-router.js +1 -1
  226. package/core/frontend/services/routing/static-pages-router.js +1 -1
  227. package/core/frontend/services/routing/static-routes-router.js +1 -1
  228. package/core/frontend/services/routing/taxonomy-router.js +1 -1
  229. package/core/frontend/services/rss/generate-feed.js +1 -1
  230. package/core/frontend/services/sitemap/base-site-map-generator.js +23 -4
  231. package/core/frontend/services/sitemap/site-map-index-generator.js +1 -1
  232. package/core/frontend/services/sitemap/site-map-manager.js +14 -8
  233. package/core/frontend/services/sitemap/utils.js +1 -1
  234. package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +1 -1
  235. package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +1 -1
  236. package/core/frontend/utils/images.js +1 -1
  237. package/core/frontend/web/middleware/admin-toolbar.js +1 -1
  238. package/core/frontend/web/middleware/handle-image-sizes.js +2 -2
  239. package/core/frontend/web/middleware/redirect-ghost-to-admin.js +1 -1
  240. package/core/frontend/web/routers/serve-favicon.js +1 -1
  241. package/core/frontend/web/routers/serve-public-file.js +1 -1
  242. package/core/frontend/web/site.js +5 -5
  243. package/core/server/adapters/cache/AdapterCacheMemoryTTL.js +2 -2
  244. package/core/server/adapters/cache/MemoryCache.js +2 -2
  245. package/core/server/adapters/cache/Redis.js +1 -1
  246. package/core/server/adapters/cache/index.js +1 -1
  247. package/core/server/adapters/lib/redis/AdapterCacheRedis.js +2 -2
  248. package/core/server/adapters/route-settings/FileStore.js +2 -8
  249. package/core/server/adapters/route-settings/FileStore.ts +1 -6
  250. package/core/server/adapters/route-settings/S3RouteSettingsStore.js +206 -0
  251. package/core/server/adapters/route-settings/S3RouteSettingsStore.ts +199 -0
  252. package/core/server/adapters/route-settings/utils.js +13 -0
  253. package/core/server/adapters/route-settings/utils.ts +7 -0
  254. package/core/server/adapters/scheduling/deps.d.ts +0 -2
  255. package/core/server/adapters/scheduling/error-capture.js +76 -0
  256. package/core/server/adapters/scheduling/error-capture.ts +91 -0
  257. package/core/server/adapters/scheduling/utils.js +18 -34
  258. package/core/server/adapters/scheduling/utils.ts +36 -0
  259. package/core/server/adapters/storage/LocalFilesStorage.js +13 -11
  260. package/core/server/adapters/storage/LocalFilesStorage.ts +24 -0
  261. package/core/server/adapters/storage/LocalImagesStorage.js +14 -12
  262. package/core/server/adapters/storage/LocalImagesStorage.ts +24 -0
  263. package/core/server/adapters/storage/LocalMediaStorage.js +13 -11
  264. package/core/server/adapters/storage/LocalMediaStorage.ts +24 -0
  265. package/core/server/adapters/storage/LocalStorageBase.js +107 -167
  266. package/core/server/adapters/storage/LocalStorageBase.ts +342 -0
  267. package/core/server/adapters/storage/S3Storage.js +2 -2
  268. package/core/server/adapters/storage/S3Storage.ts +1 -1
  269. package/core/server/adapters/storage/utils.js +36 -50
  270. package/core/server/adapters/storage/utils.ts +60 -0
  271. package/core/server/api/endpoints/authentication.js +1 -1
  272. package/core/server/api/endpoints/db.js +6 -0
  273. package/core/server/api/endpoints/featurebase.js +1 -1
  274. package/core/server/api/endpoints/files.js +2 -2
  275. package/core/server/api/endpoints/images.js +2 -2
  276. package/core/server/api/endpoints/libraries.d.ts +0 -1
  277. package/core/server/api/endpoints/media.js +8 -5
  278. package/core/server/api/endpoints/member-custom-fields.js +4 -1
  279. package/core/server/api/endpoints/member-custom-fields.ts +4 -1
  280. package/core/server/api/endpoints/members.js +25 -28
  281. package/core/server/api/endpoints/pages.js +6 -1
  282. package/core/server/api/endpoints/posts.js +28 -3
  283. package/core/server/api/endpoints/search-index-public.js +4 -3
  284. package/core/server/api/endpoints/search-index.js +5 -4
  285. package/core/server/api/endpoints/settings-public.js +1 -1
  286. package/core/server/api/endpoints/settings.js +3 -1
  287. package/core/server/api/endpoints/utils/serializers/input/utils/url.js +9 -1
  288. package/core/server/api/endpoints/utils/serializers/output/default.js +7 -0
  289. package/core/server/api/endpoints/utils/serializers/output/files.js +1 -1
  290. package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +4 -1
  291. package/core/server/api/endpoints/utils/serializers/output/media.js +1 -1
  292. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +7 -4
  293. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.ts +8 -4
  294. package/core/server/api/endpoints/utils/serializers/output/members.js +27 -106
  295. package/core/server/api/endpoints/utils/serializers/output/pages.js +7 -0
  296. package/core/server/api/endpoints/utils/serializers/output/posts.js +13 -0
  297. package/core/server/api/endpoints/utils/serializers/output/utils/url.js +1 -1
  298. package/core/server/api/endpoints/utils/validators/input/members.js +2 -52
  299. package/core/server/data/db/backup.js +1 -1
  300. package/core/server/data/exporter/export-filename.js +2 -1
  301. package/core/server/data/importer/handlers/image.js +3 -3
  302. package/core/server/data/importer/import-manager.js +6 -4
  303. package/core/server/data/importer/importers/content-file-importer.js +2 -2
  304. package/core/server/data/importer/importers/data/revue-subscriber-importer.js +6 -10
  305. package/core/server/data/importer/importers/json-to-html.js +24 -4
  306. package/core/server/data/migrations/utils/schema.js +4 -2
  307. package/core/server/data/migrations/versions/6.54/2026-07-19-16-59-00-add-content-import-permission.js +10 -0
  308. package/core/server/data/migrations/versions/6.54/2026-07-20-13-59-21-drop-email-tracked-sent-count-from-automation-action-revisions.js +7 -0
  309. package/core/server/data/migrations/versions/6.54/2026-07-21-01-58-20-add-automation-run-steps-poller-index.js +3 -0
  310. package/core/server/data/migrations/versions/6.54/2026-07-21-21-08-15-add-automated-email-recipients-mailgun-message-id-index.js +3 -0
  311. package/core/server/data/migrations/versions/6.54/2026-07-22-10-41-08-add-click-tracking-to-automated-email-recipients.js +13 -0
  312. package/core/server/data/migrations/versions/6.54/2026-07-22-15-10-30-add-email-clicked-count-to-automation-action-revisions.js +7 -0
  313. package/core/server/data/migrations/versions/6.54/2026-07-23-10-24-18-add-automation-action-revision-to-redirects.js +9 -0
  314. package/core/server/data/schema/commands.js +37 -3
  315. package/core/server/data/schema/fixtures/fixtures.json +7 -0
  316. package/core/server/data/schema/lib/default-index-name.js +20 -0
  317. package/core/server/data/schema/schema.js +40 -17
  318. package/core/server/data/seeders/data-generator.js +4 -2
  319. package/core/server/lib/image/image-size.js +7 -23
  320. package/core/server/lib/image/image-utils.js +16 -2
  321. package/core/server/lib/image/index.js +4 -4
  322. package/core/server/lib/lexical.js +3 -3
  323. package/core/server/lib/mobiledoc.js +2 -2
  324. package/core/server/lib/request-external.js +1 -1
  325. package/core/server/lib/validate-password.js +1 -1
  326. package/core/server/models/action.js +9 -0
  327. package/core/server/models/base/plugins/generate-slug.js +1 -1
  328. package/core/server/models/collection.js +1 -1
  329. package/core/server/models/custom-theme-setting.js +1 -1
  330. package/core/server/models/member.js +73 -0
  331. package/core/server/models/newsletter.js +1 -1
  332. package/core/server/models/post.js +19 -5
  333. package/core/server/models/posts-meta.js +1 -1
  334. package/core/server/models/redirect.js +1 -1
  335. package/core/server/models/settings.js +1 -1
  336. package/core/server/models/snippet.js +1 -1
  337. package/core/server/models/tag.js +1 -1
  338. package/core/server/models/user.js +47 -71
  339. package/core/server/models/welcome-email-automated-email.js +1 -1
  340. package/core/server/services/activitypub/activity-pub-service-wrapper.js +1 -1
  341. package/core/server/services/adapter-manager/adapter-manager.js +5 -1
  342. package/core/server/services/adapter-manager/adapter-manager.ts +7 -2
  343. package/core/server/services/adapter-manager/index.js +18 -15
  344. package/core/server/services/adapter-manager/index.ts +23 -17
  345. package/core/server/services/adapter-manager/utils.js +124 -14
  346. package/core/server/services/adapter-manager/utils.ts +130 -14
  347. package/core/server/services/api-version-compatibility/mw-version-rewrites.js +1 -1
  348. package/core/server/services/audience-feedback/index.js +1 -1
  349. package/core/server/services/auth/passwordreset.js +1 -1
  350. package/core/server/services/auth/session/express-session.js +1 -1
  351. package/core/server/services/auth/session/index.js +2 -2
  352. package/core/server/services/auth/session/session-service.js +29 -2
  353. package/core/server/services/automations/automations-api.js +8 -25
  354. package/core/server/services/automations/automations-api.ts +8 -37
  355. package/core/server/services/automations/automations-repository.ts +16 -0
  356. package/core/server/services/automations/database-automations-repository.js +37 -4
  357. package/core/server/services/automations/database-automations-repository.ts +41 -4
  358. package/core/server/services/automations/poll.js +16 -12
  359. package/core/server/services/automations/poll.ts +17 -15
  360. package/core/server/services/automations/service.js +1 -1
  361. package/core/server/services/automations/service.ts +3 -13
  362. package/core/server/services/automations/welcome-email-automation-poll.js +2 -1
  363. package/core/server/services/comments/comments-service-emails.js +4 -1
  364. package/core/server/services/comments/index.js +1 -1
  365. package/core/server/services/custom-redirects/index.js +2 -2
  366. package/core/server/services/email-analytics/email-analytics-service-wrapper.js +14 -13
  367. package/core/server/services/email-analytics/email-analytics-service.js +1 -1
  368. package/core/server/services/email-analytics/events/start-email-analytics-job-event.js +11 -15
  369. package/core/server/services/email-analytics/events/start-email-analytics-job-event.ts +15 -0
  370. package/core/server/services/email-analytics/index.js +2 -3
  371. package/core/server/services/email-analytics/index.ts +1 -2
  372. package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.js +1 -6
  373. package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.ts +0 -9
  374. package/core/server/services/email-analytics/jobs/fetch-latest/index.js +1 -1
  375. package/core/server/services/email-analytics/jobs/index.js +0 -2
  376. package/core/server/services/email-service/email-service-wrapper.js +1 -1
  377. package/core/server/services/email-service/email-service.js +20 -4
  378. package/core/server/services/explore-ping/explore-ping-service.js +24 -39
  379. package/core/server/services/explore-ping/explore-ping-service.ts +198 -0
  380. package/core/server/services/explore-ping/index.js +11 -11
  381. package/core/server/services/explore-ping/index.ts +42 -0
  382. package/core/server/services/gifts/gift-reminder-scheduler.js +1 -1
  383. package/core/server/services/gifts/gift-reminder-scheduler.ts +1 -1
  384. package/core/server/services/gifts/gift-service-wrapper.js +1 -1
  385. package/core/server/services/identity-tokens/identity-token-service-wrapper.js +1 -1
  386. package/core/server/services/indexnow-ping/constants.js +30 -0
  387. package/core/server/services/indexnow-ping/constants.ts +32 -0
  388. package/core/server/services/indexnow-ping/index.js +29 -253
  389. package/core/server/services/indexnow-ping/index.ts +37 -0
  390. package/core/server/services/indexnow-ping/indexnow-ping-service.js +229 -0
  391. package/core/server/services/indexnow-ping/indexnow-ping-service.ts +319 -0
  392. package/core/server/services/invites/index.js +1 -1
  393. package/core/server/services/lib/mailgun-client.js +3 -3
  394. package/core/server/services/link-redirection/index.js +2 -2
  395. package/core/server/services/link-redirection/link-redirect-repository.js +1 -1
  396. package/core/server/services/link-redirection/link-redirect.js +12 -13
  397. package/core/server/services/link-redirection/link-redirect.ts +22 -0
  398. package/core/server/services/link-redirection/link-redirects-service.js +1 -1
  399. package/core/server/services/link-tracking/full-post-link.js +2 -2
  400. package/core/server/services/link-tracking/index.js +1 -1
  401. package/core/server/services/mail/ghost-mailer.js +1 -1
  402. package/core/server/services/mail/index.js +1 -1
  403. package/core/server/services/media-inliner/external-media-inliner.js +2 -2
  404. package/core/server/services/media-inliner/service.js +4 -3
  405. package/core/server/services/member-attribution/index.js +1 -1
  406. package/core/server/services/member-welcome-emails/service.js +1 -1
  407. package/core/server/services/members/api.js +8 -2
  408. package/core/server/services/members/import-export/config.js +30 -0
  409. package/core/server/services/members/import-export/config.ts +34 -0
  410. package/core/server/services/members/import-export/csv/index.js +10 -0
  411. package/core/server/services/members/import-export/csv/index.ts +2 -0
  412. package/core/server/services/members/import-export/csv/parse.js +64 -0
  413. package/core/server/services/members/import-export/csv/parse.ts +69 -0
  414. package/core/server/services/members/import-export/csv/serialize.js +13 -0
  415. package/core/server/services/members/import-export/csv/serialize.ts +18 -0
  416. package/core/server/services/members/import-export/export/exporter.js +202 -0
  417. package/core/server/services/members/import-export/export/exporter.ts +325 -0
  418. package/core/server/services/members/import-export/import/completion-email.js +65 -0
  419. package/core/server/services/members/import-export/import/completion-email.ts +119 -0
  420. package/core/server/services/members/import-export/import/importer.js +276 -0
  421. package/core/server/services/members/import-export/import/importer.ts +430 -0
  422. package/core/server/services/members/import-export/import/reader.js +32 -0
  423. package/core/server/services/members/import-export/import/reader.ts +33 -0
  424. package/core/server/services/members/import-export/import/row.js +33 -0
  425. package/core/server/services/members/import-export/import/row.ts +52 -0
  426. package/core/server/services/members/import-export/import/spool.js +30 -0
  427. package/core/server/services/members/import-export/import/spool.ts +38 -0
  428. package/core/server/services/members/import-export/index.js +90 -0
  429. package/core/server/services/members/import-export/index.ts +118 -0
  430. package/core/server/services/members/members-api/controllers/router-controller.js +7 -0
  431. package/core/server/services/members/members-api/members-api.js +4 -2
  432. package/core/server/services/members/members-api/repositories/event-repository.js +13 -2
  433. package/core/server/services/members/members-api/services/member-bread-service.js +42 -19
  434. package/core/server/services/members/middleware.js +1 -1
  435. package/core/server/services/members/service.js +28 -17
  436. package/core/server/services/members/stripe-connect.js +1 -1
  437. package/core/server/services/members-custom-fields/actions.js +3 -0
  438. package/core/server/services/members-custom-fields/actions.ts +6 -2
  439. package/core/server/services/members-custom-fields/config.js +34 -0
  440. package/core/server/services/members-custom-fields/config.ts +38 -0
  441. package/core/server/services/members-custom-fields/definitions-service.js +156 -21
  442. package/core/server/services/members-custom-fields/definitions-service.ts +170 -25
  443. package/core/server/services/members-custom-fields/index.js +16 -3
  444. package/core/server/services/members-custom-fields/index.ts +17 -3
  445. package/core/server/services/members-custom-fields/values-service.js +56 -10
  446. package/core/server/services/members-custom-fields/values-service.ts +62 -10
  447. package/core/server/services/mentions/mention-sending-service.js +22 -2
  448. package/core/server/services/mentions/service.js +21 -5
  449. package/core/server/services/newsletters/index.js +1 -1
  450. package/core/server/services/oembed/oembed-service.js +122 -33
  451. package/core/server/services/oembed/service.js +4 -2
  452. package/core/server/services/offers/service.js +1 -1
  453. package/core/server/services/post-scheduling/index.js +4 -3
  454. package/core/server/services/post-scheduling/index.ts +4 -3
  455. package/core/server/services/post-scheduling/post-scheduling.js +1 -1
  456. package/core/server/services/post-scheduling/post-scheduling.ts +1 -1
  457. package/core/server/services/posts/post-email-handler.js +13 -6
  458. package/core/server/services/posts/post-scheduling.js +1 -1
  459. package/core/server/services/posts/posts-exporter.js +6 -4
  460. package/core/server/services/posts/posts-service-instance.js +1 -1
  461. package/core/server/services/posts/posts-service.js +4 -4
  462. package/core/server/services/posts-public/service.js +1 -1
  463. package/core/server/services/public-config/site.js +1 -1
  464. package/core/server/services/recommendations/recommendation-service-wrapper.js +1 -1
  465. package/core/server/services/recommendations/service/libraries.d.ts +0 -2
  466. package/core/server/services/route-settings/dynamic-routing-service.js +2 -3
  467. package/core/server/services/route-settings/index.js +1 -1
  468. package/core/server/services/route-settings/route-settings-parser.js +134 -124
  469. package/core/server/services/route-settings/route-settings-parser.ts +160 -125
  470. package/core/server/services/route-settings/validation-errors.js +178 -0
  471. package/core/server/services/route-settings/validation-errors.ts +196 -0
  472. package/core/server/services/settings/settings-service.js +2 -2
  473. package/core/server/services/settings-helpers/index.js +1 -1
  474. package/core/server/services/slack-notifications/service.js +1 -1
  475. package/core/server/services/slack-ping/constants.js +16 -0
  476. package/core/server/services/slack-ping/constants.ts +15 -0
  477. package/core/server/services/slack-ping/index.js +26 -204
  478. package/core/server/services/slack-ping/index.ts +35 -0
  479. package/core/server/services/slack-ping/slack-ping-service.js +214 -0
  480. package/core/server/services/slack-ping/slack-ping-service.ts +296 -0
  481. package/core/server/services/staff/index.js +1 -1
  482. package/core/server/services/stats/posts-stats-service.js +1 -1
  483. package/core/server/services/stats/service.js +1 -1
  484. package/core/server/services/stripe/service.js +1 -1
  485. package/core/server/services/tags-public/service.js +1 -1
  486. package/core/server/services/themes/storage.js +9 -0
  487. package/core/server/services/themes/theme-storage.js +1 -1
  488. package/core/server/services/themes/validate.js +1 -1
  489. package/core/server/services/update-check/index.js +1 -1
  490. package/core/server/services/url/lazy-url-service.js +66 -6
  491. package/core/server/services/url/lazy-url-service.ts +73 -6
  492. package/core/server/services/url/url-generator.js +1 -1
  493. package/core/server/services/url/url-service-facade.js +68 -3
  494. package/core/server/services/url/url-service-facade.ts +79 -4
  495. package/core/server/services/url/url-service.js +1 -1
  496. package/core/server/services/url/urls.js +1 -1
  497. package/core/server/services/webhooks/index.js +19 -2
  498. package/core/server/services/webhooks/listen.js +6 -11
  499. package/core/server/services/webhooks/payload.js +1 -3
  500. package/core/server/services/webhooks/serialize.js +16 -1
  501. package/core/server/web/admin/app.js +1 -1
  502. package/core/server/web/admin/middleware/redirect-admin-urls.js +1 -1
  503. package/core/server/web/api/endpoints/admin/routes.js +1 -0
  504. package/core/server/web/api/middleware/cors.js +1 -1
  505. package/core/server/web/api/middleware/upload.js +4 -0
  506. package/core/server/web/gift-preview/controller.js +1 -1
  507. package/core/server/web/shared/middleware/redirect-amp-urls.js +1 -1
  508. package/core/server/web/shared/middleware/uncapitalise.js +2 -2
  509. package/core/server/web/shared/middleware/url-redirects.js +1 -1
  510. package/core/shared/config/defaults.json +10 -2
  511. package/core/shared/config/overrides.json +4 -0
  512. package/core/shared/express.js +6 -1
  513. package/core/shared/labs.js +2 -1
  514. package/core/shared/url-utils.js +19 -15
  515. package/core/shared/url-utils.ts +20 -0
  516. package/ghost.js +0 -1
  517. package/package.json +30 -35
  518. package/pnpm-lock.yaml +681 -2789
  519. package/pnpm-workspace.yaml +31 -17
  520. package/components/tryghost-adapter-base-scheduling-0.0.0.tgz +0 -0
  521. package/components/tryghost-adapter-base-sso-0.0.0.tgz +0 -0
  522. package/core/built/admin/assets/Combination--5EZGaDs.js +0 -43
  523. package/core/built/admin/assets/Growth-C0NoKcHQ.js +0 -3
  524. package/core/built/admin/assets/Newsletters-Ed8kDjdy.js +0 -1
  525. package/core/built/admin/assets/Overview-CArPgRZt.js +0 -1
  526. package/core/built/admin/assets/Web-CjjYoVM3.js +0 -2
  527. package/core/built/admin/assets/account-migration-mfa5mNI9.js +0 -1
  528. package/core/built/admin/assets/activitypub/inbox-B3rjKMTv.js +0 -1221
  529. package/core/built/admin/assets/activitypub/layout-jcurg3rU.js +0 -1
  530. package/core/built/admin/assets/activitypub/use-activity-pub-queries-yqGRcnLn.js +0 -2569
  531. package/core/built/admin/assets/activitypub/users-CfyHIsTG.js +0 -1316
  532. package/core/built/admin/assets/automations-DkUnxNdv.js +0 -1
  533. package/core/built/admin/assets/automations-vjXofmV_.js +0 -1
  534. package/core/built/admin/assets/bluesky-sharing-T-pO3RcP.js +0 -1
  535. package/core/built/admin/assets/breadcrumb-CekPYTCn.js +0 -1
  536. package/core/built/admin/assets/button--i2uMDDn.js +0 -4
  537. package/core/built/admin/assets/card-CSWz_BXq.js +0 -1
  538. package/core/built/admin/assets/chart-helpers-C_4Ka_vT.js +0 -1
  539. package/core/built/admin/assets/chunk.524.8ce2c741473e2f0929dc.js +0 -25
  540. package/core/built/admin/assets/chunk.582.453459d6228d2955408b.js +0 -27
  541. package/core/built/admin/assets/code-editor-view-BfkwQto2.js +0 -1
  542. package/core/built/admin/assets/command-K75Jzs0G.js +0 -1
  543. package/core/built/admin/assets/comments-BEIi1DH-.js +0 -1
  544. package/core/built/admin/assets/container-BNXvlcjA.js +0 -1
  545. package/core/built/admin/assets/data-list-BmK5QMab.js +0 -1
  546. package/core/built/admin/assets/date-range-select-5sKzwbt7.js +0 -1
  547. package/core/built/admin/assets/disabled-sources-indicator-L_ssJTNr.js +0 -1
  548. package/core/built/admin/assets/dist-BBIJuyPg.js +0 -1
  549. package/core/built/admin/assets/dist-BHE0dp6o.js +0 -1
  550. package/core/built/admin/assets/dist-CT46_f_J.js +0 -1
  551. package/core/built/admin/assets/dist-DW0QXQO3.js +0 -1
  552. package/core/built/admin/assets/dist-DxFLceO5.js +0 -1
  553. package/core/built/admin/assets/dist-QcACAOAD.js +0 -1
  554. package/core/built/admin/assets/dist-duxRDcQu.js +0 -177
  555. package/core/built/admin/assets/domain-CLaPZ9Rc.js +0 -1
  556. package/core/built/admin/assets/dropzone-E0bSX4_a.js +0 -5
  557. package/core/built/admin/assets/edit-profile-DqNPKaA4.js +0 -1
  558. package/core/built/admin/assets/editor-CkLXQDRp.js +0 -8
  559. package/core/built/admin/assets/empty-indicator-BTtOlgIo.js +0 -1
  560. package/core/built/admin/assets/esm-TSfGW7nz.js +0 -2
  561. package/core/built/admin/assets/explore-BEstLxKr.js +0 -1
  562. package/core/built/admin/assets/feed-C58p2voG.js +0 -1
  563. package/core/built/admin/assets/field-BSbDUHPv.js +0 -1
  564. package/core/built/admin/assets/filters-BgYv8Gt7.js +0 -1
  565. package/core/built/admin/assets/filters-DvenFkmK.js +0 -1
  566. package/core/built/admin/assets/framework-provider-jQktxm9P.js +0 -4
  567. package/core/built/admin/assets/ghost-dark-8590dea6cd695ff90f27d262c4464538.css +0 -1
  568. package/core/built/admin/assets/gift-link-modal-BPjXkEFt.js +0 -1
  569. package/core/built/admin/assets/growth-D4JNiVTe.js +0 -1
  570. package/core/built/admin/assets/hooks-Cjxexi_I.js +0 -2
  571. package/core/built/admin/assets/index-BacwlcOy.js +0 -67
  572. package/core/built/admin/assets/index-DxRNHH0o.css +0 -1
  573. package/core/built/admin/assets/inline-C22rnPro.js +0 -1
  574. package/core/built/admin/assets/input-group-CKfrILLP.js +0 -1
  575. package/core/built/admin/assets/jsx-runtime-CtMZ-PAS.js +0 -1
  576. package/core/built/admin/assets/kpi-card-DZxQKAIb.js +0 -1
  577. package/core/built/admin/assets/kpi-card-FidQ5zg3.js +0 -1
  578. package/core/built/admin/assets/kpi-helpers-C5T8Vaf1.js +0 -1
  579. package/core/built/admin/assets/kpi-tabs-_VRK6hGV.js +0 -1
  580. package/core/built/admin/assets/label-Cza7hPgn.js +0 -1
  581. package/core/built/admin/assets/label-picker-DgC_zLaw.js +0 -1
  582. package/core/built/admin/assets/layout-BxsXnKFX.js +0 -1
  583. package/core/built/admin/assets/limit-service-CTurluJQ.js +0 -20
  584. package/core/built/admin/assets/link-helpers-C3Gqy2cz.js +0 -1
  585. package/core/built/admin/assets/list-page-BtqCnow_.js +0 -1
  586. package/core/built/admin/assets/member-custom-fields-9uXFBqSt.js +0 -1
  587. package/core/built/admin/assets/member-detail-Dq6ZDIxo.js +0 -1
  588. package/core/built/admin/assets/members-CUWD9jal.js +0 -10
  589. package/core/built/admin/assets/modals-CIdwHVga.js +0 -31
  590. package/core/built/admin/assets/moderation-DTt04UDA.js +0 -1
  591. package/core/built/admin/assets/newsletter-cC8vcc9h.js +0 -1
  592. package/core/built/admin/assets/note-DZU0IY9e.js +0 -1
  593. package/core/built/admin/assets/notifications-NoHpBHJ4.js +0 -1
  594. package/core/built/admin/assets/nql-lang-CvCSOQG3.js +0 -19
  595. package/core/built/admin/assets/onboarding-route-Deg2hNm8.js +0 -1
  596. package/core/built/admin/assets/overview-BQPt_9w3.js +0 -1
  597. package/core/built/admin/assets/page-header-D6bEqPo2.js +0 -1
  598. package/core/built/admin/assets/post-analytics-header-BPw_B2_D.js +0 -1
  599. package/core/built/admin/assets/post-analytics-kp2_--XO.js +0 -1
  600. package/core/built/admin/assets/post-share-modal-Cave3Z4W.js +0 -1
  601. package/core/built/admin/assets/preferences-C7h3j_uy.js +0 -5
  602. package/core/built/admin/assets/profile-B2x4q2oB.js +0 -1
  603. package/core/built/admin/assets/router-provider-5fsX1CYn.js +0 -1
  604. package/core/built/admin/assets/select-PhPjIBBT.js +0 -1
  605. package/core/built/admin/assets/settings-D5P9Gwgo.js +0 -6
  606. package/core/built/admin/assets/settings-zUOzQV5I.js +0 -1
  607. package/core/built/admin/assets/share-modal-EfpfbuWF.js +0 -1
  608. package/core/built/admin/assets/social-urls-DgAF08Xc.js +0 -18
  609. package/core/built/admin/assets/sort-button-WOQYJm2H.js +0 -1
  610. package/core/built/admin/assets/source-icon-hm8Cj-Gx.js +0 -1
  611. package/core/built/admin/assets/stats-CnQDb62m.js +0 -1
  612. package/core/built/admin/assets/stats-view-CCfTJgSe.js +0 -1
  613. package/core/built/admin/assets/step-1-BGlhY4DS.js +0 -1
  614. package/core/built/admin/assets/step-2-D3sDEyFH.js +0 -1
  615. package/core/built/admin/assets/step-3-CvZoUdsc.js +0 -2
  616. package/core/built/admin/assets/switch-CNjkOmwz.js +0 -1
  617. package/core/built/admin/assets/table-C5nZYPnW.js +0 -1
  618. package/core/built/admin/assets/tabs-dtOcExye.js +0 -1
  619. package/core/built/admin/assets/tags-Dhm0FB_g.js +0 -1
  620. package/core/built/admin/assets/textarea-CeKw3wmV.js +0 -1
  621. package/core/built/admin/assets/toggle-group-DfhZIMTW.js +0 -1
  622. package/core/built/admin/assets/topic-filter-Cxe1Il41.js +0 -1
  623. package/core/built/admin/assets/typeof-Ca-duI-z.js +0 -1
  624. package/core/built/admin/assets/use-filter-params-Bub6BqNy.js +0 -1
  625. package/core/built/admin/assets/use-growth-stats-BJORomv0.js +0 -1
  626. package/core/built/admin/assets/use-reply-chain-data-B89YjVoo.js +0 -1
  627. package/core/built/admin/assets/use-simple-pagination-BL2SYXKi.js +0 -1
  628. package/core/built/admin/assets/virtual-list-DNJOSK9I.js +0 -1
  629. package/core/built/admin/assets/web-BHUE3YQc.js +0 -1
  630. package/core/server/adapters/scheduling/scheduling-base.js +0 -5
  631. package/core/server/adapters/sso/SSOBase.js +0 -5
  632. package/core/server/adapters/storage/index.js +0 -17
  633. package/core/server/services/mail/templates/newsletter.html +0 -876
  634. package/core/server/services/members/exporter/query.js +0 -206
  635. package/core/server/services/members/importer/index.js +0 -30
  636. package/core/server/services/members/importer/labels.js +0 -125
  637. package/core/server/services/members/importer/members-csv-importer.js +0 -502
  638. /package/core/server/services/members/{importer → import-export/import}/email-template.js +0 -0
  639. /package/core/server/services/members/{importer/members-csv-importer-stripe-utils.js → import-export/import/stripe-utils.js} +0 -0
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.makeImporter = makeImporter;
7
+ exports.makeExporter = makeExporter;
8
+ const importer_1 = __importDefault(require("./import/importer"));
9
+ const reader_1 = __importDefault(require("./import/reader"));
10
+ const spool_1 = require("./import/spool");
11
+ const exporter_1 = __importDefault(require("./export/exporter"));
12
+ const MembersCSVImporterStripeUtils = require('./import/stripe-utils');
13
+ const db = require('../../../data/db');
14
+ const models = require('../../../models');
15
+ const labs = require('../../../../shared/labs');
16
+ // Build the members CSV importer. This is the composition root: today's models and
17
+ // services are wired behind the collaborators the importer declares, one per
18
+ // concern, so nothing Bookshelf-shaped leaks into the import service itself.
19
+ function makeImporter(deps) {
20
+ // The members repository resolves asynchronously and is stable once ready, so
21
+ // cache the promise and reuse it across every call the import makes.
22
+ let membersRepositoryPromise;
23
+ const getMembersRepository = () => (membersRepositoryPromise ??= deps.getMembersRepository());
24
+ // The members aggregate, plus the import label lookup folded in so the label
25
+ // (member-tagging data) does not need a source of its own.
26
+ const members = {
27
+ get: async (query, options) => (await getMembersRepository()).get(query, options),
28
+ create: async (values, options) => (await getMembersRepository()).create(values, options),
29
+ update: async (values, options) => (await getMembersRepository()).update(values, options),
30
+ getCustomerIdByEmail: async (email) => (await getMembersRepository()).getCustomerIdByEmail(email),
31
+ linkStripeCustomer: async (link, options) => (await getMembersRepository()).linkStripeCustomer(link, options),
32
+ getImportLabel: name => models.Label.findOne({ name })
33
+ };
34
+ // The completion email: its recipient, links and delivery in one collaborator.
35
+ const email = {
36
+ send: deps.sendEmail,
37
+ getDefaultRecipient: async () => (await models.User.getOwnerUser()).get('email'),
38
+ urlFor: deps.urlFor
39
+ };
40
+ // Gifts is initialised at boot and always present at request time; the getter
41
+ // resolves it lazily so the ready service is picked up whenever a row uses it.
42
+ const gifts = {
43
+ reassignRedeemer: (giftId, memberId, options) => deps.getGiftService().reassignRedeemer(giftId, memberId, options)
44
+ };
45
+ return new importer_1.default({
46
+ knex: deps.knex,
47
+ readRows: reader_1.default,
48
+ spool: (0, spool_1.createRowSpool)(),
49
+ members,
50
+ tiers: {
51
+ getDefault: deps.getDefaultTier,
52
+ getByName: deps.getTierByName
53
+ },
54
+ stripe: new MembersCSVImporterStripeUtils({
55
+ stripeAPIService: deps.stripeAPIService,
56
+ productRepository: deps.productRepository
57
+ }),
58
+ gifts,
59
+ email,
60
+ addJob: deps.addJob,
61
+ getTimezone: deps.getTimezone,
62
+ getInlineThreshold: deps.getInlineThreshold
63
+ });
64
+ }
65
+ // Build the members CSV exporter. The same composition root from the other direction:
66
+ // knex and the members id lookup are wired here, and the custom fields definitions and
67
+ // values services are injected (boot builds them before this one). The labs flag alone
68
+ // decides whether custom field columns appear, so nothing flag-shaped leaks into the
69
+ // exporter itself.
70
+ function makeExporter({ definitions, values }) {
71
+ const exporter = new exporter_1.default({
72
+ knex: db.knex,
73
+ members: {
74
+ // Minimal query, only to fetch the ids of the filtered members; the stream
75
+ // reads their related data itself.
76
+ findFilteredIds: async (options) => {
77
+ const page = await models.Member.findPage({ ...options, withRelated: [], columns: ['id'], limit: 'all' });
78
+ return page.data.map((member) => member.id);
79
+ }
80
+ },
81
+ customFields: {
82
+ // Boot builds the definitions and values services before this one, so they
83
+ // are always present -- no not-initialised state to guard. The flag decides
84
+ // whether their columns are included at all.
85
+ activeDefinitions: async () => (labs.isSet('membersCustomFields') ? definitions.browse() : []),
86
+ valuesForMembers: memberIds => values.getValuesForMembers(memberIds)
87
+ }
88
+ });
89
+ return (options = {}) => exporter.export(options);
90
+ }
@@ -0,0 +1,118 @@
1
+ import type {Knex} from 'knex';
2
+ import MembersCSVImporter, {type MembersRepository, type GiftService, type EmailNotifications, type Tier} from './import/importer';
3
+ import readMemberRows from './import/reader';
4
+ import {createRowSpool} from './import/spool';
5
+ import MembersCSVExporter, {type ExportOptions, type CustomFieldDefinition} from './export/exporter';
6
+
7
+ const MembersCSVImporterStripeUtils = require('./import/stripe-utils');
8
+ const db = require('../../../data/db');
9
+ const models = require('../../../models');
10
+ const labs = require('../../../../shared/labs');
11
+
12
+ // The raw collaborators the members service hands the import composition root, before
13
+ // they are adapted into the ports the importer declares. The members repository is the
14
+ // importer's aggregate minus the import-label lookup, which the root folds in itself.
15
+ interface ImporterServices {
16
+ knex: Knex;
17
+ getMembersRepository(): Promise<Omit<MembersRepository, 'getImportLabel'>>;
18
+ getDefaultTier(): Promise<Tier>;
19
+ getTierByName(name: string): Promise<Tier | null>;
20
+ getGiftService(): GiftService;
21
+ sendEmail: EmailNotifications['send'];
22
+ urlFor: EmailNotifications['urlFor'];
23
+ addJob(job: {job: () => Promise<void>; offloaded: boolean; name: string}): void;
24
+ getTimezone(): string;
25
+ getInlineThreshold(): number;
26
+ stripeAPIService: unknown;
27
+ productRepository: unknown;
28
+ }
29
+
30
+ // The custom fields services the members service hands the export composition root.
31
+ interface CustomFieldsServices {
32
+ definitions: {browse(): Promise<CustomFieldDefinition[]>};
33
+ values: {getValuesForMembers(memberIds: string[]): Promise<Map<string, Record<string, unknown>>>};
34
+ }
35
+
36
+ // Build the members CSV importer. This is the composition root: today's models and
37
+ // services are wired behind the collaborators the importer declares, one per
38
+ // concern, so nothing Bookshelf-shaped leaks into the import service itself.
39
+ export function makeImporter(deps: ImporterServices) {
40
+ // The members repository resolves asynchronously and is stable once ready, so
41
+ // cache the promise and reuse it across every call the import makes.
42
+ let membersRepositoryPromise: Promise<Omit<MembersRepository, 'getImportLabel'>> | undefined;
43
+ const getMembersRepository = () => (membersRepositoryPromise ??= deps.getMembersRepository());
44
+
45
+ // The members aggregate, plus the import label lookup folded in so the label
46
+ // (member-tagging data) does not need a source of its own.
47
+ const members: MembersRepository = {
48
+ get: async (query, options) => (await getMembersRepository()).get(query, options),
49
+ create: async (values, options) => (await getMembersRepository()).create(values, options),
50
+ update: async (values, options) => (await getMembersRepository()).update(values, options),
51
+ getCustomerIdByEmail: async email => (await getMembersRepository()).getCustomerIdByEmail(email),
52
+ linkStripeCustomer: async (link, options) => (await getMembersRepository()).linkStripeCustomer(link, options),
53
+ getImportLabel: name => models.Label.findOne({name})
54
+ };
55
+
56
+ // The completion email: its recipient, links and delivery in one collaborator.
57
+ const email: EmailNotifications = {
58
+ send: deps.sendEmail,
59
+ getDefaultRecipient: async () => (await models.User.getOwnerUser()).get('email'),
60
+ urlFor: deps.urlFor
61
+ };
62
+
63
+ // Gifts is initialised at boot and always present at request time; the getter
64
+ // resolves it lazily so the ready service is picked up whenever a row uses it.
65
+ const gifts: GiftService = {
66
+ reassignRedeemer: (giftId, memberId, options) => deps.getGiftService().reassignRedeemer(giftId, memberId, options)
67
+ };
68
+
69
+ return new MembersCSVImporter({
70
+ knex: deps.knex,
71
+ readRows: readMemberRows,
72
+ spool: createRowSpool(),
73
+ members,
74
+ tiers: {
75
+ getDefault: deps.getDefaultTier,
76
+ getByName: deps.getTierByName
77
+ },
78
+ stripe: new MembersCSVImporterStripeUtils({
79
+ stripeAPIService: deps.stripeAPIService,
80
+ productRepository: deps.productRepository
81
+ }),
82
+ gifts,
83
+ email,
84
+ addJob: deps.addJob,
85
+ getTimezone: deps.getTimezone,
86
+ getInlineThreshold: deps.getInlineThreshold
87
+ });
88
+ }
89
+
90
+ // Build the members CSV exporter. The same composition root from the other direction:
91
+ // knex and the members id lookup are wired here, and the custom fields definitions and
92
+ // values services are injected (boot builds them before this one). The labs flag alone
93
+ // decides whether custom field columns appear, so nothing flag-shaped leaks into the
94
+ // exporter itself.
95
+ export function makeExporter({definitions, values}: CustomFieldsServices): (options?: ExportOptions) => Promise<NodeJS.ReadableStream> {
96
+ const exporter = new MembersCSVExporter({
97
+ knex: db.knex,
98
+
99
+ members: {
100
+ // Minimal query, only to fetch the ids of the filtered members; the stream
101
+ // reads their related data itself.
102
+ findFilteredIds: async (options) => {
103
+ const page = await models.Member.findPage({...options, withRelated: [], columns: ['id'], limit: 'all'});
104
+ return page.data.map((member: {id: string}) => member.id);
105
+ }
106
+ },
107
+
108
+ customFields: {
109
+ // Boot builds the definitions and values services before this one, so they
110
+ // are always present -- no not-initialised state to guard. The flag decides
111
+ // whether their columns are included at all.
112
+ activeDefinitions: async (): Promise<CustomFieldDefinition[]> => (labs.isSet('membersCustomFields') ? definitions.browse() : []),
113
+ valuesForMembers: memberIds => values.getValuesForMembers(memberIds)
114
+ }
115
+ });
116
+
117
+ return (options = {}) => exporter.export(options);
118
+ }
@@ -467,6 +467,13 @@ module.exports = class RouterController {
467
467
  });
468
468
  }
469
469
 
470
+ if (offer.status && offer.status !== 'active') {
471
+ throw new BadRequestError({
472
+ message: tpl(messages.offerArchived),
473
+ context: 'Offer with id "' + offerId + '" is no longer active'
474
+ });
475
+ }
476
+
470
477
  if (!offer.tier) {
471
478
  throw new BadRequestError({
472
479
  message: 'Offer does not have a tier'
@@ -81,10 +81,11 @@ module.exports = function MembersAPI({
81
81
  sentry,
82
82
  settingsHelpers,
83
83
  urlUtils,
84
+ urlService,
84
85
  commentsService,
85
86
  emailAddressService,
86
87
  giftService,
87
- customFieldsService
88
+ customFieldValues
88
89
  }) {
89
90
  const tokenService = new TokenService({
90
91
  privateKey,
@@ -123,6 +124,7 @@ module.exports = function MembersAPI({
123
124
  });
124
125
 
125
126
  const eventRepository = new EventRepository({
127
+ urlService,
126
128
  DonationPaymentEvent,
127
129
  EmailRecipient,
128
130
  MemberSubscribeEvent,
@@ -167,7 +169,7 @@ module.exports = function MembersAPI({
167
169
  nextPaymentCalculator,
168
170
  commentsService,
169
171
  giftService,
170
- customFieldsService
172
+ customFieldValues
171
173
  });
172
174
 
173
175
  const geolocationService = new GeolocationService();
@@ -34,6 +34,7 @@ module.exports = class EventRepository {
34
34
  Comment,
35
35
  labsService,
36
36
  memberAttributionService,
37
+ urlService,
37
38
  MemberEmailChangeEvent,
38
39
  AutomatedEmailRecipient,
39
40
  Gift
@@ -47,6 +48,7 @@ module.exports = class EventRepository {
47
48
  this._EmailRecipient = EmailRecipient;
48
49
  this._Comment = Comment;
49
50
  this._labsService = labsService;
51
+ this._urlService = urlService;
50
52
  this._MemberCreatedEvent = MemberCreatedEvent;
51
53
  this._SubscriptionCreatedEvent = SubscriptionCreatedEvent;
52
54
  this._MemberLinkClickEvent = MemberLinkClickEvent;
@@ -59,6 +61,12 @@ module.exports = class EventRepository {
59
61
  this._knex = db.knex;
60
62
  }
61
63
 
64
+ // the URL service needs the attributed post's relations (e.g. tags for a
65
+ // tag-filtered collection) to build its URL; prefix them onto the eager-load
66
+ #attributionPostRelations(prefix) {
67
+ return this._urlService.getRequiredRelations().map(relation => `${prefix}.${relation}`);
68
+ }
69
+
62
70
  async getEventTimeline(options = {}) {
63
71
  if (!options.limit) {
64
72
  options.limit = 10;
@@ -213,6 +221,7 @@ module.exports = class EventRepository {
213
221
  withRelated: [
214
222
  'member',
215
223
  'subscriptionCreatedEvent.postAttribution',
224
+ ...this.#attributionPostRelations('subscriptionCreatedEvent.postAttribution'),
216
225
  'subscriptionCreatedEvent.userAttribution',
217
226
  'subscriptionCreatedEvent.tagAttribution',
218
227
  'subscriptionCreatedEvent.memberCreatedEvent',
@@ -343,6 +352,7 @@ module.exports = class EventRepository {
343
352
  withRelated: [
344
353
  'member',
345
354
  'postAttribution',
355
+ ...this.#attributionPostRelations('postAttribution'),
346
356
  'userAttribution',
347
357
  'tagAttribution',
348
358
  'signupStatusEvent'
@@ -402,6 +412,7 @@ module.exports = class EventRepository {
402
412
  withRelated: [
403
413
  'member',
404
414
  'postAttribution',
415
+ ...this.#attributionPostRelations('postAttribution'),
405
416
  'userAttribution',
406
417
  'tagAttribution'
407
418
  ],
@@ -591,7 +602,7 @@ module.exports = class EventRepository {
591
602
  async getCommentEvents(options = {}, filter) {
592
603
  options = {
593
604
  ...options,
594
- withRelated: ['member', 'post', 'post.tags', 'post.authors', 'parent'],
605
+ withRelated: ['member', 'post', ...this.#attributionPostRelations('post'), 'parent'],
595
606
  filter: 'member_id:-null+custom:true',
596
607
  useBasicCount: true,
597
608
  mongoTransformer: chainTransformers(
@@ -625,7 +636,7 @@ module.exports = class EventRepository {
625
636
  async getClickEvents(options = {}, filter) {
626
637
  options = {
627
638
  ...options,
628
- withRelated: ['member', 'link', 'link.post', 'link.post.tags', 'link.post.authors'],
639
+ withRelated: ['member', 'link', 'link.post', ...this.#attributionPostRelations('link.post')],
629
640
  filter: 'custom:true',
630
641
  useBasicCount: true,
631
642
  mongoTransformer: chainTransformers(
@@ -6,7 +6,8 @@ const moment = require('moment');
6
6
  const messages = {
7
7
  stripeNotConnected: 'Missing Stripe connection.',
8
8
  memberAlreadyExists: 'Member already exists.',
9
- memberNotFound: 'Member not found.'
9
+ memberNotFound: 'Member not found.',
10
+ customFieldsOnAdd: 'Custom field values cannot be set while creating a member. Create the member, then set values with an edit.'
10
11
  };
11
12
 
12
13
  // Stored in the action's `context.action_name`; Admin maps it to a display label.
@@ -36,15 +37,6 @@ const CUSTOM_FIELDS_EDITED_ACTION = 'custom_fields_edited';
36
37
  * @prop {{getActiveByMembers: (memberIds: string[]) => Promise<Map<string, {cadence: 'month' | 'year', currency: string, amount: number}>>}} service
37
38
  */
38
39
 
39
- /**
40
- * @typedef {object} ICustomFieldsServiceWrapper
41
- * @prop {{
42
- * getValuesForMembers: (memberIds: string[]) => Promise<Map<string, Record<string, unknown>>>,
43
- * planWrite: (values: unknown) => Promise<object[]>,
44
- * applyWrite: (memberId: string, writes: object[]) => Promise<void>
45
- * }} values
46
- */
47
-
48
40
  module.exports = class MemberBREADService {
49
41
  /**
50
42
  * @param {object} deps
@@ -58,9 +50,9 @@ module.exports = class MemberBREADService {
58
50
  * @param {import('../../../settings-helpers/settings-helpers')} deps.settingsHelpers
59
51
  * @param {import('./next-payment-calculator')} deps.nextPaymentCalculator
60
52
  * @param {IGiftServiceWrapper} deps.giftService
61
- * @param {ICustomFieldsServiceWrapper} deps.customFieldsService
53
+ * @param {import('../../../members-custom-fields/values-service').CustomFieldValuesService} deps.customFieldValues Required: boot builds it before the members service
62
54
  */
63
- constructor({memberRepository, labsService, emailService, stripeService, offersAPI, memberAttributionService, emailSuppressionList, settingsHelpers, nextPaymentCalculator, commentsService, giftService, customFieldsService}) {
55
+ constructor({memberRepository, labsService, emailService, stripeService, offersAPI, memberAttributionService, emailSuppressionList, settingsHelpers, nextPaymentCalculator, commentsService, giftService, customFieldValues}) {
64
56
  this.offersAPI = offersAPI;
65
57
  /** @private */
66
58
  this.memberRepository = memberRepository;
@@ -83,7 +75,7 @@ module.exports = class MemberBREADService {
83
75
  /** @private */
84
76
  this.giftService = giftService;
85
77
  /** @private */
86
- this.customFieldsService = customFieldsService;
78
+ this.customFieldValues = customFieldValues;
87
79
  }
88
80
 
89
81
  /**
@@ -112,7 +104,7 @@ module.exports = class MemberBREADService {
112
104
  return null;
113
105
  }
114
106
 
115
- return this.customFieldsService.values.getValuesForMembers(memberIds);
107
+ return this.customFieldValues.getValuesForMembers(memberIds);
116
108
  }
117
109
 
118
110
  /**
@@ -444,7 +436,36 @@ module.exports = class MemberBREADService {
444
436
  return member;
445
437
  }
446
438
 
439
+ /**
440
+ * @private
441
+ * The write-side flag gate, paired with `fetchCustomFieldValues` on the read
442
+ * side. The schema declares `custom_fields` for every site, so the key arrives
443
+ * whether or not the feature is on and this is what decides it goes no further.
444
+ * @param {object} data
445
+ */
446
+ dropCustomFieldsWhenDisabled(data) {
447
+ if (!this.labsService.isSet('membersCustomFields')) {
448
+ delete data.custom_fields;
449
+ }
450
+ }
451
+
447
452
  async add(data, options) {
453
+ this.dropCustomFieldsWhenDisabled(data);
454
+
455
+ // Values cannot be set on create, only on a subsequent edit. `namesValues`
456
+ // both judges the body and rejects a malformed one, so a body refused here is
457
+ // refused on edit for the same reason.
458
+ if (this.customFieldValues.namesValues(data.custom_fields)) {
459
+ throw new errors.ValidationError({
460
+ message: tpl(messages.customFieldsOnAdd),
461
+ property: 'custom_fields'
462
+ });
463
+ }
464
+
465
+ // Not a member column, so it comes off before the repository sees it. Only
466
+ // an absent key or one naming no values gets this far.
467
+ delete data.custom_fields;
468
+
448
469
  if (!this.stripeService.configured && (data.comped || data.stripe_customer_id)) {
449
470
  const property = data.comped ? 'comped' : 'stripe_customer_id';
450
471
  throw new errors.ValidationError({
@@ -527,10 +548,12 @@ module.exports = class MemberBREADService {
527
548
  async edit(data, options) {
528
549
  delete data.last_seen_at;
529
550
 
551
+ this.dropCustomFieldsWhenDisabled(data);
552
+
530
553
  // Values live in their own table, so they come off the member data before
531
- // the repository sees it — `custom_fields` is not a member column. It only
532
- // reaches here at all when the flag is on (the input validator strips it
533
- // otherwise), so its presence is the signal to write.
554
+ // the repository sees it — `custom_fields` is not a member column. The gate
555
+ // above has already dropped it when the feature is off, so by this point its
556
+ // presence is the signal to write.
534
557
  const customFields = data.custom_fields;
535
558
  const writeCustomFields = customFields !== undefined;
536
559
  delete data.custom_fields;
@@ -540,7 +563,7 @@ module.exports = class MemberBREADService {
540
563
  // plan to apply once below, so the values aren't resolved and validated
541
564
  // twice.
542
565
  const plannedCustomFields = writeCustomFields
543
- ? await this.customFieldsService.values.planWrite(customFields)
566
+ ? await this.customFieldValues.planWrite(customFields)
544
567
  : null;
545
568
 
546
569
  let model;
@@ -589,7 +612,7 @@ module.exports = class MemberBREADService {
589
612
  }
590
613
 
591
614
  if (plannedCustomFields) {
592
- await this.customFieldsService.values.applyWrite(model.id, plannedCustomFields);
615
+ await this.customFieldValues.applyWrite(model.id, plannedCustomFields);
593
616
 
594
617
  // Custom fields aren't a member column or relation, so an edit touching
595
618
  // only them leaves `model._changed` empty and the save fires nothing.
@@ -4,7 +4,7 @@ const logging = require('@tryghost/logging');
4
4
  const membersService = require('./service');
5
5
  const emailSuppressionList = require('../email-suppression-list');
6
6
  const models = require('../../models');
7
- const urlUtils = require('../../../shared/url-utils');
7
+ const urlUtils = require('../../../shared/url-utils').default;
8
8
  const spamPrevention = require('../../web/shared/middleware/api/spam-prevention');
9
9
  const {
10
10
  formattedMemberResponse,
@@ -4,12 +4,12 @@ const tpl = require('@tryghost/tpl');
4
4
  const MembersSSR = require('./members-ssr');
5
5
  const db = require('../../data/db');
6
6
  const MembersConfigProvider = require('./members-config-provider');
7
- const makeMembersCSVImporter = require('./importer');
7
+ const {makeImporter, makeExporter} = require('./import-export');
8
+ const {resolveInlineThreshold} = require('./import-export/config');
8
9
  const MembersStats = require('./stats/members-stats');
9
10
  const memberJobs = require('./jobs');
10
11
  const logging = require('@tryghost/logging');
11
- const urlUtils = require('../../../shared/url-utils');
12
- const labsService = require('../../../shared/labs');
12
+ const urlUtils = require('../../../shared/url-utils').default;
13
13
  const settingsCache = require('../../../shared/settings-cache');
14
14
  const config = require('../../../shared/config');
15
15
  const models = require('../../models');
@@ -46,10 +46,12 @@ const membersStats = new MembersStats({
46
46
  let membersApi;
47
47
  let verificationTrigger;
48
48
 
49
- const initMembersCSVImporter = ({stripeAPIService}) => {
50
- return makeMembersCSVImporter({
51
- storagePath: config.getContentPath('data'),
49
+ const buildImporterDeps = ({stripeAPIService}) => {
50
+ return {
52
51
  getTimezone: () => settingsCache.get('timezone'),
52
+ // A getter rather than a value because the threshold is an operator
53
+ // setting that can change between requests
54
+ getInlineThreshold: () => resolveInlineThreshold(config.get('members:importer:inlineThreshold')),
53
55
  getMembersRepository: async () => {
54
56
  const api = await module.exports.api;
55
57
  return api.members;
@@ -75,16 +77,12 @@ const initMembersCSVImporter = ({stripeAPIService}) => {
75
77
  },
76
78
  getGiftService: () => giftService.service,
77
79
  sendEmail: ghostMailer.send.bind(ghostMailer),
78
- isSet: flag => labsService.isSet(flag),
79
80
  addJob: jobsService.addJob.bind(jobsService),
80
81
  knex: db.knex,
81
82
  urlFor: urlUtils.urlFor.bind(urlUtils),
82
- context: {
83
- importer: true
84
- },
85
83
  stripeAPIService,
86
84
  productRepository: membersApi.productRepository
87
- });
85
+ };
88
86
  };
89
87
 
90
88
  const initVerificationTrigger = () => {
@@ -150,10 +148,22 @@ module.exports = {
150
148
  }
151
149
  module.exports.verificationTrigger = verificationTrigger;
152
150
 
153
- const membersCSVImporter = initMembersCSVImporter({stripeAPIService: stripeService.api});
154
- module.exports.processImport = async (options) => {
155
- return await membersCSVImporter.process({...options, verificationTrigger});
156
- };
151
+ const importerDeps = buildImporterDeps({stripeAPIService: stripeService.api});
152
+ const membersCSVImporter = makeImporter(importerDeps);
153
+ // The importer takes plain arguments and returns the domain outcome; callers build
154
+ // the request and shape the response. importCSV decides inline vs deferred by load
155
+ // (the endpoint); importInline always runs now (the Revue data import). This only
156
+ // supplies the verification trigger, a members-service internal.
157
+ module.exports.importCSV = (request) => membersCSVImporter.importCSV(request, verificationTrigger);
158
+ module.exports.importInline = (request) => membersCSVImporter.importInline(request, verificationTrigger);
159
+
160
+ // Constructed here rather than required statically: the exporter needs the
161
+ // custom fields services, which boot builds before this one.
162
+ const customFields = require('../members-custom-fields');
163
+ module.exports.export = makeExporter({
164
+ definitions: customFields.definitions,
165
+ values: customFields.values
166
+ });
157
167
 
158
168
  if (!env?.startsWith('testing')) {
159
169
  const membersMigrationJobName = 'members-migrations';
@@ -193,10 +203,11 @@ module.exports = {
193
203
 
194
204
  stripeConnect: require('./stripe-connect'),
195
205
 
196
- processImport: null,
206
+ importCSV: null,
207
+ importInline: null,
197
208
 
198
209
  stats: membersStats,
199
- export: require('./exporter/query')
210
+ export: null
200
211
  };
201
212
 
202
213
  module.exports.middleware = require('./middleware');
@@ -4,7 +4,7 @@ const {Buffer} = require('buffer');
4
4
  const {randomBytes} = require('crypto');
5
5
 
6
6
  const config = require('../../../shared/config');
7
- const urlUtils = require('../../../shared/url-utils');
7
+ const urlUtils = require('../../../shared/url-utils').default;
8
8
 
9
9
  const messages = {
10
10
  incorrectState: 'State did not match.'
@@ -24,6 +24,9 @@ async function recordCustomFieldAction({ Action, context, verb, subject, details
24
24
  await Action.add({
25
25
  event: COMMANDS[verb],
26
26
  resource_type: 'member_custom_field',
27
+ // The field's id: this column holds 24 characters, and a key minted from
28
+ // a publisher-chosen name is bounded by the far wider key column, so only
29
+ // the id fits every field.
27
30
  resource_id: subject,
28
31
  actor_type: context.actor.type,
29
32
  actor_id: context.actor.id,
@@ -29,8 +29,9 @@ export type CustomFieldVerb = keyof typeof COMMANDS;
29
29
  // `details` is stored in the action's `context` column (Ghost's slot for "diffs,
30
30
  // meta"). We always pass the field's `primary_name` so the log reads as a human
31
31
  // label, not a bare key — this is what keeps the timeline legible after a hard
32
- // delete, when the row itself is gone.
33
- export type CustomFieldActionDetails = {primary_name: string; previous_name?: string};
32
+ // delete, when the row itself is gone. `key` rides alongside it because the key is
33
+ // how a field is addressed publicly — its id never leaves the API.
34
+ export type CustomFieldActionDetails = {primary_name: string; key: string; previous_name?: string};
34
35
 
35
36
  export type RecordCustomFieldAction =
36
37
  (input: {context: RequestContext; verb: CustomFieldVerb; subject: string; details: CustomFieldActionDetails}) => Promise<void>;
@@ -47,6 +48,9 @@ export async function recordCustomFieldAction(
47
48
  await Action.add({
48
49
  event: COMMANDS[verb],
49
50
  resource_type: 'member_custom_field',
51
+ // The field's id: this column holds 24 characters, and a key minted from
52
+ // a publisher-chosen name is bounded by the far wider key column, so only
53
+ // the id fits every field.
50
54
  resource_id: subject,
51
55
  actor_type: context.actor.type,
52
56
  actor_id: context.actor.id,
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveMaxDefinitions = resolveMaxDefinitions;
4
+ const zod_1 = require("zod");
5
+ /**
6
+ * Resolving Ghost's config into the values this service runs on.
7
+ *
8
+ * Config arrives untyped: defaults.json supplies the shipped value, and any
9
+ * higher layer — an operator's config file, an environment variable, argv — can
10
+ * replace it with anything at all. Turning that into something usable is a
11
+ * config concern, so it happens here, at the boundary. The service is handed an
12
+ * answer and never learns where it came from.
13
+ */
14
+ // A ceiling in the form the service needs it. A numeric string is accepted
15
+ // because a value supplied through an environment variable can arrive as one.
16
+ const Ceiling = zod_1.z
17
+ .union([zod_1.z.number(), zod_1.z.string().trim().min(1)])
18
+ .transform(Number)
19
+ .pipe(zod_1.z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER));
20
+ // defaults.json is the single source of the shipped ceiling: it is the lowest
21
+ // config layer and the file an operator actually reads and edits, so it is read
22
+ // rather than restated. Parsed eagerly because a missing or malformed value
23
+ // there is our bug rather than an operator's, and should fail loudly at boot
24
+ // instead of quietly becoming the fallback for everything below.
25
+ const shippedCeiling = Ceiling.parse(require('../../../shared/config/defaults.json').members.customFields.maxDefinitions);
26
+ // A higher layer can override the shipped value with anything. Something
27
+ // unreadable falls back to the shipped ceiling rather than throwing, because an
28
+ // operator can correct this live and a bad value must not take the feature down
29
+ // with it — and rather than meaning "no ceiling", because a typo must not
30
+ // silently remove the safeguard.
31
+ const MaxDefinitions = Ceiling.catch(shippedCeiling);
32
+ function resolveMaxDefinitions(configured) {
33
+ return MaxDefinitions.parse(configured);
34
+ }