ghost 6.53.0 → 6.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (596) 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.1.1.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-CSaHoSVD.js +3 -0
  14. package/core/built/admin/assets/Newsletters-C5cs6FGo.js +1 -0
  15. package/core/built/admin/assets/Overview-j4NaeUNm.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-_fD935OX.js +2 -0
  19. package/core/built/admin/assets/account-migration-DLvVA5yq.js +1 -0
  20. package/core/built/admin/assets/activitypub/{account-migration-BPZG37DJ.js → account-migration-DHbZcxGM.js} +13 -13
  21. package/core/built/admin/assets/activitypub/activitypub.js +7 -7
  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-zfxUey_L.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-B5ira32t.js → dist-Ba_QxHHl.js} +5 -5
  29. package/core/built/admin/assets/activitypub/{domain-iqE4YXwD.js → domain-CmwSZLHK.js} +33 -33
  30. package/core/built/admin/assets/activitypub/{edit-profile-B8MFYh28.js → edit-profile-CXdwNmVG.js} +46 -45
  31. package/core/built/admin/assets/activitypub/{explore-BbdKodp3.js → explore-DfbjzGM1.js} +20 -20
  32. package/core/built/admin/assets/activitypub/{feed-Cl3A5owG.js → feed-DSEBJOqf.js} +15 -15
  33. package/core/built/admin/assets/activitypub/{field-DL6WyR-c.js → field-CY7XVcx6.js} +13 -13
  34. package/core/built/admin/assets/activitypub/{hash-6G3DzwL9.js → hash-BC9Q0N4c.js} +2 -2
  35. package/core/built/admin/assets/activitypub/{inbox-YmhuBice.js → inbox-DQ4ZnC1m.js} +2 -2
  36. package/core/built/admin/assets/activitypub/inbox-DtQ0kytT.js +1221 -0
  37. package/core/built/admin/assets/activitypub/{label-DGbLjDvE.js → label-Dw96GQ7u.js} +6 -6
  38. package/core/built/admin/assets/activitypub/layout-IdVq3lRy.js +1 -0
  39. package/core/built/admin/assets/activitypub/{moderation-qnBtk1zS.js → moderation-Dg_-I-8C.js} +32 -31
  40. package/core/built/admin/assets/activitypub/{note-C7ZRoSJv.js → note-Cy1-uKMY.js} +21 -21
  41. package/core/built/admin/assets/activitypub/{notifications-DiEA4b1o.js → notifications-B_fvoLIM.js} +17 -17
  42. package/core/built/admin/assets/activitypub/{onboarding-_JVgEwgV.js → onboarding-BFDkzeR2.js} +2 -2
  43. package/core/built/admin/assets/activitypub/{onboarding-DG4zu3qM.js → onboarding-D6rcBdPe.js} +5 -5
  44. package/core/built/admin/assets/activitypub/{preferences-B3FtocnP.js → preferences-ByJseZp6.js} +1607 -1606
  45. package/core/built/admin/assets/activitypub/{profile-D8ZJfYXB.js → profile-BFtbnIjz.js} +264 -263
  46. package/core/built/admin/assets/activitypub/{reply-C1vggenw.js → reply-CpdMeAO5.js} +2 -2
  47. package/core/built/admin/assets/activitypub/{routes-BOii-V9n.js → routes-Dh3xXfce.js} +1311 -1295
  48. package/core/built/admin/assets/activitypub/{separator-1gNokN5S.js → separator-BI1FLsYM.js} +4 -4
  49. package/core/built/admin/assets/activitypub/{settings--9Sb0nbl.js → settings-DTgqJPxM.js} +14 -14
  50. package/core/built/admin/assets/activitypub/{site-fkMmqv0V.js → site-CdL9ZLqm.js} +10 -10
  51. package/core/built/admin/assets/activitypub/{step-1-QhivSMw2.js → step-1-DIDg4aHb.js} +15 -15
  52. package/core/built/admin/assets/activitypub/{step-2-pMk9YwqD.js → step-2-BfGe8BYt.js} +7 -7
  53. package/core/built/admin/assets/activitypub/{step-3-DvmVC1fo.js → step-3-mE9spAqw.js} +12 -12
  54. package/core/built/admin/assets/activitypub/{tabs-Dc0FEEYD.js → tabs-ogqwoBlb.js} +241 -237
  55. package/core/built/admin/assets/activitypub/{topic-filter-CuDyM5bD.js → topic-filter-DLHBZT93.js} +4 -4
  56. package/core/built/admin/assets/activitypub/use-activity-pub-queries-VzbN99u_.js +1957 -0
  57. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Drx1kdAK.js → use-navigate-with-base-path-CAwXTmqH.js} +165 -175
  58. package/core/built/admin/assets/activitypub/{use-reply-chain-data-BHkCHcW5.js → use-reply-chain-data-CxonteFD.js} +8 -8
  59. package/core/built/admin/assets/activitypub/users-BLeiOTHc.js +1464 -0
  60. package/core/built/admin/assets/activitypub/{x-BHCEe-c2.js → x-C8tAnXly.js} +2 -2
  61. package/core/built/admin/assets/{audience-adiFehTD.js → audience-BKRdsFmy.js} +1 -1
  62. package/core/built/admin/assets/{automated-emails-UWM02CMr.js → automated-emails-Cn87L5Md.js} +1 -1
  63. package/core/built/admin/assets/automations-B7-y3dXt.js +1 -0
  64. package/core/built/admin/assets/automations-BP_aHamJ.js +1 -0
  65. package/core/built/admin/assets/{avatar-flipboard-Lz3F9fNT.js → avatar-flipboard-C6Kj3Awu.js} +1 -1
  66. package/core/built/admin/assets/bluesky-sharing-Bh36XPh4.js +1 -0
  67. package/core/built/admin/assets/box-BWbhXh21.js +1 -0
  68. package/core/built/admin/assets/breadcrumb-D34YWnaw.js +1 -0
  69. package/core/built/admin/assets/card-DGoDJzrn.js +1 -0
  70. package/core/built/admin/assets/{chart-ChpW-NzQ.js → chart-BuRT2Y6p.js} +14 -14
  71. package/core/built/admin/assets/chart-helpers-DbklaJw9.js +1 -0
  72. package/core/built/admin/assets/checkbox-DA4-1UiI.js +1 -0
  73. package/core/built/admin/assets/chunk.524.45e0875f41b71e46e849.js +25 -0
  74. package/core/built/admin/assets/chunk.582.51defd4b009f0de8d4d5.js +27 -0
  75. package/core/built/admin/assets/{chunk.831.0703a12e49f51cec3f3a.js → chunk.589.096f4d0bb775e5229aa9.js} +78 -85
  76. package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js → chunk.962.b73442b07be930bb5d85.js} +2216 -3188
  77. package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js.LICENSE.txt → chunk.962.b73442b07be930bb5d85.js.LICENSE.txt} +0 -63
  78. package/core/built/admin/assets/code-editor-view-BKBrkffZ.js +1 -0
  79. package/core/built/admin/assets/comments-CzVNIT8b.js +1 -0
  80. package/core/built/admin/assets/container-BYz2Ed39.js +1 -0
  81. package/core/built/admin/assets/data-list-16rkJYYi.js +1 -0
  82. package/core/built/admin/assets/date-range-select-B5vSsrpx.js +1 -0
  83. package/core/built/admin/assets/disabled-sources-indicator-NkOIoMue.js +1 -0
  84. package/core/built/admin/assets/{dist-CsekE4FL.js → dist-CQJY6SVY.js} +1 -1
  85. package/core/built/admin/assets/dist-DGzPJ_bO.js +4 -0
  86. package/core/built/admin/assets/{dist-BbGrW05X.js → dist-DyViJwIy.js} +1 -1
  87. package/core/built/admin/assets/dist-Ndy-PuGN.js +1 -0
  88. package/core/built/admin/assets/dist-P_ohUlTi.js +1 -0
  89. package/core/built/admin/assets/domain-B7_n5nfx.js +1 -0
  90. package/core/built/admin/assets/dropzone-DcuJEEUf.js +5 -0
  91. package/core/built/admin/assets/edit-profile-rvDGrS8J.js +1 -0
  92. package/core/built/admin/assets/editor-BCiIyFjm.js +8 -0
  93. package/core/built/admin/assets/empty-indicator-oX1u1Pkn.js +1 -0
  94. package/core/built/admin/assets/esm-CFX93H5M.js +2 -0
  95. package/core/built/admin/assets/explore-BZAZOg5X.js +1 -0
  96. package/core/built/admin/assets/feed-CFV8xDw9.js +1 -0
  97. package/core/built/admin/assets/field-BW-M2Zwp.js +1 -0
  98. package/core/built/admin/assets/{filter-sources-v39ihhhV.js → filter-sources-Fx8wiYYw.js} +1 -1
  99. package/core/built/admin/assets/filters-CGX_pf2N.js +1 -0
  100. package/core/built/admin/assets/filters-DtcXMZDU.js +1 -0
  101. package/core/built/admin/assets/framework-provider-CmtnPXIT.js +4 -0
  102. package/core/built/admin/assets/{ghost-b57f077997b739a8ae9a70772dc016cb.js → ghost-b1dce91ad3232cc259ee5fbbf9526243.js} +294 -290
  103. package/core/built/admin/assets/ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css +1 -0
  104. package/core/built/admin/assets/gift-link-modal-Bk8qpnMw.js +1 -0
  105. package/core/built/admin/assets/{gift-links-CY3GwiVi.js → gift-links-nBxJjZiQ.js} +1 -1
  106. package/core/built/admin/assets/growth-Ck2s3JjR.js +1 -0
  107. package/core/built/admin/assets/hooks-BApwwBE0.js +2 -0
  108. package/core/built/admin/assets/{inbox-TEISAmth.js → inbox-BRp1_aaC.js} +35 -35
  109. package/core/built/admin/assets/index-BBf502Wg.js +69 -0
  110. package/core/built/admin/assets/index-BCCZKxP2.css +1 -0
  111. package/core/built/admin/assets/inline-EMAm3okk.js +1 -0
  112. package/core/built/admin/assets/input-group-DjuYnNCd.js +1 -0
  113. package/core/built/admin/assets/{react-dom-C6aoWSfl.js → jsx-runtime-DX3WBWVO.js} +1 -1
  114. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +5 -2
  115. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +2 -2
  116. package/core/built/admin/assets/{koenig-lexical-Di7b48ED.js → koenig-lexical-CM7UFNdL.js} +2 -2
  117. package/core/built/admin/assets/kpi-card-BrGH6FsT.js +1 -0
  118. package/core/built/admin/assets/kpi-card-CIGyijjx.js +1 -0
  119. package/core/built/admin/assets/kpi-helpers-_HRRsklE.js +1 -0
  120. package/core/built/admin/assets/kpi-tabs-BSvh9eoq.js +1 -0
  121. package/core/built/admin/assets/label-BOR9XdKl.js +1 -0
  122. package/core/built/admin/assets/label-picker-BdNAWuUX.js +1 -0
  123. package/core/built/admin/assets/{labels-GbxlXWtf.js → labels-Cyayfd-e.js} +1 -1
  124. package/core/built/admin/assets/layout-Bw4GnxXp.js +1 -0
  125. package/core/built/admin/assets/limit-service-9fwD33lU.js +20 -0
  126. package/core/built/admin/assets/link-helpers-tOlxmuH5.js +1 -0
  127. package/core/built/admin/assets/list-page-B6ANtzkd.js +1 -0
  128. package/core/built/admin/assets/mailchimp-Ds_NQ04w.svg +9 -0
  129. package/core/built/admin/assets/member-custom-fields-DvFyamLu.js +1 -0
  130. package/core/built/admin/assets/member-detail-Cg2vTqvJ.js +1 -0
  131. package/core/built/admin/assets/members-DsPxYAVm.js +10 -0
  132. package/core/built/admin/assets/modals-Bf_fyvHZ.js +31 -0
  133. package/core/built/admin/assets/moderation-Dlp7M5sa.js +1 -0
  134. package/core/built/admin/assets/multi-select-combobox-CH1o8XXQ.js +1 -0
  135. package/core/built/admin/assets/newsletter-CQ5CAYUI.js +1 -0
  136. package/core/built/admin/assets/{newsletters-DZm3yLj8.js → newsletters-D1jbtV-h.js} +1 -1
  137. package/core/built/admin/assets/note-BrAZ7Z0o.js +1 -0
  138. package/core/built/admin/assets/notifications-BnbHLOPC.js +1 -0
  139. package/core/built/admin/assets/nql-lang-B7faUf8D.js +19 -0
  140. package/core/built/admin/assets/{offers-D11QtPXX.js → offers-CrY6nSRR.js} +1 -1
  141. package/core/built/admin/assets/onboarding-route-eU146kuA.js +1 -0
  142. package/core/built/admin/assets/overview-BpbaK-xu.js +1 -0
  143. package/core/built/admin/assets/page-header-C0jVxtS8.js +1 -0
  144. package/core/built/admin/assets/{pages-BnObVRrf.js → pages-BbNWFcGj.js} +1 -1
  145. package/core/built/admin/assets/pintura-CXOmq-5H.svg +15 -0
  146. package/core/built/admin/assets/post-analytics-Iw7dk1mT.js +1 -0
  147. package/core/built/admin/assets/post-analytics-header-D9pJ4iNm.js +1 -0
  148. package/core/built/admin/assets/{post-analytics-provider-DSfBCtnj.js → post-analytics-provider-BDqcfBor.js} +1 -1
  149. package/core/built/admin/assets/post-share-modal-DBfKl2GZ.js +1 -0
  150. package/core/built/admin/assets/{posts-CwH8VJvB.js → posts-EWpZIjkr.js} +1 -1
  151. package/core/built/admin/assets/preferences-D4EANGoc.js +5 -0
  152. package/core/built/admin/assets/profile-dJ44Bn_W.js +1 -0
  153. package/core/built/admin/assets/{referrers-nxR52jPI.js → referrers-BCfFYSHc.js} +1 -1
  154. package/core/built/admin/assets/router-provider-C1R4AZ2o.js +1 -0
  155. package/core/built/admin/assets/select--2uVN9_-.js +1 -0
  156. package/core/built/admin/assets/settings-Bz3RZRmE.js +1 -0
  157. package/core/built/admin/assets/settings-SD9bxIpt.js +4 -0
  158. package/core/built/admin/assets/share-modal-CkdTTMJd.js +1 -0
  159. package/core/built/admin/assets/social-urls-BvFZwYcE.js +8 -0
  160. package/core/built/admin/assets/sort-button-DZp9Y2r1.js +1 -0
  161. package/core/built/admin/assets/source-icon-CHr9qJ2Y.js +1 -0
  162. package/core/built/admin/assets/stack-xiN0eQ6Z.js +1 -0
  163. package/core/built/admin/assets/stats-DGoXZxWE.js +1 -0
  164. package/core/built/admin/assets/stats-view-D2-1L0ms.js +1 -0
  165. package/core/built/admin/assets/step-1-RdahbwyG.js +1 -0
  166. package/core/built/admin/assets/step-2-D83PeRwd.js +1 -0
  167. package/core/built/admin/assets/step-3-p_Op4wv4.js +2 -0
  168. package/core/built/admin/assets/switch-qp518gFQ.js +1 -0
  169. package/core/built/admin/assets/table-B8LgTQJZ.js +1 -0
  170. package/core/built/admin/assets/tabs-D3ZOYkM7.js +1 -0
  171. package/core/built/admin/assets/tags-B4l891z2.js +1 -0
  172. package/core/built/admin/assets/text-DwtjwGkh.js +1 -0
  173. package/core/built/admin/assets/textarea-CTlb3Uu6.js +1 -0
  174. package/core/built/admin/assets/{tiers-EghDzCKc.js → tiers-BgYLWRJv.js} +1 -1
  175. package/core/built/admin/assets/toggle-group-DNXDkAwf.js +1 -0
  176. package/core/built/admin/assets/topic-filter-DZGjEcz3.js +1 -0
  177. package/core/built/admin/assets/{use-analytics-data-0l_OHtnR.js → use-analytics-data-CaT8RirX.js} +1 -1
  178. package/core/built/admin/assets/use-filter-params-DeQ8sX4N.js +1 -0
  179. package/core/built/admin/assets/use-growth-stats-9Db2CuJe.js +1 -0
  180. package/core/built/admin/assets/{use-post-referrers-DwI31Ril.js → use-post-referrers-BV54YcQS.js} +1 -1
  181. package/core/built/admin/assets/use-reply-chain-data-DuYZGDan.js +1 -0
  182. package/core/built/admin/assets/use-simple-pagination-8fTua9Nt.js +1 -0
  183. package/core/built/admin/assets/{use-tinybird-query-DvZBBMG7.js → use-tinybird-query-Dz156HvZ.js} +1 -1
  184. package/core/built/admin/assets/{use-tinybird-token-CQtebkvU.js → use-tinybird-token-C9RUdL_n.js} +1 -1
  185. package/core/built/admin/assets/{users-Pc8IRjk9.js → users-CcSCQFcQ.js} +1 -1
  186. package/core/built/admin/assets/virtual-list-BCvP0YF-.js +1 -0
  187. package/core/built/admin/assets/web-DTZnnUGr.js +1 -0
  188. package/core/built/admin/index.html +18 -22
  189. package/core/frontend/apps/private-blogging/index.js +1 -1
  190. package/core/frontend/apps/private-blogging/lib/middleware.js +1 -1
  191. package/core/frontend/helpers/split.js +2 -1
  192. package/core/frontend/meta/asset-url.js +1 -1
  193. package/core/frontend/meta/author-image.js +1 -1
  194. package/core/frontend/meta/blog-logo.js +1 -1
  195. package/core/frontend/meta/canonical-url.js +1 -1
  196. package/core/frontend/meta/cover-image.js +1 -1
  197. package/core/frontend/meta/get-meta.js +1 -1
  198. package/core/frontend/meta/og-image.js +1 -1
  199. package/core/frontend/meta/paginated-url.js +1 -1
  200. package/core/frontend/meta/twitter-image.js +1 -1
  201. package/core/frontend/meta/url.js +1 -1
  202. package/core/frontend/services/assets-minification/admin-auth-assets.js +1 -1
  203. package/core/frontend/services/llms/handler.js +1 -1
  204. package/core/frontend/services/proxy.js +31 -2
  205. package/core/frontend/services/routing/collection-router.js +1 -1
  206. package/core/frontend/services/routing/controllers/email-post.js +1 -1
  207. package/core/frontend/services/routing/controllers/entry/markdown.js +1 -1
  208. package/core/frontend/services/routing/controllers/entry/markdown.ts +1 -1
  209. package/core/frontend/services/routing/controllers/entry.js +1 -1
  210. package/core/frontend/services/routing/controllers/entry.ts +1 -1
  211. package/core/frontend/services/routing/controllers/previews.js +6 -7
  212. package/core/frontend/services/routing/controllers/unsubscribe.js +7 -3
  213. package/core/frontend/services/routing/email-router.js +1 -1
  214. package/core/frontend/services/routing/events.js +12 -0
  215. package/core/frontend/services/routing/middleware/page-param.js +1 -1
  216. package/core/frontend/services/routing/parent-router.js +1 -1
  217. package/core/frontend/services/routing/preview-router.js +1 -1
  218. package/core/frontend/services/routing/router-manager.js +4 -8
  219. package/core/frontend/services/routing/rss-router.js +1 -1
  220. package/core/frontend/services/routing/static-pages-router.js +1 -1
  221. package/core/frontend/services/routing/static-routes-router.js +1 -1
  222. package/core/frontend/services/routing/taxonomy-router.js +1 -1
  223. package/core/frontend/services/rss/generate-feed.js +1 -1
  224. package/core/frontend/services/sitemap/base-site-map-generator.js +23 -4
  225. package/core/frontend/services/sitemap/site-map-index-generator.js +1 -1
  226. package/core/frontend/services/sitemap/site-map-manager.js +14 -8
  227. package/core/frontend/services/sitemap/utils.js +1 -1
  228. package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +1 -1
  229. package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +1 -1
  230. package/core/frontend/utils/images.js +1 -1
  231. package/core/frontend/web/middleware/admin-toolbar.js +1 -1
  232. package/core/frontend/web/middleware/handle-image-sizes.js +2 -2
  233. package/core/frontend/web/middleware/redirect-ghost-to-admin.js +1 -1
  234. package/core/frontend/web/routers/serve-favicon.js +1 -1
  235. package/core/frontend/web/routers/serve-public-file.js +1 -1
  236. package/core/frontend/web/site.js +5 -5
  237. package/core/server/adapters/cache/AdapterCacheMemoryTTL.js +2 -2
  238. package/core/server/adapters/cache/MemoryCache.js +2 -2
  239. package/core/server/adapters/cache/Redis.js +1 -1
  240. package/core/server/adapters/cache/index.js +1 -1
  241. package/core/server/adapters/lib/redis/AdapterCacheRedis.js +2 -2
  242. package/core/server/adapters/route-settings/FileStore.js +2 -8
  243. package/core/server/adapters/route-settings/FileStore.ts +1 -6
  244. package/core/server/adapters/route-settings/S3RouteSettingsStore.js +206 -0
  245. package/core/server/adapters/route-settings/S3RouteSettingsStore.ts +199 -0
  246. package/core/server/adapters/route-settings/utils.js +13 -0
  247. package/core/server/adapters/route-settings/utils.ts +7 -0
  248. package/core/server/adapters/scheduling/deps.d.ts +0 -2
  249. package/core/server/adapters/scheduling/error-capture.js +76 -0
  250. package/core/server/adapters/scheduling/error-capture.ts +91 -0
  251. package/core/server/adapters/scheduling/utils.js +18 -34
  252. package/core/server/adapters/scheduling/utils.ts +36 -0
  253. package/core/server/adapters/storage/LocalFilesStorage.js +1 -1
  254. package/core/server/adapters/storage/LocalImagesStorage.js +1 -1
  255. package/core/server/adapters/storage/LocalMediaStorage.js +1 -1
  256. package/core/server/adapters/storage/LocalStorageBase.js +3 -3
  257. package/core/server/adapters/storage/S3Storage.js +2 -2
  258. package/core/server/adapters/storage/S3Storage.ts +1 -1
  259. package/core/server/adapters/storage/utils.js +1 -1
  260. package/core/server/api/endpoints/authentication.js +1 -1
  261. package/core/server/api/endpoints/featurebase.js +1 -1
  262. package/core/server/api/endpoints/files.js +2 -2
  263. package/core/server/api/endpoints/images.js +2 -2
  264. package/core/server/api/endpoints/libraries.d.ts +0 -1
  265. package/core/server/api/endpoints/media.js +8 -5
  266. package/core/server/api/endpoints/member-custom-fields.js +4 -1
  267. package/core/server/api/endpoints/member-custom-fields.ts +4 -1
  268. package/core/server/api/endpoints/posts.js +17 -1
  269. package/core/server/api/endpoints/search-index-public.js +4 -3
  270. package/core/server/api/endpoints/search-index.js +5 -4
  271. package/core/server/api/endpoints/settings-public.js +1 -1
  272. package/core/server/api/endpoints/settings.js +3 -1
  273. package/core/server/api/endpoints/utils/serializers/input/utils/url.js +9 -1
  274. package/core/server/api/endpoints/utils/serializers/output/default.js +7 -0
  275. package/core/server/api/endpoints/utils/serializers/output/files.js +1 -1
  276. package/core/server/api/endpoints/utils/serializers/output/media.js +1 -1
  277. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +7 -4
  278. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.ts +8 -4
  279. package/core/server/api/endpoints/utils/serializers/output/members.js +16 -26
  280. package/core/server/api/endpoints/utils/serializers/output/pages.js +7 -0
  281. package/core/server/api/endpoints/utils/serializers/output/posts.js +13 -0
  282. package/core/server/api/endpoints/utils/serializers/output/utils/url.js +1 -1
  283. package/core/server/api/endpoints/utils/validators/input/members.js +2 -52
  284. package/core/server/data/db/backup.js +1 -1
  285. package/core/server/data/importer/handlers/image.js +3 -3
  286. package/core/server/data/importer/import-manager.js +6 -4
  287. package/core/server/data/importer/importers/content-file-importer.js +2 -2
  288. package/core/server/data/migrations/utils/schema.js +4 -2
  289. package/core/server/data/migrations/versions/6.54/2026-07-19-16-59-00-add-content-import-permission.js +10 -0
  290. 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
  291. package/core/server/data/migrations/versions/6.54/2026-07-21-01-58-20-add-automation-run-steps-poller-index.js +3 -0
  292. 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
  293. package/core/server/data/migrations/versions/6.54/2026-07-22-10-41-08-add-click-tracking-to-automated-email-recipients.js +13 -0
  294. 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
  295. package/core/server/data/migrations/versions/6.54/2026-07-23-10-24-18-add-automation-action-revision-to-redirects.js +9 -0
  296. package/core/server/data/schema/commands.js +37 -3
  297. package/core/server/data/schema/fixtures/fixtures.json +7 -0
  298. package/core/server/data/schema/lib/default-index-name.js +20 -0
  299. package/core/server/data/schema/schema.js +40 -17
  300. package/core/server/data/seeders/data-generator.js +4 -2
  301. package/core/server/lib/image/image-size.js +5 -7
  302. package/core/server/lib/image/image-utils.js +2 -2
  303. package/core/server/lib/image/index.js +4 -4
  304. package/core/server/lib/lexical.js +3 -3
  305. package/core/server/lib/mobiledoc.js +2 -2
  306. package/core/server/lib/validate-password.js +1 -1
  307. package/core/server/models/action.js +9 -0
  308. package/core/server/models/base/plugins/generate-slug.js +1 -1
  309. package/core/server/models/collection.js +1 -1
  310. package/core/server/models/custom-theme-setting.js +1 -1
  311. package/core/server/models/member.js +73 -0
  312. package/core/server/models/newsletter.js +1 -1
  313. package/core/server/models/post.js +19 -5
  314. package/core/server/models/posts-meta.js +1 -1
  315. package/core/server/models/redirect.js +1 -1
  316. package/core/server/models/settings.js +1 -1
  317. package/core/server/models/snippet.js +1 -1
  318. package/core/server/models/tag.js +1 -1
  319. package/core/server/models/user.js +1 -1
  320. package/core/server/models/welcome-email-automated-email.js +1 -1
  321. package/core/server/services/activitypub/activity-pub-service-wrapper.js +1 -1
  322. package/core/server/services/adapter-manager/adapter-manager.js +5 -1
  323. package/core/server/services/adapter-manager/adapter-manager.ts +7 -2
  324. package/core/server/services/adapter-manager/index.js +18 -15
  325. package/core/server/services/adapter-manager/index.ts +23 -17
  326. package/core/server/services/adapter-manager/utils.js +124 -14
  327. package/core/server/services/adapter-manager/utils.ts +130 -14
  328. package/core/server/services/api-version-compatibility/mw-version-rewrites.js +1 -1
  329. package/core/server/services/audience-feedback/index.js +1 -1
  330. package/core/server/services/auth/passwordreset.js +1 -1
  331. package/core/server/services/auth/session/express-session.js +1 -1
  332. package/core/server/services/auth/session/index.js +2 -2
  333. package/core/server/services/auth/session/session-service.js +1 -1
  334. package/core/server/services/automations/automations-api.js +2 -19
  335. package/core/server/services/automations/automations-api.ts +2 -31
  336. package/core/server/services/automations/automations-repository.ts +15 -0
  337. package/core/server/services/automations/database-automations-repository.js +30 -2
  338. package/core/server/services/automations/database-automations-repository.ts +33 -2
  339. package/core/server/services/automations/poll.js +16 -12
  340. package/core/server/services/automations/poll.ts +17 -15
  341. package/core/server/services/automations/service.js +1 -1
  342. package/core/server/services/automations/service.ts +3 -13
  343. package/core/server/services/automations/welcome-email-automation-poll.js +2 -1
  344. package/core/server/services/comments/index.js +1 -1
  345. package/core/server/services/custom-redirects/index.js +2 -2
  346. package/core/server/services/email-analytics/email-analytics-service-wrapper.js +14 -13
  347. package/core/server/services/email-analytics/email-analytics-service.js +1 -1
  348. package/core/server/services/email-analytics/events/start-email-analytics-job-event.js +11 -15
  349. package/core/server/services/email-analytics/events/start-email-analytics-job-event.ts +15 -0
  350. package/core/server/services/email-analytics/index.js +2 -3
  351. package/core/server/services/email-analytics/index.ts +1 -2
  352. package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.js +1 -6
  353. package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.ts +0 -9
  354. package/core/server/services/email-analytics/jobs/fetch-latest/index.js +1 -1
  355. package/core/server/services/email-analytics/jobs/index.js +0 -2
  356. package/core/server/services/email-service/email-service-wrapper.js +1 -1
  357. package/core/server/services/email-service/email-service.js +20 -4
  358. package/core/server/services/explore-ping/explore-ping-service.js +24 -39
  359. package/core/server/services/explore-ping/explore-ping-service.ts +198 -0
  360. package/core/server/services/explore-ping/index.js +11 -11
  361. package/core/server/services/explore-ping/index.ts +42 -0
  362. package/core/server/services/gifts/gift-reminder-scheduler.js +1 -1
  363. package/core/server/services/gifts/gift-reminder-scheduler.ts +1 -1
  364. package/core/server/services/gifts/gift-service-wrapper.js +1 -1
  365. package/core/server/services/identity-tokens/identity-token-service-wrapper.js +1 -1
  366. package/core/server/services/indexnow-ping/constants.js +30 -0
  367. package/core/server/services/indexnow-ping/constants.ts +32 -0
  368. package/core/server/services/indexnow-ping/index.js +29 -253
  369. package/core/server/services/indexnow-ping/index.ts +37 -0
  370. package/core/server/services/indexnow-ping/indexnow-ping-service.js +229 -0
  371. package/core/server/services/indexnow-ping/indexnow-ping-service.ts +319 -0
  372. package/core/server/services/invites/index.js +1 -1
  373. package/core/server/services/lib/mailgun-client.js +3 -3
  374. package/core/server/services/link-redirection/index.js +2 -2
  375. package/core/server/services/link-redirection/link-redirect-repository.js +1 -1
  376. package/core/server/services/link-redirection/link-redirect.js +12 -13
  377. package/core/server/services/link-redirection/link-redirect.ts +22 -0
  378. package/core/server/services/link-redirection/link-redirects-service.js +1 -1
  379. package/core/server/services/link-tracking/full-post-link.js +2 -2
  380. package/core/server/services/link-tracking/index.js +1 -1
  381. package/core/server/services/mail/ghost-mailer.js +1 -1
  382. package/core/server/services/mail/index.js +1 -1
  383. package/core/server/services/media-inliner/external-media-inliner.js +2 -2
  384. package/core/server/services/media-inliner/service.js +4 -3
  385. package/core/server/services/member-attribution/index.js +1 -1
  386. package/core/server/services/member-welcome-emails/service.js +1 -1
  387. package/core/server/services/members/api.js +8 -2
  388. package/core/server/services/members/csv/index.js +10 -0
  389. package/core/server/services/members/csv/index.ts +3 -0
  390. package/core/server/services/members/csv/parse.js +94 -0
  391. package/core/server/services/members/csv/parse.ts +111 -0
  392. package/core/server/services/members/csv/types.js +2 -0
  393. package/core/server/services/members/csv/types.ts +39 -0
  394. package/core/server/services/members/csv/unparse.js +69 -0
  395. package/core/server/services/members/csv/unparse.ts +79 -0
  396. package/core/server/services/members/exporter/query.js +35 -8
  397. package/core/server/services/members/importer/config.js +35 -0
  398. package/core/server/services/members/importer/config.ts +39 -0
  399. package/core/server/services/members/importer/members-csv-importer.js +31 -13
  400. package/core/server/services/members/members-api/members-api.js +4 -2
  401. package/core/server/services/members/members-api/repositories/event-repository.js +13 -2
  402. package/core/server/services/members/members-api/services/member-bread-service.js +42 -19
  403. package/core/server/services/members/middleware.js +1 -1
  404. package/core/server/services/members/service.js +15 -2
  405. package/core/server/services/members/stripe-connect.js +1 -1
  406. package/core/server/services/members-custom-fields/actions.js +3 -0
  407. package/core/server/services/members-custom-fields/actions.ts +6 -2
  408. package/core/server/services/members-custom-fields/config.js +34 -0
  409. package/core/server/services/members-custom-fields/config.ts +38 -0
  410. package/core/server/services/members-custom-fields/definitions-service.js +156 -21
  411. package/core/server/services/members-custom-fields/definitions-service.ts +170 -25
  412. package/core/server/services/members-custom-fields/index.js +16 -3
  413. package/core/server/services/members-custom-fields/index.ts +17 -3
  414. package/core/server/services/members-custom-fields/values-service.js +56 -10
  415. package/core/server/services/members-custom-fields/values-service.ts +62 -10
  416. package/core/server/services/mentions/mention-sending-service.js +22 -2
  417. package/core/server/services/mentions/service.js +21 -5
  418. package/core/server/services/newsletters/index.js +1 -1
  419. package/core/server/services/oembed/oembed-service.js +122 -33
  420. package/core/server/services/oembed/service.js +4 -2
  421. package/core/server/services/offers/service.js +1 -1
  422. package/core/server/services/post-scheduling/index.js +4 -3
  423. package/core/server/services/post-scheduling/index.ts +4 -3
  424. package/core/server/services/post-scheduling/post-scheduling.js +1 -1
  425. package/core/server/services/post-scheduling/post-scheduling.ts +1 -1
  426. package/core/server/services/posts/post-email-handler.js +13 -6
  427. package/core/server/services/posts/post-scheduling.js +1 -1
  428. package/core/server/services/posts/posts-service-instance.js +1 -1
  429. package/core/server/services/posts/posts-service.js +2 -2
  430. package/core/server/services/posts-public/service.js +1 -1
  431. package/core/server/services/public-config/site.js +1 -1
  432. package/core/server/services/recommendations/recommendation-service-wrapper.js +1 -1
  433. package/core/server/services/recommendations/service/libraries.d.ts +0 -2
  434. package/core/server/services/route-settings/dynamic-routing-service.js +2 -3
  435. package/core/server/services/route-settings/index.js +1 -1
  436. package/core/server/services/route-settings/route-settings-parser.js +134 -124
  437. package/core/server/services/route-settings/route-settings-parser.ts +160 -125
  438. package/core/server/services/route-settings/validation-errors.js +178 -0
  439. package/core/server/services/route-settings/validation-errors.ts +196 -0
  440. package/core/server/services/settings/settings-service.js +2 -2
  441. package/core/server/services/settings-helpers/index.js +1 -1
  442. package/core/server/services/slack-notifications/service.js +1 -1
  443. package/core/server/services/slack-ping/constants.js +16 -0
  444. package/core/server/services/slack-ping/constants.ts +15 -0
  445. package/core/server/services/slack-ping/index.js +26 -204
  446. package/core/server/services/slack-ping/index.ts +35 -0
  447. package/core/server/services/slack-ping/slack-ping-service.js +214 -0
  448. package/core/server/services/slack-ping/slack-ping-service.ts +296 -0
  449. package/core/server/services/staff/index.js +1 -1
  450. package/core/server/services/stats/posts-stats-service.js +1 -1
  451. package/core/server/services/stats/service.js +1 -1
  452. package/core/server/services/stripe/service.js +1 -1
  453. package/core/server/services/tags-public/service.js +1 -1
  454. package/core/server/services/themes/validate.js +1 -1
  455. package/core/server/services/update-check/index.js +1 -1
  456. package/core/server/services/url/lazy-url-service.js +66 -6
  457. package/core/server/services/url/lazy-url-service.ts +73 -6
  458. package/core/server/services/url/url-generator.js +1 -1
  459. package/core/server/services/url/url-service-facade.js +68 -3
  460. package/core/server/services/url/url-service-facade.ts +79 -4
  461. package/core/server/services/url/url-service.js +1 -1
  462. package/core/server/services/url/urls.js +1 -1
  463. package/core/server/services/webhooks/index.js +19 -2
  464. package/core/server/services/webhooks/listen.js +6 -11
  465. package/core/server/services/webhooks/payload.js +1 -3
  466. package/core/server/services/webhooks/serialize.js +16 -1
  467. package/core/server/web/admin/app.js +1 -1
  468. package/core/server/web/admin/middleware/redirect-admin-urls.js +1 -1
  469. package/core/server/web/api/endpoints/admin/routes.js +1 -0
  470. package/core/server/web/api/middleware/cors.js +1 -1
  471. package/core/server/web/api/middleware/upload.js +4 -0
  472. package/core/server/web/gift-preview/controller.js +1 -1
  473. package/core/server/web/shared/middleware/redirect-amp-urls.js +1 -1
  474. package/core/server/web/shared/middleware/uncapitalise.js +2 -2
  475. package/core/server/web/shared/middleware/url-redirects.js +1 -1
  476. package/core/shared/config/defaults.json +8 -1
  477. package/core/shared/config/overrides.json +4 -0
  478. package/core/shared/url-utils.js +19 -15
  479. package/core/shared/url-utils.ts +20 -0
  480. package/ghost.js +0 -1
  481. package/package.json +26 -31
  482. package/pnpm-lock.yaml +681 -2789
  483. package/pnpm-workspace.yaml +31 -17
  484. package/components/tryghost-adapter-base-scheduling-0.0.0.tgz +0 -0
  485. package/components/tryghost-adapter-base-sso-0.0.0.tgz +0 -0
  486. package/core/built/admin/assets/Combination--5EZGaDs.js +0 -43
  487. package/core/built/admin/assets/Growth-C0NoKcHQ.js +0 -3
  488. package/core/built/admin/assets/Newsletters-Ed8kDjdy.js +0 -1
  489. package/core/built/admin/assets/Overview-CArPgRZt.js +0 -1
  490. package/core/built/admin/assets/Web-CjjYoVM3.js +0 -2
  491. package/core/built/admin/assets/account-migration-mfa5mNI9.js +0 -1
  492. package/core/built/admin/assets/activitypub/inbox-B3rjKMTv.js +0 -1221
  493. package/core/built/admin/assets/activitypub/layout-jcurg3rU.js +0 -1
  494. package/core/built/admin/assets/activitypub/use-activity-pub-queries-yqGRcnLn.js +0 -2569
  495. package/core/built/admin/assets/activitypub/users-CfyHIsTG.js +0 -1316
  496. package/core/built/admin/assets/automations-DkUnxNdv.js +0 -1
  497. package/core/built/admin/assets/automations-vjXofmV_.js +0 -1
  498. package/core/built/admin/assets/bluesky-sharing-T-pO3RcP.js +0 -1
  499. package/core/built/admin/assets/breadcrumb-CekPYTCn.js +0 -1
  500. package/core/built/admin/assets/button--i2uMDDn.js +0 -4
  501. package/core/built/admin/assets/card-CSWz_BXq.js +0 -1
  502. package/core/built/admin/assets/chart-helpers-C_4Ka_vT.js +0 -1
  503. package/core/built/admin/assets/chunk.524.8ce2c741473e2f0929dc.js +0 -25
  504. package/core/built/admin/assets/chunk.582.453459d6228d2955408b.js +0 -27
  505. package/core/built/admin/assets/code-editor-view-BfkwQto2.js +0 -1
  506. package/core/built/admin/assets/command-K75Jzs0G.js +0 -1
  507. package/core/built/admin/assets/comments-BEIi1DH-.js +0 -1
  508. package/core/built/admin/assets/container-BNXvlcjA.js +0 -1
  509. package/core/built/admin/assets/data-list-BmK5QMab.js +0 -1
  510. package/core/built/admin/assets/date-range-select-5sKzwbt7.js +0 -1
  511. package/core/built/admin/assets/disabled-sources-indicator-L_ssJTNr.js +0 -1
  512. package/core/built/admin/assets/dist-BBIJuyPg.js +0 -1
  513. package/core/built/admin/assets/dist-BHE0dp6o.js +0 -1
  514. package/core/built/admin/assets/dist-DJ6c4_De.js +0 -1
  515. package/core/built/admin/assets/dist-DW0QXQO3.js +0 -1
  516. package/core/built/admin/assets/dist-DxFLceO5.js +0 -1
  517. package/core/built/admin/assets/dist-QcACAOAD.js +0 -1
  518. package/core/built/admin/assets/dist-duxRDcQu.js +0 -177
  519. package/core/built/admin/assets/domain-CLaPZ9Rc.js +0 -1
  520. package/core/built/admin/assets/dropzone-E0bSX4_a.js +0 -5
  521. package/core/built/admin/assets/edit-profile-DqNPKaA4.js +0 -1
  522. package/core/built/admin/assets/editor-CkLXQDRp.js +0 -8
  523. package/core/built/admin/assets/empty-indicator-BTtOlgIo.js +0 -1
  524. package/core/built/admin/assets/esm-TSfGW7nz.js +0 -2
  525. package/core/built/admin/assets/explore-BEstLxKr.js +0 -1
  526. package/core/built/admin/assets/feed-C58p2voG.js +0 -1
  527. package/core/built/admin/assets/field-BSbDUHPv.js +0 -1
  528. package/core/built/admin/assets/filters-BgYv8Gt7.js +0 -1
  529. package/core/built/admin/assets/filters-DvenFkmK.js +0 -1
  530. package/core/built/admin/assets/framework-provider-jQktxm9P.js +0 -4
  531. package/core/built/admin/assets/ghost-dark-8590dea6cd695ff90f27d262c4464538.css +0 -1
  532. package/core/built/admin/assets/gift-link-modal-BPjXkEFt.js +0 -1
  533. package/core/built/admin/assets/growth-D4JNiVTe.js +0 -1
  534. package/core/built/admin/assets/hooks-Cjxexi_I.js +0 -2
  535. package/core/built/admin/assets/index-BacwlcOy.js +0 -67
  536. package/core/built/admin/assets/index-DxRNHH0o.css +0 -1
  537. package/core/built/admin/assets/inline-C22rnPro.js +0 -1
  538. package/core/built/admin/assets/input-group-CKfrILLP.js +0 -1
  539. package/core/built/admin/assets/jsx-runtime-CtMZ-PAS.js +0 -1
  540. package/core/built/admin/assets/kpi-card-DZxQKAIb.js +0 -1
  541. package/core/built/admin/assets/kpi-card-FidQ5zg3.js +0 -1
  542. package/core/built/admin/assets/kpi-helpers-C5T8Vaf1.js +0 -1
  543. package/core/built/admin/assets/kpi-tabs-_VRK6hGV.js +0 -1
  544. package/core/built/admin/assets/label-Cza7hPgn.js +0 -1
  545. package/core/built/admin/assets/label-picker-DgC_zLaw.js +0 -1
  546. package/core/built/admin/assets/layout-BxsXnKFX.js +0 -1
  547. package/core/built/admin/assets/limit-service-CTurluJQ.js +0 -20
  548. package/core/built/admin/assets/link-helpers-C3Gqy2cz.js +0 -1
  549. package/core/built/admin/assets/list-page-BtqCnow_.js +0 -1
  550. package/core/built/admin/assets/member-custom-fields-9uXFBqSt.js +0 -1
  551. package/core/built/admin/assets/member-detail-Dq6ZDIxo.js +0 -1
  552. package/core/built/admin/assets/members-CUWD9jal.js +0 -10
  553. package/core/built/admin/assets/modals-CIdwHVga.js +0 -31
  554. package/core/built/admin/assets/moderation-DTt04UDA.js +0 -1
  555. package/core/built/admin/assets/newsletter-cC8vcc9h.js +0 -1
  556. package/core/built/admin/assets/note-DZU0IY9e.js +0 -1
  557. package/core/built/admin/assets/notifications-NoHpBHJ4.js +0 -1
  558. package/core/built/admin/assets/nql-lang-CvCSOQG3.js +0 -19
  559. package/core/built/admin/assets/onboarding-route-Deg2hNm8.js +0 -1
  560. package/core/built/admin/assets/overview-BQPt_9w3.js +0 -1
  561. package/core/built/admin/assets/page-header-D6bEqPo2.js +0 -1
  562. package/core/built/admin/assets/post-analytics-header-BPw_B2_D.js +0 -1
  563. package/core/built/admin/assets/post-analytics-kp2_--XO.js +0 -1
  564. package/core/built/admin/assets/post-share-modal-Cave3Z4W.js +0 -1
  565. package/core/built/admin/assets/preferences-C7h3j_uy.js +0 -5
  566. package/core/built/admin/assets/profile-B2x4q2oB.js +0 -1
  567. package/core/built/admin/assets/router-provider-5fsX1CYn.js +0 -1
  568. package/core/built/admin/assets/select-PhPjIBBT.js +0 -1
  569. package/core/built/admin/assets/settings-D5P9Gwgo.js +0 -6
  570. package/core/built/admin/assets/settings-zUOzQV5I.js +0 -1
  571. package/core/built/admin/assets/share-modal-EfpfbuWF.js +0 -1
  572. package/core/built/admin/assets/social-urls-DgAF08Xc.js +0 -18
  573. package/core/built/admin/assets/sort-button-WOQYJm2H.js +0 -1
  574. package/core/built/admin/assets/source-icon-hm8Cj-Gx.js +0 -1
  575. package/core/built/admin/assets/stats-CnQDb62m.js +0 -1
  576. package/core/built/admin/assets/stats-view-CCfTJgSe.js +0 -1
  577. package/core/built/admin/assets/step-1-BGlhY4DS.js +0 -1
  578. package/core/built/admin/assets/step-2-D3sDEyFH.js +0 -1
  579. package/core/built/admin/assets/step-3-CvZoUdsc.js +0 -2
  580. package/core/built/admin/assets/switch-CNjkOmwz.js +0 -1
  581. package/core/built/admin/assets/table-C5nZYPnW.js +0 -1
  582. package/core/built/admin/assets/tabs-dtOcExye.js +0 -1
  583. package/core/built/admin/assets/tags-Dhm0FB_g.js +0 -1
  584. package/core/built/admin/assets/textarea-CeKw3wmV.js +0 -1
  585. package/core/built/admin/assets/toggle-group-DfhZIMTW.js +0 -1
  586. package/core/built/admin/assets/topic-filter-Cxe1Il41.js +0 -1
  587. package/core/built/admin/assets/typeof-Ca-duI-z.js +0 -1
  588. package/core/built/admin/assets/use-filter-params-Bub6BqNy.js +0 -1
  589. package/core/built/admin/assets/use-growth-stats-BJORomv0.js +0 -1
  590. package/core/built/admin/assets/use-reply-chain-data-B89YjVoo.js +0 -1
  591. package/core/built/admin/assets/use-simple-pagination-BL2SYXKi.js +0 -1
  592. package/core/built/admin/assets/virtual-list-DNJOSK9I.js +0 -1
  593. package/core/built/admin/assets/web-BHUE3YQc.js +0 -1
  594. package/core/server/adapters/scheduling/scheduling-base.js +0 -5
  595. package/core/server/adapters/sso/SSOBase.js +0 -5
  596. package/core/server/adapters/storage/index.js +0 -17
@@ -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,9 +17,9 @@ 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, request, 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;
@@ -248,8 +248,7 @@ class ImageSize {
248
248
  // get the storage readable filePath
249
249
  filePath = this.storageUtils.getLocalImagesStoragePath(imagePath);
250
250
 
251
- return this.storage.getStorage('images')
252
- .read({path: filePath})
251
+ return this.imageStore.read({path: filePath})
253
252
  .then((buf) => {
254
253
  debug('Image fetched (storage):', filePath);
255
254
  return this._imageSizeFromBuffer(buf);
@@ -298,10 +297,9 @@ class ImageSize {
298
297
  */
299
298
  async getOriginalImagePath(imagePath) {
300
299
  const {dir, name, ext} = path.parse(imagePath);
301
- const storageInstance = this.storage.getStorage('images');
302
300
 
303
301
  const preferredUnoptimizedImagePath = path.join(dir, `${name}_o${ext}`);
304
- const preferredUnoptimizedImagePathExists = await storageInstance.exists(preferredUnoptimizedImagePath);
302
+ const preferredUnoptimizedImagePathExists = await this.imageStore.exists(preferredUnoptimizedImagePath);
305
303
  if (preferredUnoptimizedImagePathExists) {
306
304
  return preferredUnoptimizedImagePath;
307
305
  }
@@ -315,7 +313,7 @@ class ImageSize {
315
313
  }
316
314
 
317
315
  const legacyOriginalImagePath = path.join(dir, `${imageName}_o${imageNumber || ''}${ext}`);
318
- const legacyOriginalImageExists = await storageInstance.exists(legacyOriginalImagePath);
316
+ const legacyOriginalImageExists = await this.imageStore.exists(legacyOriginalImagePath);
319
317
 
320
318
  return legacyOriginalImageExists ? legacyOriginalImagePath : imagePath;
321
319
  }
@@ -25,9 +25,9 @@ function probe(url, options = {}, {probeImageSize: probeImageSizeFn = probeImage
25
25
  }
26
26
 
27
27
  class ImageUtils {
28
- constructor({config, urlUtils, settingsCache, storageUtils, storage, validator, request, cacheStore}) {
28
+ constructor({config, urlUtils, settingsCache, storageUtils, imageStore, validator, request, cacheStore}) {
29
29
  this.blogIcon = new BlogIcon({config, urlUtils, settingsCache, storageUtils});
30
- this.imageSize = new ImageSize({config, storage, storageUtils, validator, urlUtils, request, probe});
30
+ this.imageSize = new ImageSize({config, imageStore, storageUtils, validator, urlUtils, request, probe});
31
31
  this.cachedImageSizeFromUrl = new CachedImageSizeFromUrl({
32
32
  getImageSizeFromUrl: this.imageSize.getImageSizeFromUrl.bind(this.imageSize),
33
33
  cache: cacheStore
@@ -1,22 +1,22 @@
1
1
  const request = require('@tryghost/request');
2
- const urlUtils = require('../../../shared/url-utils');
3
- const storage = require('../../adapters/storage');
2
+ const urlUtils = require('../../../shared/url-utils').default;
4
3
  const storageUtils = require('../../adapters/storage/utils');
5
4
  const validator = require('@tryghost/validator');
6
5
  const config = require('../../../shared/config');
7
6
  const settingsCache = require('../../../shared/settings-cache');
8
7
  const ImageUtils = require('./image-utils');
9
8
 
10
- const adapterManager = require('../../services/adapter-manager');
9
+ const adapterManager = require('../../services/adapter-manager').default;
11
10
 
12
11
  const cacheStore = adapterManager.getAdapter('cache:imageSizes');
12
+ const imageStore = adapterManager.getAdapter('storage:images');
13
13
 
14
14
  module.exports = new ImageUtils({
15
15
  config,
16
16
  urlUtils,
17
17
  settingsCache,
18
18
  storageUtils,
19
- storage,
19
+ imageStore,
20
20
  validator,
21
21
  request,
22
22
  cacheStore
@@ -1,10 +1,10 @@
1
1
  const path = require('path');
2
2
  const errors = require('@tryghost/errors');
3
- const urlUtils = require('../../shared/url-utils');
3
+ const urlUtils = require('../../shared/url-utils').default;
4
4
  const config = require('../../shared/config');
5
5
  const labs = require('../../shared/labs');
6
6
  const settingsCache = require('../../shared/settings-cache');
7
- const storage = require('../adapters/storage');
7
+ const adapterManager = require('../services/adapter-manager').default;
8
8
 
9
9
  let nodes;
10
10
  let lexicalHtmlRenderer;
@@ -50,7 +50,7 @@ function buildRenderOptions(userOptions) {
50
50
  // NOTE: the "saveRaw" check is smelly
51
51
  return imageTransform.canTransformFiles()
52
52
  && imageTransform.shouldResizeFileExtension(ext)
53
- && typeof storage.getStorage('images').saveRaw === 'function';
53
+ && typeof adapterManager.getAdapter('storage:images').saveRaw === 'function';
54
54
  },
55
55
  canTransformImageToFormat(format) {
56
56
  const imageTransform = require('@tryghost/image-transform');
@@ -1,6 +1,6 @@
1
1
  const path = require('path');
2
2
  const config = require('../../shared/config');
3
- const storage = require('../adapters/storage');
3
+ const adapterManager = require('../services/adapter-manager').default;
4
4
 
5
5
  let cardFactory;
6
6
  let cards;
@@ -37,7 +37,7 @@ module.exports = {
37
37
  // NOTE: the "saveRaw" check is smelly
38
38
  return imageTransform.canTransformFiles()
39
39
  && imageTransform.shouldResizeFileExtension(ext)
40
- && typeof storage.getStorage('images').saveRaw === 'function';
40
+ && typeof adapterManager.getAdapter('storage:images').saveRaw === 'function';
41
41
  }
42
42
  });
43
43
 
@@ -4,7 +4,7 @@ const validator = require('@tryghost/validator');
4
4
 
5
5
  const tpl = require('@tryghost/tpl');
6
6
  const settingsCache = require('../../shared/settings-cache');
7
- const urlUtils = require('../../shared/url-utils');
7
+ const urlUtils = require('../../shared/url-utils').default;
8
8
 
9
9
  const messages = {
10
10
  passwordDoesNotComplyLength: 'Your password must be at least {minLength} characters long.',
@@ -1,5 +1,12 @@
1
1
  const ghostBookshelf = require('./base');
2
2
 
3
+ // Member custom fields are owned by a raw-knex service rather than the Bookshelf
4
+ // registry. Actions still need a read model for `include=resource` to recognise
5
+ // their polymorphic resource type and load the current field definition.
6
+ const MemberCustomFieldResource = ghostBookshelf.Model.extend({
7
+ tableName: 'members_custom_fields'
8
+ });
9
+
3
10
  const Action = ghostBookshelf.Model.extend({
4
11
  tableName: 'actions',
5
12
 
@@ -18,6 +25,8 @@ const Action = ghostBookshelf.Model.extend({
18
25
  candidates.push([User, 'security_action']);
19
26
  }
20
27
 
28
+ candidates.push([MemberCustomFieldResource, 'member_custom_field']);
29
+
21
30
  return candidates;
22
31
  },
23
32
 
@@ -1,7 +1,7 @@
1
1
  const _ = require('lodash');
2
2
  const security = require('@tryghost/security');
3
3
 
4
- const urlUtils = require('../../../../shared/url-utils');
4
+ const urlUtils = require('../../../../shared/url-utils').default;
5
5
 
6
6
  /**
7
7
  * @type {Bookshelf} Bookshelf
@@ -1,5 +1,5 @@
1
1
  const ghostBookshelf = require('./base');
2
- const urlUtils = require('../../shared/url-utils');
2
+ const urlUtils = require('../../shared/url-utils').default;
3
3
 
4
4
  const Collection = ghostBookshelf.Model.extend({
5
5
  tableName: 'collections',
@@ -1,6 +1,6 @@
1
1
  const _ = require('lodash');
2
2
  const ghostBookshelf = require('./base');
3
- const urlUtils = require('../../shared/url-utils');
3
+ const urlUtils = require('../../shared/url-utils').default;
4
4
 
5
5
  const CustomThemeSetting = ghostBookshelf.Model.extend({
6
6
  tableName: 'custom_theme_settings',
@@ -4,6 +4,70 @@ const _ = require('lodash');
4
4
  const config = require('../../shared/config');
5
5
  const {MemberCommentingCodec} = require('../services/members/commenting');
6
6
 
7
+ const DEEP_OFFSET_THRESHOLD = 1000;
8
+
9
+ // The rewrite only applies to the plain single-table browse query. Joins,
10
+ // group by, unions etc. at the top level of the statement mean some other
11
+ // query shape — but the same keywords inside parens (NQL filters and search
12
+ // compile to `where members.id in (select ... join ...)`) are fine, so only
13
+ // depth-0 SQL is inspected. Bindings are `?` placeholders, so no user data
14
+ // appears in the inspected string.
15
+ function sqlOutsideParens(sql) {
16
+ let depth = 0;
17
+ let result = '';
18
+
19
+ for (const char of sql) {
20
+ if (char === '(') {
21
+ depth += 1;
22
+ } else if (char === ')') {
23
+ depth -= 1;
24
+ } else if (depth === 0) {
25
+ result += char;
26
+ }
27
+ }
28
+
29
+ return result;
30
+ }
31
+
32
+ // Deferred join for deep OFFSET pagination: plain LIMIT/OFFSET does a full
33
+ // row lookup for every discarded OFFSET row, so deep browse pages took ~10s
34
+ // on large sites. Instead, run LIMIT/OFFSET over a subquery selecting only
35
+ // the primary key (covered by the (created_at, id) index), then join back to
36
+ // fetch full rows for just the final page.
37
+ //
38
+ // The query is inspected via its compiled SQL (`qb.toSQL()`, public knex API)
39
+ // rather than knex's internal builder state. The prefix/suffix anchors below
40
+ // mean anything unexpected — custom selects, a lock clause, missing
41
+ // limit/offset — safely skips the rewrite.
42
+ function applyDeferredJoinForDeepOffset(qb) {
43
+ const {sql, bindings} = qb.toSQL();
44
+
45
+ // The plain browse query compiles to
46
+ // `select * from `members` [where ...] order by ... limit ? offset ?`;
47
+ // knex passes limit and offset as the last two bindings
48
+ if (!sql.startsWith('select * from `members`') || !sql.endsWith('limit ? offset ?')) {
49
+ return;
50
+ }
51
+
52
+ const offset = bindings[bindings.length - 1];
53
+
54
+ if (!Number.isInteger(offset) || offset < DEEP_OFFSET_THRESHOLD) {
55
+ return;
56
+ }
57
+
58
+ const topLevelSql = sqlOutsideParens(sql);
59
+ if ([' join ', ' group by ', ' having ', ' union '].some(keyword => topLevelSql.includes(keyword))) {
60
+ return;
61
+ }
62
+
63
+ // Aliased so the default raw browse order (`created_at DESC, id DESC`)
64
+ // stays unambiguous in the outer query
65
+ const idSubquery = qb.clone().select('members.id as deep_page_id');
66
+
67
+ qb.clear('where').clear('limit').clear('offset')
68
+ .innerJoin(idSubquery.as('deep_page'), 'members.id', 'deep_page.deep_page_id');
69
+ }
70
+
7
71
  const Member = ghostBookshelf.Model.extend({
8
72
  tableName: 'members',
9
73
 
@@ -357,6 +421,15 @@ const Member = ghostBookshelf.Model.extend({
357
421
  return result;
358
422
  },
359
423
 
424
+ // Fires with the fully-built knex query (filters/order/limit/offset
425
+ // applied, select columns not yet); the count query runs before this
426
+ // event, so pagination meta is unaffected by the rewrite
427
+ onFetchingCollection: function onFetchingCollection(collection, columns, options) {
428
+ ghostBookshelf.Model.prototype.onFetchingCollection.apply(this, arguments);
429
+
430
+ applyDeferredJoinForDeepOffset(options.query);
431
+ },
432
+
360
433
  onDestroyed: function onDestroyed(model, options) {
361
434
  const result = ghostBookshelf.Model.prototype.onDestroyed.apply(this, arguments);
362
435
 
@@ -1,7 +1,7 @@
1
1
  const ghostBookshelf = require('./base');
2
2
  const ObjectID = require('bson-objectid').default;
3
3
  const crypto = require('crypto');
4
- const urlUtils = require('../../shared/url-utils');
4
+ const urlUtils = require('../../shared/url-utils').default;
5
5
 
6
6
  const Newsletter = ghostBookshelf.Model.extend({
7
7
  tableName: 'newsletters',
@@ -14,7 +14,7 @@ const limitService = require('../services/limits');
14
14
  const mobiledocLib = require('../lib/mobiledoc');
15
15
  const lexicalLib = require('../lib/lexical');
16
16
  const relations = require('./relations');
17
- const urlUtils = require('../../shared/url-utils');
17
+ const urlUtils = require('../../shared/url-utils').default;
18
18
  const {Tag} = require('./tag');
19
19
  const {Newsletter} = require('./newsletter');
20
20
  const {BadRequestError} = require('@tryghost/errors');
@@ -950,15 +950,29 @@ Post = ghostBookshelf.Model.extend({
950
950
  },
951
951
 
952
952
  authors: function authors() {
953
+ // posts_authors.id breaks sort_order ties deterministically (by attach
954
+ // order); without it MySQL can order tied rows differently per query,
955
+ // which changes the computed primary_author. See tags() below.
956
+ // `id` is pivoted in so it is in the SELECT list — the query uses
957
+ // DISTINCT, which requires ORDER BY columns to be selected.
953
958
  return this.belongsToMany('User', 'posts_authors', 'post_id', 'author_id')
954
- .withPivot('sort_order')
955
- .query('orderBy', 'sort_order', 'ASC');
959
+ .withPivot(['sort_order', 'id'])
960
+ .query('orderBy', 'sort_order', 'ASC')
961
+ .query('orderBy', 'posts_authors.id', 'ASC');
956
962
  },
957
963
 
958
964
  tags: function tags() {
965
+ // posts_tags.id breaks sort_order ties deterministically (by attach
966
+ // order). primary_tag is tags[0]-if-public, so a non-deterministic tie
967
+ // order (which MySQL produces for tags sharing a sort_order) makes the
968
+ // primary tag — and the post's URL under a {primary_tag} permalink —
969
+ // depend on the query shape.
970
+ // `id` is pivoted in so it is in the SELECT list — the query uses
971
+ // DISTINCT, which requires ORDER BY columns to be selected.
959
972
  return this.belongsToMany('Tag', 'posts_tags', 'post_id', 'tag_id')
960
- .withPivot('sort_order')
961
- .query('orderBy', 'sort_order', 'ASC');
973
+ .withPivot(['sort_order', 'id'])
974
+ .query('orderBy', 'sort_order', 'ASC')
975
+ .query('orderBy', 'posts_tags.id', 'ASC');
962
976
  },
963
977
 
964
978
  mobiledoc_revisions() {
@@ -1,5 +1,5 @@
1
1
  const ghostBookshelf = require('./base');
2
- const urlUtils = require('../../shared/url-utils');
2
+ const urlUtils = require('../../shared/url-utils').default;
3
3
 
4
4
  const PostsMeta = ghostBookshelf.Model.extend({
5
5
  tableName: 'posts_meta',
@@ -1,5 +1,5 @@
1
1
  const ghostBookshelf = require('./base');
2
- const urlUtils = require('../../shared/url-utils');
2
+ const urlUtils = require('../../shared/url-utils').default;
3
3
 
4
4
  const Redirect = ghostBookshelf.Model.extend({
5
5
  tableName: 'redirects',
@@ -6,7 +6,7 @@ const ghostBookshelf = require('./base');
6
6
  const tpl = require('@tryghost/tpl');
7
7
  const errors = require('@tryghost/errors');
8
8
  const validator = require('@tryghost/validator');
9
- const urlUtils = require('../../shared/url-utils');
9
+ const urlUtils = require('../../shared/url-utils').default;
10
10
  const {WRITABLE_KEYS_ALLOWLIST} = require('../../shared/labs');
11
11
  const {getOrGenerateSiteUuid} = require('../services/settings/settings-utils');
12
12
 
@@ -1,5 +1,5 @@
1
1
  const ghostBookshelf = require('./base');
2
- const urlUtils = require('../../shared/url-utils');
2
+ const urlUtils = require('../../shared/url-utils').default;
3
3
  const mobiledocLib = require('../lib/mobiledoc');
4
4
  const lexicalLib = require('../lib/lexical');
5
5
  const _ = require('lodash');
@@ -1,7 +1,7 @@
1
1
  const ghostBookshelf = require('./base');
2
2
  const tpl = require('@tryghost/tpl');
3
3
  const errors = require('@tryghost/errors');
4
- const urlUtils = require('../../shared/url-utils');
4
+ const urlUtils = require('../../shared/url-utils').default;
5
5
 
6
6
  const messages = {
7
7
  tagNotFound: 'Tag not found.'
@@ -9,7 +9,7 @@ const security = require('@tryghost/security');
9
9
  const {pipeline} = require('@tryghost/promise');
10
10
  const validatePassword = require('../lib/validate-password');
11
11
  const permissions = require('../services/permissions');
12
- const urlUtils = require('../../shared/url-utils');
12
+ const urlUtils = require('../../shared/url-utils').default;
13
13
  const {setIsRoles} = require('./role-utils');
14
14
  const activeStates = ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4'];
15
15
  const ASSIGNABLE_ROLES = ['Administrator', 'Super Editor', 'Editor', 'Author', 'Contributor'];
@@ -1,6 +1,6 @@
1
1
  const ghostBookshelf = require('./base');
2
2
  const errors = require('@tryghost/errors');
3
- const urlUtils = require('../../shared/url-utils');
3
+ const urlUtils = require('../../shared/url-utils').default;
4
4
  const lexicalLib = require('../lib/lexical');
5
5
  const {DEFAULT_EMAIL_DESIGN_SETTING_SLUG} = require('../services/member-welcome-emails/constants');
6
6
 
@@ -14,7 +14,7 @@ module.exports = class ActivityPubServiceWrapper {
14
14
  const logging = require('@tryghost/logging');
15
15
  const events = require('../../lib/common/events');
16
16
  const {knex} = require('../../data/db');
17
- const urlUtils = require('../../../shared/url-utils');
17
+ const urlUtils = require('../../../shared/url-utils').default;
18
18
  const IdentityTokenServiceWrapper = require('../identity-tokens');
19
19
  const settingsCache = require('../../../shared/settings-cache');
20
20