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
@@ -1,56 +1,6 @@
1
- const errors = require('@tryghost/errors');
2
1
  const jsonSchema = require('../utils/json-schema');
3
- const labs = require('../../../../../../shared/labs');
4
-
5
- // The members JSON schemas live in @tryghost/admin-api-schema and set
6
- // `additionalProperties: false`, so ajv strips `custom_fields` out of the body
7
- // before it reaches the service — silently, with no error to explain where the
8
- // values went. Stash the key across validation and restore it afterwards, so
9
- // values can ride the member body while the rest of it stays schema-validated.
10
- //
11
- // Gated on the flag: with the flag off, the key is stripped exactly as it is
12
- // today. The lasting fix is declaring `custom_fields` in the schema package
13
- // upstream, which is a separate release; this holds the seam until then.
14
- function preserveCustomFields(validate) {
15
- return async function validateWithCustomFields(apiConfig, frame) {
16
- if (!labs.isSet('membersCustomFields') || !Array.isArray(frame.data.members)) {
17
- return validate(apiConfig, frame);
18
- }
19
-
20
- const stashed = frame.data.members.map(member => member && member.custom_fields);
21
-
22
- await validate(apiConfig, frame);
23
-
24
- frame.data.members.forEach((member, index) => {
25
- if (member && stashed[index] !== undefined) {
26
- member.custom_fields = stashed[index];
27
- }
28
- });
29
- };
30
- }
31
-
32
- // Setting values while *creating* a member is a later vertical, not this one. On
33
- // add, ajv would silently strip `custom_fields` (a value that appears to vanish),
34
- // so reject it explicitly instead — the gap is then legible rather than a mystery.
35
- // Flag-gated, so with the flag off the key is stripped exactly as before.
36
- function rejectCustomFieldsOnAdd(validate) {
37
- return function validateWithoutCustomFields(apiConfig, frame) {
38
- const hasCustomFields = labs.isSet('membersCustomFields')
39
- && Array.isArray(frame.data.members)
40
- && frame.data.members.some(member => member && member.custom_fields !== undefined);
41
-
42
- if (hasCustomFields) {
43
- throw new errors.ValidationError({
44
- message: 'Custom field values cannot be set while creating a member. Create the member, then set values with an edit.',
45
- property: 'custom_fields'
46
- });
47
- }
48
-
49
- return validate(apiConfig, frame);
50
- };
51
- }
52
2
 
53
3
  module.exports = {
54
- add: rejectCustomFieldsOnAdd(jsonSchema.validate),
55
- edit: preserveCustomFields(jsonSchema.validate)
4
+ add: jsonSchema.validate,
5
+ edit: jsonSchema.validate
56
6
  };
@@ -5,7 +5,7 @@ const fs = require('fs-extra');
5
5
  const path = require('path');
6
6
  const config = require('../../../shared/config');
7
7
  const logging = require('@tryghost/logging');
8
- const urlUtils = require('../../../shared/url-utils');
8
+ const urlUtils = require('../../../shared/url-utils').default;
9
9
  const exporter = require('../exporter');
10
10
 
11
11
  /**
@@ -3,6 +3,7 @@ const logging = require('@tryghost/logging');
3
3
  const errors = require('@tryghost/errors');
4
4
  const security = require('@tryghost/security');
5
5
  const models = require('../../models');
6
+ const path = require('path');
6
7
 
7
8
  const modelOptions = {context: {internal: true}};
8
9
 
@@ -14,7 +15,7 @@ const exportFileName = async function exportFileName(options) {
14
15
 
15
16
  // custom filename
16
17
  if (options.filename) {
17
- return options.filename + '.json';
18
+ return path.basename(options.filename) + '.json';
18
19
  }
19
20
 
20
21
  try {
@@ -1,8 +1,8 @@
1
1
  const _ = require('lodash');
2
2
  const path = require('path');
3
3
  const config = require('../../../../shared/config');
4
- const urlUtils = require('../../../../shared/url-utils');
5
- const storage = require('../../../adapters/storage');
4
+ const urlUtils = require('../../../../shared/url-utils').default;
5
+ const adapterManager = require('../../../services/adapter-manager').default;
6
6
  let ImageHandler;
7
7
 
8
8
  ImageHandler = {
@@ -12,7 +12,7 @@ ImageHandler = {
12
12
  directories: ['images', 'content'],
13
13
 
14
14
  loadFile: function (files, baseDir) {
15
- const store = storage.getStorage('images');
15
+ const store = adapterManager.getAdapter('storage:images');
16
16
  const baseDirRegex = baseDir ? new RegExp('^' + baseDir + '/') : new RegExp('');
17
17
 
18
18
  const imageFolderRegexes = _.map(store.staticFileURLPrefix.split('/'), function (dir) {
@@ -18,12 +18,14 @@ const MarkdownHandler = require('./handlers/markdown');
18
18
  const ContentFileImporter = require('./importers/content-file-importer');
19
19
  const RevueImporter = require('./importers/importer-revue');
20
20
  const DataImporter = require('./importers/data');
21
- const urlUtils = require('../../../shared/url-utils');
21
+ const urlUtils = require('../../../shared/url-utils').default;
22
22
  const {GhostMailer} = require('../../services/mail');
23
23
  const jobManager = require('../../services/jobs');
24
- const mediaStorage = require('../../adapters/storage').getStorage('media');
25
- const imageStorage = require('../../adapters/storage').getStorage('images');
26
- const fileStorage = require('../../adapters/storage').getStorage('files');
24
+ const adapterManager = require('../../services/adapter-manager').default;
25
+
26
+ const mediaStorage = adapterManager.getAdapter('storage:media');
27
+ const imageStorage = adapterManager.getAdapter('storage:images');
28
+ const fileStorage = adapterManager.getAdapter('storage:files');
27
29
 
28
30
  const {emailTemplate} = require('./email-template');
29
31
  const ghostMailer = new GhostMailer();
@@ -57,14 +57,14 @@ class ContentFileImporter {
57
57
  /** @property {string} */
58
58
  type;
59
59
 
60
- /** @property {import('ghost-storage-base')} */
60
+ /** @property {import('ghost-storage-base').StorageBase} */
61
61
  #store;
62
62
 
63
63
  /**
64
64
  *
65
65
  * @param {Object} deps
66
66
  * @param {'images' | 'media' | 'files'} deps.type - importer type
67
- * @param {import('ghost-storage-base')} deps.store
67
+ * @param {import('ghost-storage-base').StorageBase} deps.store
68
68
  */
69
69
  constructor(deps) {
70
70
  this.type = deps.type;
@@ -6,7 +6,6 @@ const path = require('path');
6
6
  const fs = require('fs-extra');
7
7
 
8
8
  const config = require('../../../../../shared/config');
9
- const models = require('../../../../models');
10
9
 
11
10
  class RevueSubscriberImporter extends BaseImporter {
12
11
  constructor(allDataFromFile) {
@@ -38,17 +37,14 @@ class RevueSubscriberImporter extends BaseImporter {
38
37
  const outputFilePath = path.join(config.getContentPath('data'), '/', outputFileName);
39
38
  const csvData = papaparse.unparse(this.dataToImport);
40
39
 
41
- const memberImporterOptions = {
42
- pathToCSV: outputFilePath,
43
- globalLabels: [{name: importLabel}],
44
- importLabel: {name: importLabel},
45
- LabelModel: models.Label,
46
- forceInline: true
47
- };
48
-
49
40
  await fs.writeFile(outputFilePath, csvData);
50
41
 
51
- return membersService.processImport(memberImporterOptions);
42
+ // Inline: the data import has no request to hold open and needs the result now.
43
+ return membersService.importInline({
44
+ filePath: outputFilePath,
45
+ extraLabels: [{name: importLabel}],
46
+ requestUserEmail: null
47
+ });
52
48
  }
53
49
  }
54
50
 
@@ -4,6 +4,25 @@ const {cards} = require('@tryghost/kg-default-cards');
4
4
  const imageCard = cards.find(c => c.name === 'image');
5
5
  const embedCard = cards.find(c => c.name === 'embed');
6
6
 
7
+ const getValidURL = (url) => {
8
+ const normalizedURL = typeof url === 'string' ? url.trim() : '';
9
+
10
+ if (!normalizedURL) {
11
+ return '';
12
+ }
13
+
14
+ try {
15
+ const parsedURL = new URL(normalizedURL, 'https://example.com');
16
+ if (parsedURL.protocol === 'http:' || parsedURL.protocol === 'https:') {
17
+ return normalizedURL;
18
+ }
19
+ } catch {
20
+ // Invalid URLs are omitted from imported links
21
+ }
22
+
23
+ return '';
24
+ };
25
+
7
26
  // Take the array of items for a specific post and return the converted HTML
8
27
  const itemsToHtml = (items) => {
9
28
  let itemHTMLChunks = [];
@@ -30,22 +49,23 @@ const itemsToHtml = (items) => {
30
49
  } else if (type === 'link') {
31
50
  // This could be a bookmark, or it could be a paragraph of text with a linked header, there's no way to tell
32
51
  // The safest option here is to output an image with text under it
52
+ const itemURL = getValidURL(item.url);
33
53
  let cardOpts = {
34
54
  env: {dom: new SimpleDom.Document()},
35
55
  payload: {
36
56
  src: item.image,
37
57
  caption: item.title,
38
- href: item.url
58
+ href: itemURL
39
59
  }
40
60
  };
41
61
  itemHTMLChunks.push(serializer.serialize(imageCard.render(cardOpts)));
42
-
43
- let linkHTML = `<h4><a href="${item.url}">${item.title}</a></h4>${item.description}`;
62
+ const linkTitleHTML = itemURL ? `<a href="${serializer.escapeAttrValue(itemURL)}">${item.title}</a>` : item.title;
63
+ let linkHTML = `<h4>${linkTitleHTML}</h4>${item.description}`;
44
64
  itemHTMLChunks.push(linkHTML);
45
65
  } else if (type === 'tweet') {
46
66
  // Should this be an oEmbed call? Probably.
47
67
  itemHTMLChunks.push(`<figure class="kg-card kg-embed-card">
48
- <blockquote class="twitter-tweet"><a href="${item.url}"></a></blockquote>
68
+ <blockquote class="twitter-tweet"><a href="${serializer.escapeAttrValue(item.url)}"></a></blockquote>
49
69
  <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
50
70
  </figure>`);
51
71
  } else if (type === 'video') {
@@ -191,12 +191,14 @@ function createSetNullableMigration(table, column, options = {}) {
191
191
  /**
192
192
  * @param {string} table
193
193
  * @param {string[]|string} columns One or multiple columns (in case the index should be for multiple columns)
194
+ * @param {object} [options]
195
+ * @param {number} [options.length] MySQL only: create a prefix index of this many characters
194
196
  * @returns {Migration}
195
197
  */
196
- function createAddIndexMigration(table, columns) {
198
+ function createAddIndexMigration(table, columns, options = {}) {
197
199
  return createTransactionalMigration(
198
200
  async function up(knex) {
199
- await commands.addIndex(table, columns, knex);
201
+ await commands.addIndex(table, columns, knex, options);
200
202
  },
201
203
  async function down(knex) {
202
204
  await commands.dropIndex(table, columns, knex);
@@ -0,0 +1,10 @@
1
+ const {addPermissionWithRoles} = require('../../utils');
2
+
3
+ // Content import (the CSV posts importer) is restricted to Administrators
4
+ // (the Owner bypasses permission checks) and the self-serve migrator's
5
+ // integration, mirroring the existing db importContent permissions.
6
+ module.exports = addPermissionWithRoles({
7
+ name: 'Import content',
8
+ action: 'importContent',
9
+ object: 'content_import'
10
+ }, ['Administrator', 'Self-Serve Migration Integration']);
@@ -0,0 +1,7 @@
1
+ const {createDropColumnMigration} = require('../../utils');
2
+
3
+ module.exports = createDropColumnMigration('automation_action_revisions', 'email_tracked_sent_count', {
4
+ type: 'integer',
5
+ nullable: true,
6
+ unsigned: true
7
+ }, {algorithm: 'auto'});
@@ -0,0 +1,3 @@
1
+ const {createAddIndexMigration} = require('../../utils');
2
+
3
+ module.exports = createAddIndexMigration('automation_run_steps', ['status', 'ready_at', 'created_at', 'id']);
@@ -0,0 +1,3 @@
1
+ const {createAddIndexMigration} = require('../../utils');
2
+
3
+ module.exports = createAddIndexMigration('automated_email_recipients', ['mailgun_message_id'], {length: 31});
@@ -0,0 +1,13 @@
1
+ const {combineNonTransactionalMigrations, createAddColumnMigration} = require('../../utils');
2
+
3
+ module.exports = combineNonTransactionalMigrations(
4
+ createAddColumnMigration('automated_email_recipients', 'track_clicks', {
5
+ type: 'boolean',
6
+ nullable: false,
7
+ defaultTo: false
8
+ }, {algorithm: 'auto'}),
9
+ createAddColumnMigration('automated_email_recipients', 'clicked_at', {
10
+ type: 'dateTime',
11
+ nullable: true
12
+ }, {algorithm: 'auto'})
13
+ );
@@ -0,0 +1,7 @@
1
+ const {createAddColumnMigration} = require('../../utils');
2
+
3
+ module.exports = createAddColumnMigration('automation_action_revisions', 'email_clicked_count', {
4
+ type: 'integer',
5
+ nullable: true,
6
+ unsigned: true
7
+ }, {algorithm: 'auto'});
@@ -0,0 +1,9 @@
1
+ const {createAddColumnMigration} = require('../../utils');
2
+
3
+ module.exports = createAddColumnMigration('redirects', 'automation_action_revision_id', {
4
+ type: 'string',
5
+ maxlength: 24,
6
+ nullable: true,
7
+ references: 'automation_action_revisions.id',
8
+ setNullDelete: true
9
+ }, {algorithm: 'auto'});
@@ -5,6 +5,7 @@ const tpl = require('@tryghost/tpl');
5
5
  const db = require('../db');
6
6
  const DatabaseInfo = require('@tryghost/database-info');
7
7
  const schema = require('./schema');
8
+ const {defaultIndexName} = require('./lib/default-index-name');
8
9
 
9
10
  const messages = {
10
11
  hasPrimaryKeySQLiteError: 'Must use hasPrimaryKeySQLite on an SQLite3 database',
@@ -191,19 +192,38 @@ async function renameColumn(tableName, from, to, transaction = db.knex) {
191
192
  });
192
193
  }
193
194
 
195
+ /**
196
+ * Builds the column arguments for a MySQL index prefix, such as `col(123)`.
197
+ *
198
+ * @param {import('knex').Knex} knex
199
+ * @param {string|string[]} columns
200
+ * @param {number} length
201
+ * @returns {import('knex').Knex.Raw[]}
202
+ */
203
+ function prefixIndexColumns(knex, columns, length) {
204
+ return (Array.isArray(columns) ? columns : [columns])
205
+ .map(col => knex.raw('?? (?)', [col, length]));
206
+ }
207
+
194
208
  /**
195
209
  * Adds an non-unique index to a table over the given columns.
196
210
  *
197
211
  * @param {string} tableName - name of the table to add indexes to
198
212
  * @param {string|string[]} columns - column(s) to add indexes for
199
213
  * @param {import('knex').Knex} [transaction] - connection object containing knex reference
214
+ * @param {object} [options]
215
+ * @param {number} [options.length] - MySQL only: create a prefix index of this many characters
200
216
  */
201
- async function addIndex(tableName, columns, transaction = db.knex) {
217
+ async function addIndex(tableName, columns, transaction = db.knex, options = {}) {
202
218
  try {
203
219
  logging.info(`Adding index for '${columns}' in table '${tableName}'`);
204
220
 
205
221
  return await transaction.schema.table(tableName, function (table) {
206
- table.index(columns);
222
+ if (options.length && DatabaseInfo.isMySQL(transaction)) {
223
+ table.index(prefixIndexColumns(transaction, columns, options.length), defaultIndexName(tableName, columns));
224
+ } else {
225
+ table.index(columns);
226
+ }
207
227
  });
208
228
  } catch (err) {
209
229
  if (err.code === 'SQLITE_ERROR') {
@@ -500,7 +520,21 @@ function createTable(table, transaction = db.knex, tableSpec = schema[table]) {
500
520
  .forEach(column => addTableColumn(table, t, column, tableSpec[column]));
501
521
 
502
522
  if (tableSpec['@@INDEXES@@']) {
503
- tableSpec['@@INDEXES@@'].forEach(index => t.index(index));
523
+ tableSpec['@@INDEXES@@'].forEach((index) => {
524
+ if (index && typeof index === 'object' && !Array.isArray(index)) {
525
+ if (index.length && DatabaseInfo.isMySQL(transaction)) {
526
+ t.index(
527
+ prefixIndexColumns(transaction, index.columns, index.length),
528
+ defaultIndexName(table, index.columns)
529
+ );
530
+ } else {
531
+ // SQLite doesn't support prefix indexes, so we index the whole thing.
532
+ t.index(index.columns);
533
+ }
534
+ } else {
535
+ t.index(index);
536
+ }
537
+ });
504
538
  }
505
539
  if (tableSpec['@@UNIQUE_CONSTRAINTS@@']) {
506
540
  tableSpec['@@UNIQUE_CONSTRAINTS@@'].forEach(unique => t.unique(unique));
@@ -144,6 +144,11 @@
144
144
  "action_type": "deleteAllContent",
145
145
  "object_type": "db"
146
146
  },
147
+ {
148
+ "name": "Import content",
149
+ "action_type": "importContent",
150
+ "object_type": "content_import"
151
+ },
147
152
  {
148
153
  "name": "Send mail",
149
154
  "action_type": "send",
@@ -966,6 +971,7 @@
966
971
  "entries": {
967
972
  "Administrator": {
968
973
  "db": "all",
974
+ "content_import": "all",
969
975
  "mail": "all",
970
976
  "notification": "all",
971
977
  "post": "all",
@@ -1020,6 +1026,7 @@
1020
1026
  },
1021
1027
  "Self-Serve Migration Integration": {
1022
1028
  "db": "importContent",
1029
+ "content_import": "importContent",
1023
1030
  "member": "add",
1024
1031
  "tag": "read"
1025
1032
  },
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Normally, we use Knex for index names. But in some cases, we need to derive
3
+ * them because Knex won't get it right. We try to match [Knex's code][0] as
4
+ * closely as possible.
5
+ *
6
+ * [0]: https://github.com/knex/knex/blob/e25d54bcb707714a17f5a5744eba5c4246bb4d1d/lib/schema/tablecompiler.js#L401-L415
7
+ *
8
+ * @param {string} tableName
9
+ * @param {string|string[]} columns
10
+ * @returns {string}
11
+ */
12
+ function defaultIndexName(tableName, columns) {
13
+ if (!Array.isArray(columns)) {
14
+ columns = columns ? [columns] : [];
15
+ }
16
+ const table = tableName.replace(/\.|-/g, '_');
17
+ return (table + '_' + columns.join('_') + '_index').toLowerCase();
18
+ }
19
+
20
+ exports.defaultIndexName = defaultIndexName;
@@ -1076,20 +1076,6 @@ module.exports = {
1076
1076
  metadata: {type: 'string', maxlength: 2000, nullable: true},
1077
1077
  queue_entry: {type: 'integer', nullable: true, unsigned: true}
1078
1078
  },
1079
- redirects: {
1080
- id: {type: 'string', maxlength: 24, nullable: false, primary: true},
1081
- from: {type: 'string', maxlength: 191, nullable: false, index: true},
1082
- to: {type: 'string', maxlength: 2000, nullable: false},
1083
- post_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'posts.id', setNullDelete: true},
1084
- created_at: {type: 'dateTime', nullable: false},
1085
- updated_at: {type: 'dateTime', nullable: true}
1086
- },
1087
- members_click_events: {
1088
- id: {type: 'string', maxlength: 24, nullable: false, primary: true},
1089
- member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
1090
- redirect_id: {type: 'string', maxlength: 24, nullable: false, references: 'redirects.id', cascadeDelete: true},
1091
- created_at: {type: 'dateTime', nullable: false}
1092
- },
1093
1079
  members_feedback: {
1094
1080
  id: {type: 'string', maxlength: 24, nullable: false, primary: true},
1095
1081
  score: {type: 'integer', nullable: false, unsigned: true, defaultTo: 0},
@@ -1265,12 +1251,27 @@ module.exports = {
1265
1251
  email_lexical: {type: 'text', maxlength: 1000000000, fieldtype: 'long', nullable: true},
1266
1252
  email_design_setting_id: {type: 'string', maxlength: 24, nullable: true, references: 'email_design_settings.id', setNullDelete: true},
1267
1253
  email_sent_count: {type: 'integer', nullable: true, unsigned: true},
1268
- email_tracked_sent_count: {type: 'integer', nullable: true, unsigned: true},
1269
1254
  email_opened_count: {type: 'integer', nullable: true, unsigned: true},
1255
+ email_clicked_count: {type: 'integer', nullable: true, unsigned: true},
1270
1256
  '@@UNIQUE_CONSTRAINTS@@': [
1271
1257
  ['created_at', 'action_id']
1272
1258
  ]
1273
1259
  },
1260
+ redirects: {
1261
+ id: {type: 'string', maxlength: 24, nullable: false, primary: true},
1262
+ from: {type: 'string', maxlength: 191, nullable: false, index: true},
1263
+ to: {type: 'string', maxlength: 2000, nullable: false},
1264
+ post_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'posts.id', setNullDelete: true},
1265
+ automation_action_revision_id: {type: 'string', maxlength: 24, nullable: true, references: 'automation_action_revisions.id', setNullDelete: true},
1266
+ created_at: {type: 'dateTime', nullable: false},
1267
+ updated_at: {type: 'dateTime', nullable: true}
1268
+ },
1269
+ members_click_events: {
1270
+ id: {type: 'string', maxlength: 24, nullable: false, primary: true},
1271
+ member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
1272
+ redirect_id: {type: 'string', maxlength: 24, nullable: false, references: 'redirects.id', cascadeDelete: true},
1273
+ created_at: {type: 'dateTime', nullable: false}
1274
+ },
1274
1275
  automation_action_edges: {
1275
1276
  source_action_id: {type: 'string', maxlength: 24, nullable: false, references: 'automation_actions.id', restrictDelete: true},
1276
1277
  target_action_id: {type: 'string', maxlength: 24, nullable: false, references: 'automation_actions.id', restrictDelete: true},
@@ -1296,7 +1297,10 @@ module.exports = {
1296
1297
  finished_at: {type: 'dateTime', nullable: true},
1297
1298
  status: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'pending', validations: {isIn: [['pending', 'automation disabled', 'failed', 'finished', 'member changed status', 'member unsubscribed']]}},
1298
1299
  locked_by: {type: 'string', maxlength: 191, nullable: true},
1299
- locked_at: {type: 'dateTime', nullable: true}
1300
+ locked_at: {type: 'dateTime', nullable: true},
1301
+ '@@INDEXES@@': [
1302
+ ['status', 'ready_at', 'created_at', 'id']
1303
+ ]
1300
1304
  },
1301
1305
  welcome_email_automated_emails: {
1302
1306
  id: {type: 'string', maxlength: 24, nullable: false, primary: true},
@@ -1338,9 +1342,28 @@ module.exports = {
1338
1342
  mailgun_message_id: {type: 'string', maxlength: 1000, nullable: true},
1339
1343
  delivered_at: {type: 'dateTime', nullable: true},
1340
1344
  opened_at: {type: 'dateTime', nullable: true},
1345
+ clicked_at: {type: 'dateTime', nullable: true},
1341
1346
  track_opens: {type: 'boolean', nullable: false, defaultTo: false},
1347
+ track_clicks: {type: 'boolean', nullable: false, defaultTo: false},
1342
1348
  created_at: {type: 'dateTime', nullable: false},
1343
- updated_at: {type: 'dateTime', nullable: true}
1349
+ updated_at: {type: 'dateTime', nullable: true},
1350
+ '@@INDEXES@@': [
1351
+ // `mailgun_message_id` is too long for a MySQL index, so we use a
1352
+ // prefix.
1353
+ //
1354
+ // We choose 31 because Mailgun message IDs look like this:
1355
+ //
1356
+ // 20200420080647.ab01cd02ef03ba04@mailgun.domain.example
1357
+ // YYYYMMDDHHMMSS.RANDOM-HEX-BYTES@DOMAIN
1358
+ //
1359
+ // That first part is unlikely to have conflicts, so let's use
1360
+ // that. This index is for performance, not uniqueness, so it's
1361
+ // okay if there's a conflict.
1362
+ //
1363
+ // Note that this prefix index only happens for MySQL. SQLite
1364
+ // indexes the full value.
1365
+ {columns: ['mailgun_message_id'], length: 31}
1366
+ ]
1344
1367
  },
1345
1368
  gifts: {
1346
1369
  id: {type: 'string', maxlength: 24, nullable: false, primary: true},
@@ -59,8 +59,10 @@ class DataGenerator {
59
59
  table.dependencies = Object.entries(this.schemaTables[table.name]).reduce((acc, [_col, data]) => {
60
60
  if (data.references) {
61
61
  const referencedTable = data.references.split('.')[0];
62
- // The ghost_subscriptions_id property has a foreign key to the subscriptions table, but we don't use that table yet atm, so don't add it as a dependency
63
- if (!acc.includes(referencedTable) && referencedTable !== 'subscriptions') {
62
+ // Some nullable relationships point to tables the generator does not populate.
63
+ // Generated redirects belong to posts, so automation revisions are not a seed dependency.
64
+ const isUnsupportedOptionalDependency = referencedTable === 'subscriptions' || (referencedTable === 'automation_action_revisions' && data.nullable);
65
+ if (!acc.includes(referencedTable) && !isUnsupportedOptionalDependency) {
64
66
  acc.push(referencedTable);
65
67
  }
66
68
  }
@@ -17,29 +17,15 @@ const FETCH_ONLY_FORMATS = [
17
17
  ];
18
18
 
19
19
  class ImageSize {
20
- constructor({config, storage, storageUtils, validator, urlUtils, request, probe}) {
20
+ constructor({config, imageStore, storageUtils, validator, urlUtils, fetchExternal, probe}) {
21
21
  this.config = config;
22
- this.storage = storage;
22
+ this.imageStore = imageStore;
23
23
  this.storageUtils = storageUtils;
24
24
  this.validator = validator;
25
25
  this.urlUtils = urlUtils;
26
- this.request = request;
26
+ this.fetchExternal = fetchExternal;
27
27
  this.probe = probe;
28
28
 
29
- this.REQUEST_OPTIONS = {
30
- // we need the user-agent, otherwise some https request may fail (e.g. cloudfare)
31
- headers: {
32
- 'User-Agent': 'Mozilla/5.0 Safari/537.36'
33
- },
34
- timeout: {
35
- request: this.config.get('times:getImageSizeTimeoutInMS') || 10000
36
- },
37
- retry: {
38
- limit: 0 // for `got`, used with image-size
39
- },
40
- responseType: 'buffer'
41
- };
42
-
43
29
  this.NEEDLE_OPTIONS = {
44
30
  // we need the user-agent, otherwise some https request may fail (e.g. cloudflare)
45
31
  headers: {
@@ -107,7 +93,7 @@ class ImageSize {
107
93
  // download full image then use image-size to get it's dimensions
108
94
  // returns promise which resolves dimensions
109
95
  _fetchImageSizeFromUrl(imageUrl) {
110
- return this.request(imageUrl, this.REQUEST_OPTIONS).then((response) => {
96
+ return this.fetchExternal(imageUrl, this.NEEDLE_OPTIONS).then((response) => {
111
97
  return this._imageSizeFromBuffer(response.body);
112
98
  });
113
99
  }
@@ -248,8 +234,7 @@ class ImageSize {
248
234
  // get the storage readable filePath
249
235
  filePath = this.storageUtils.getLocalImagesStoragePath(imagePath);
250
236
 
251
- return this.storage.getStorage('images')
252
- .read({path: filePath})
237
+ return this.imageStore.read({path: filePath})
253
238
  .then((buf) => {
254
239
  debug('Image fetched (storage):', filePath);
255
240
  return this._imageSizeFromBuffer(buf);
@@ -298,10 +283,9 @@ class ImageSize {
298
283
  */
299
284
  async getOriginalImagePath(imagePath) {
300
285
  const {dir, name, ext} = path.parse(imagePath);
301
- const storageInstance = this.storage.getStorage('images');
302
286
 
303
287
  const preferredUnoptimizedImagePath = path.join(dir, `${name}_o${ext}`);
304
- const preferredUnoptimizedImagePathExists = await storageInstance.exists(preferredUnoptimizedImagePath);
288
+ const preferredUnoptimizedImagePathExists = await this.imageStore.exists(preferredUnoptimizedImagePath);
305
289
  if (preferredUnoptimizedImagePathExists) {
306
290
  return preferredUnoptimizedImagePath;
307
291
  }
@@ -315,7 +299,7 @@ class ImageSize {
315
299
  }
316
300
 
317
301
  const legacyOriginalImagePath = path.join(dir, `${imageName}_o${imageNumber || ''}${ext}`);
318
- const legacyOriginalImageExists = await storageInstance.exists(legacyOriginalImagePath);
302
+ const legacyOriginalImageExists = await this.imageStore.exists(legacyOriginalImagePath);
319
303
 
320
304
  return legacyOriginalImageExists ? legacyOriginalImagePath : imagePath;
321
305
  }
@@ -24,10 +24,23 @@ function probe(url, options = {}, {probeImageSize: probeImageSizeFn = probeImage
24
24
  return promise;
25
25
  }
26
26
 
27
+ // For image formats that require a full fetch. This function ensures that
28
+ // SSRF protections are in place by using the externalRequest `got` client.
29
+ function fetchExternal(url, options = {}) {
30
+ return externalRequest.get(url, {
31
+ headers: options.headers,
32
+ timeout: {
33
+ request: options.response_timeout || 10000
34
+ },
35
+ responseType: 'buffer',
36
+ retry: {limit: 0}
37
+ });
38
+ }
39
+
27
40
  class ImageUtils {
28
- constructor({config, urlUtils, settingsCache, storageUtils, storage, validator, request, cacheStore}) {
41
+ constructor({config, urlUtils, settingsCache, storageUtils, imageStore, validator, request, cacheStore}) {
29
42
  this.blogIcon = new BlogIcon({config, urlUtils, settingsCache, storageUtils});
30
- this.imageSize = new ImageSize({config, storage, storageUtils, validator, urlUtils, request, probe});
43
+ this.imageSize = new ImageSize({config, imageStore, storageUtils, validator, urlUtils, fetchExternal, probe});
31
44
  this.cachedImageSizeFromUrl = new CachedImageSizeFromUrl({
32
45
  getImageSizeFromUrl: this.imageSize.getImageSizeFromUrl.bind(this.imageSize),
33
46
  cache: cacheStore
@@ -38,3 +51,4 @@ class ImageUtils {
38
51
 
39
52
  module.exports = ImageUtils;
40
53
  module.exports.probe = probe;
54
+ module.exports.fetchExternal = fetchExternal;