ghost 6.47.0 → 6.48.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 (372) hide show
  1. package/MigratorConfig.js +0 -1
  2. package/bin/create-migration.js +1 -1
  3. package/bin/generate-golden-email.js +0 -1
  4. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  5. package/core/boot.js +13 -7
  6. package/core/built/admin/assets/{PolarAngleAxis-CLluELUg.js → PolarAngleAxis-DufzOBEz.js} +1 -1
  7. package/core/built/admin/assets/{_baseAssignValue-Dz1iqdwD.js → _baseAssignValue-BjUm4QeA.js} +1 -1
  8. package/core/built/admin/assets/{a-large-small-BA74vHPp.js → a-large-small-D0RF_WS9.js} +1 -1
  9. package/core/built/admin/assets/{account-migration-B-NqdKuN.js → account-migration-B7n6ezrZ.js} +1 -1
  10. package/core/built/admin/assets/activitypub/{account-migration-ClmVrAXr.js → account-migration-BJeRnMCl.js} +3 -3
  11. package/core/built/admin/assets/activitypub/activitypub.js +1 -1
  12. package/core/built/admin/assets/activitypub/{at-sign-9F3qd4Nn.js → at-sign-BygVOKdj.js} +2 -2
  13. package/core/built/admin/assets/activitypub/{avatar-flipboard-jBHA13Ej.js → avatar-flipboard-CNcjI8lK.js} +2 -2
  14. package/core/built/admin/assets/activitypub/{bluesky-sharing-1irhvVtF.js → bluesky-sharing-mgBNeRfA.js} +4 -4
  15. package/core/built/admin/assets/activitypub/{copy-DXRvsGiK.js → copy-BMChXIQc.js} +2 -2
  16. package/core/built/admin/assets/activitypub/{deleted-feed-item-67VQJde4.js → deleted-feed-item-D-spb6V1.js} +2 -2
  17. package/core/built/admin/assets/activitypub/{edit-profile-BfpbEj98.js → edit-profile-CDQ3V8-c.js} +4 -4
  18. package/core/built/admin/assets/activitypub/{feed-DUrI7SPC.js → feed-Vqr3WU-V.js} +4 -4
  19. package/core/built/admin/assets/activitypub/{hash-CMtB10PN.js → hash-D7SSXVOg.js} +2 -2
  20. package/core/built/admin/assets/activitypub/{inbox-2xq8SJ7A.js → inbox-BHk5Dw27.js} +2 -2
  21. package/core/built/admin/assets/activitypub/{index-BT97xLpd.js → index-BejkeH-m.js} +2 -2
  22. package/core/built/admin/assets/activitypub/{index-DssHQAjK.js → index-BqL23J-m.js} +32 -32
  23. package/core/built/admin/assets/activitypub/{index-Ba6FXt8y.js → index-CHhvjNuG.js} +6 -6
  24. package/core/built/admin/assets/activitypub/{index-ERtz4Bvy.js → index-CZsNO9hA.js} +5 -5
  25. package/core/built/admin/assets/activitypub/{index-sgY7lLrg.js → index-CaIhRYzz.js} +3 -3
  26. package/core/built/admin/assets/activitypub/{index-D1EWoXrK.js → index-DA2MkQVu.js} +2 -2
  27. package/core/built/admin/assets/activitypub/{index-sudOvKcY.js → index-DHhFcmfu.js} +21 -21
  28. package/core/built/admin/assets/activitypub/{index-Ccighz1t.js → index-sh2bDSls.js} +4 -4
  29. package/core/built/admin/assets/activitypub/{label-KQSsSjmN.js → label-D80yhOIm.js} +2 -2
  30. package/core/built/admin/assets/activitypub/{moderation-B78if-r0.js → moderation-LJNmKBCi.js} +3 -3
  31. package/core/built/admin/assets/activitypub/{note-Bfr7ovn7.js → note-CyjKLcQ-.js} +4 -4
  32. package/core/built/admin/assets/activitypub/{reply-CehesW8Z.js → reply-BiiCFx7G.js} +2 -2
  33. package/core/built/admin/assets/activitypub/{separator-B_Ly_Qq8.js → separator-CY3PMmtI.js} +2 -2
  34. package/core/built/admin/assets/activitypub/{settings-D6R97p7v.js → settings-BQy6Gr7R.js} +3 -3
  35. package/core/built/admin/assets/activitypub/{step-1-Cl1YxgZ1.js → step-1-DCqRwgf3.js} +3 -3
  36. package/core/built/admin/assets/activitypub/{step-2-DDyR--Qe.js → step-2-DQlhehTO.js} +5 -5
  37. package/core/built/admin/assets/activitypub/{step-3-Don8gv0n.js → step-3-DAUCAcxW.js} +7 -7
  38. package/core/built/admin/assets/activitypub/{tabs-DTpfm-wu.js → tabs-B_6UuI7r.js} +3 -3
  39. package/core/built/admin/assets/activitypub/{topic-filter-Oee10885.js → topic-filter--FT1A_dc.js} +2 -2
  40. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
  41. package/core/built/admin/assets/admin-x-settings/{code-editor-view-CGZuiDGx.js → code-editor-view-Bp_sCJR0.js} +2 -2
  42. package/core/built/admin/assets/admin-x-settings/{index-CwEblQZC.js → index-BPXA3pTW.js} +5 -5
  43. package/core/built/admin/assets/admin-x-settings/{index-rr_UntGE.js → index-BS375mg1.js} +3 -3
  44. package/core/built/admin/assets/admin-x-settings/{index-BpM6W2br.js → index-B_PlQoEG.js} +3 -3
  45. package/core/built/admin/assets/admin-x-settings/{index-BGdS5xw4.js → index-BflhAbu2.js} +3 -3
  46. package/core/built/admin/assets/admin-x-settings/{index-DtWUeJhp.js → index-CftMe8fe.js} +3 -3
  47. package/core/built/admin/assets/admin-x-settings/{index-B65inCwj.js → index-DRB7FH6y.js} +2 -2
  48. package/core/built/admin/assets/admin-x-settings/{index-DSX261S9.js → index-DijZ3oAM.js} +2 -2
  49. package/core/built/admin/assets/admin-x-settings/{index-DF6YEs01.js → index-cV0Lof9H.js} +1526 -1500
  50. package/core/built/admin/assets/admin-x-settings/{index-CluZYkUC.js → index-qc4x3vZj.js} +3 -3
  51. package/core/built/admin/assets/admin-x-settings/{modals-Bf4KOU31.js → modals-CkjuEByw.js} +55 -67
  52. package/core/built/admin/assets/{arrow-right-BxP3aeA5.js → arrow-right-BF77Yx73.js} +1 -1
  53. package/core/built/admin/assets/{at-sign-Bf0y-jim.js → at-sign-DhJF3n_V.js} +1 -1
  54. package/core/built/admin/assets/{audience-DHR1WgFK.js → audience-DHPKKayV.js} +1 -1
  55. package/core/built/admin/assets/{automated-emails-DbJbDLib.js → automated-emails-DInKYTEC.js} +1 -1
  56. package/core/built/admin/assets/{automations-aLgTzSsZ.js → automations-DJpeZw9T.js} +1 -1
  57. package/core/built/admin/assets/automations-DpQKN9j0.js +1 -0
  58. package/core/built/admin/assets/{avatar-flipboard-B0F2LMW5.js → avatar-flipboard-yRdmFC6R.js} +1 -1
  59. package/core/built/admin/assets/{bluesky-sharing-DjhtIuyr.js → bluesky-sharing-qSiCERoR.js} +1 -1
  60. package/core/built/admin/assets/{chart-BGwxlD0z.js → chart-CP2N9ZC-.js} +1 -1
  61. package/core/built/admin/assets/{chevron-up-C2FeVzre.js → chevron-up-BQ6fOpFR.js} +1 -1
  62. package/core/built/admin/assets/{chunk.524.31b31f7958dfae110016.js → chunk.524.ad4560630d4d62fbceb5.js} +4 -4
  63. package/core/built/admin/assets/{chunk.582.a855020953886af6e83b.js → chunk.582.fd4878e4e0af31ef86c0.js} +6 -6
  64. package/core/built/admin/assets/{chunk.972.258e6b1dab79b2189f1c.js → chunk.98.69968e0f393d82c2949c.js} +4 -4
  65. package/core/built/admin/assets/{code-editor-view-DzPkm_nJ.js → code-editor-view-CVODiRVJ.js} +1 -1
  66. package/core/built/admin/assets/{comments-DgItXUWN.js → comments-CP-NxopD.js} +1 -1
  67. package/core/built/admin/assets/{content-helpers-BNefU_PE.js → content-helpers-Crzkusiq.js} +1 -1
  68. package/core/built/admin/assets/{copy-DoNNUZlb.js → copy-r1LFsU75.js} +1 -1
  69. package/core/built/admin/assets/{data-list-CO1cZQRU.js → data-list-CzSc7z-2.js} +1 -1
  70. package/core/built/admin/assets/{deleted-feed-item-DC2wSAhv.js → deleted-feed-item-PyEM8FiX.js} +1 -1
  71. package/core/built/admin/assets/{dropzone-BTODLafn.js → dropzone-DI8A9qO6.js} +1 -1
  72. package/core/built/admin/assets/{edit-profile-BMMpmWIZ.js → edit-profile-DlJ64lV7.js} +1 -1
  73. package/core/built/admin/assets/editor-CevNZicQ.js +8 -0
  74. package/core/built/admin/assets/{empty-indicator-Dza0FQlj.js → empty-indicator-Dxg05yWg.js} +1 -1
  75. package/core/built/admin/assets/{en-yf9qAqTu.js → en-D93GVp3o.js} +1 -1
  76. package/core/built/admin/assets/{eye-CAqnnfQF.js → eye-6POPPpTw.js} +1 -1
  77. package/core/built/admin/assets/{feed-BkNsbWiF.js → feed-P_RMYb5x.js} +1 -1
  78. package/core/built/admin/assets/{field-Ddb1ZOqM.js → field-DeNjwWrL.js} +1 -1
  79. package/core/built/admin/assets/{filter-query-core-5Mac92kh.js → filter-query-core-DFs5WSmA.js} +1 -1
  80. package/core/built/admin/assets/{filters-BCb4bgtg.js → filters-C_BSQgb7.js} +1 -1
  81. package/core/built/admin/assets/{gh-chart-C6zkIg8k.js → gh-chart-pNHAbeQn.js} +1 -1
  82. package/core/built/admin/assets/{ghost-5313258fd425ced5db6516acde01ba36.js → ghost-3f5b3569e0beec61266cb74077677fbc.js} +3 -3
  83. package/core/built/admin/assets/{growth-ezUlN8OE.js → growth-B83tVOYO.js} +1 -1
  84. package/core/built/admin/assets/{hash-DE2OmChI.js → hash-BCTATV5W.js} +1 -1
  85. package/core/built/admin/assets/{inbox-OthiHvlV.js → inbox-rE3c5suT.js} +1 -1
  86. package/core/built/admin/assets/{index-BLyzLfyx.js → index-7EiRc5Ay.js} +1 -1
  87. package/core/built/admin/assets/{index-CV5v0eFE.js → index-B5bpZGTI.js} +1 -1
  88. package/core/built/admin/assets/index-BNtzAd7H.css +1 -0
  89. package/core/built/admin/assets/{index-BC1yWeaJ.js → index-BT33w2Io.js} +1 -1
  90. package/core/built/admin/assets/{index-DjffQ3VJ.js → index-BbkXWdhb.js} +1 -1
  91. package/core/built/admin/assets/{index-DH6PA3W6.js → index-BfhSrnrJ.js} +1 -1
  92. package/core/built/admin/assets/{index-CRvK0Iac.js → index-BmR_OUpb.js} +1 -1
  93. package/core/built/admin/assets/{index-CNV7fxKZ.js → index-BuhMgn5c.js} +1 -1
  94. package/core/built/admin/assets/{index-pkixJbdq.js → index-C-075SzJ.js} +34 -34
  95. package/core/built/admin/assets/{index-DJoByVS8.js → index-CB3hJd9E.js} +1 -1
  96. package/core/built/admin/assets/{index-D3bb-MEJ.js → index-CCISLIQd.js} +1 -1
  97. package/core/built/admin/assets/{index-BIEhcKiV.js → index-Cnptpx11.js} +1 -1
  98. package/core/built/admin/assets/{index-DK1cu59e.js → index-CrBRU81r.js} +1 -1
  99. package/core/built/admin/assets/{index-B0_p1-R0.js → index-CscUHFJp.js} +1 -1
  100. package/core/built/admin/assets/{index-Bi5qzf86.js → index-D3ZzfuJt.js} +1 -1
  101. package/core/built/admin/assets/{index-CKPny_6u.js → index-D4wn-U0V.js} +1 -1
  102. package/core/built/admin/assets/{index-YzcsD17L.js → index-DNRlkUeu.js} +1 -1
  103. package/core/built/admin/assets/{index-BoMsDCxD.js → index-D_G6negZ.js} +1 -1
  104. package/core/built/admin/assets/{index-CwsmINtV.js → index-DfxHSK1s.js} +1 -1
  105. package/core/built/admin/assets/{index-X91I8PcS.js → index-Dpc3COTl.js} +1 -1
  106. package/core/built/admin/assets/{index-c1h-EQpd.js → index-UsbnU2jy.js} +1 -1
  107. package/core/built/admin/assets/{index-oKgNVmwC.js → index-VfrJzh5m.js} +1 -1
  108. package/core/built/admin/assets/{index-D5MrQBSe.js → index-fbxc8Dpt.js} +1 -1
  109. package/core/built/admin/assets/{input-group-BOLMrDfJ.js → input-group-BLygwiDK.js} +1 -1
  110. package/core/built/admin/assets/{koenig-lexical-DlzcWUPw.js → koenig-lexical-B9U3sBS5.js} +1 -1
  111. package/core/built/admin/assets/{kpi-card-BlF7JKRC.js → kpi-card-Bmnvvp4X.js} +1 -1
  112. package/core/built/admin/assets/{kpi-card-HDshm3lO.js → kpi-card-CGVtzdgJ.js} +1 -1
  113. package/core/built/admin/assets/{kpi-tabs-Dty6zMSP.js → kpi-tabs-DxbvMkIU.js} +1 -1
  114. package/core/built/admin/assets/{kpis-CFz4r5wW.js → kpis-CQBAGVjP.js} +1 -1
  115. package/core/built/admin/assets/{label-CVzNcbjb.js → label-DpTwHQi_.js} +1 -1
  116. package/core/built/admin/assets/{links-D9dHwDlP.js → links-Bdw25FJF.js} +1 -1
  117. package/core/built/admin/assets/{list-page-shoQED7N.js → list-page-BvTQwP5F.js} +1 -1
  118. package/core/built/admin/assets/{loader-circle-cad701gH.js → loader-circle-3HJkQKWf.js} +1 -1
  119. package/core/built/admin/assets/{mail-DG4PKpZy.js → mail-DvrqP73n.js} +1 -1
  120. package/core/built/admin/assets/{main-layout-BmFla3Se.js → main-layout-BAPpm0bz.js} +1 -1
  121. package/core/built/admin/assets/{members-d19Z6k1C.js → members-CF4CzJSf.js} +1 -1
  122. package/core/built/admin/assets/minus-DJIePlnU.js +1 -0
  123. package/core/built/admin/assets/modals-CVsVi0zu.js +35 -0
  124. package/core/built/admin/assets/{moderation-BWBLnh4h.js → moderation-BX1KH5QL.js} +1 -1
  125. package/core/built/admin/assets/{newsletter-DNY4MroI.js → newsletter-BlKeb58e.js} +1 -1
  126. package/core/built/admin/assets/{newsletters-B10iBPP-.js → newsletters-3In8H0Z5.js} +1 -1
  127. package/core/built/admin/assets/{note-S0b6wjRR.js → note-ybwJCAxm.js} +1 -1
  128. package/core/built/admin/assets/{offers-B-9mZqKd.js → offers-Cl0ZNEMr.js} +1 -1
  129. package/core/built/admin/assets/{onboarding-route-AMFn0X5G.js → onboarding-route-A3ECeMAi.js} +1 -1
  130. package/core/built/admin/assets/{overview-WKadyZRW.js → overview-DrMrfsk-.js} +1 -1
  131. package/core/built/admin/assets/{pagemenu-BofQcFaF.js → pagemenu-O7HbsehH.js} +1 -1
  132. package/core/built/admin/assets/{pencil-LfMcD0vS.js → pencil-CknTbJeE.js} +1 -1
  133. package/core/built/admin/assets/{pin-CayUjL8e.js → pin-BNs-JdQ3.js} +1 -1
  134. package/core/built/admin/assets/{post-analytics-DMHvt3Jl.js → post-analytics-Dk1VloZp.js} +1 -1
  135. package/core/built/admin/assets/{post-analytics-context-10cqioP1.js → post-analytics-context-kPL94Ivz.js} +1 -1
  136. package/core/built/admin/assets/{post-analytics-header-DlICE18K.js → post-analytics-header-CpMOozq-.js} +1 -1
  137. package/core/built/admin/assets/{post-share-modal-Cfwy2UwD.js → post-share-modal-F0dobdhF.js} +1 -1
  138. package/core/built/admin/assets/posts/{alert-dialog-cQK32v9G.js → alert-dialog-NoPLULhG.js} +5 -5
  139. package/core/built/admin/assets/posts/{app-utils-DQ2hixop.js → app-utils-BiM9QO4L.js} +3 -3
  140. package/core/built/admin/assets/posts/{automations-BqkU9-zY.js → automations-BgIAmq9f.js} +3 -3
  141. package/core/built/admin/assets/posts/{automations-CoilKpVH.js → automations-D_XwO405.js} +30 -30
  142. package/core/built/admin/assets/posts/{avatar-BejAO6Rj.js → avatar-BYsYOpmq.js} +5 -5
  143. package/core/built/admin/assets/posts/{badge-BYGRyd2f.js → badge-B54vLono.js} +2 -2
  144. package/core/built/admin/assets/posts/{button-CG2Dpjqy.js → button-DMLfwOQt.js} +3 -3
  145. package/core/built/admin/assets/posts/{check-fsC5BvGC.js → check-D6qDi62T.js} +2 -2
  146. package/core/built/admin/assets/posts/{comments-CsyF5C1S.js → comments-CyYCbvUG.js} +26 -26
  147. package/core/built/admin/assets/posts/{data-list-JslRF2F5.js → data-list-B0DrMm-x.js} +4 -4
  148. package/core/built/admin/assets/posts/{dialog-3KY3A8t5.js → dialog-DtEZpY1q.js} +3 -3
  149. package/core/built/admin/assets/posts/{editor-3HPW_xW4.js → editor-LJHLmUoW.js} +1943 -1943
  150. package/core/built/admin/assets/posts/{ellipsis-BhK5S70U.js → ellipsis-JeIF0Biz.js} +2 -2
  151. package/core/built/admin/assets/posts/{empty-indicator-C9DbE9wZ.js → empty-indicator-dktzN32y.js} +2 -2
  152. package/core/built/admin/assets/posts/{filters-BCBDCnQF.js → filters-D1L-LU_m.js} +10 -10
  153. package/core/built/admin/assets/posts/{get-site-timezone-83C41MGz.js → get-site-timezone-dsyl8nlB.js} +3 -3
  154. package/core/built/admin/assets/posts/{growth-COoL1kMe.js → growth-yX8UB_ce.js} +12 -12
  155. package/core/built/admin/assets/posts/{heading-D3VqNO3z.js → heading-CNte43wH.js} +2 -2
  156. package/core/built/admin/assets/posts/{hooks-5YpJYWOw.js → hooks-BIgv7QBp.js} +2 -2
  157. package/core/built/admin/assets/posts/{index-Dqn5WIFh.js → index-2FO6Vy0r.js} +11 -11
  158. package/core/built/admin/assets/posts/{input-C1qcZBGw.js → input-BycmlCp8.js} +3 -3
  159. package/core/built/admin/assets/posts/{input-surface-C4vUAdbV.js → input-surface-vY3ACaso.js} +2 -2
  160. package/core/built/admin/assets/posts/{koenig-lexical-NZjxFY0X.js → koenig-lexical-Cq8SUcZC.js} +2 -2
  161. package/core/built/admin/assets/posts/{kpis-C2FEXoUT.js → kpis-CAJcU1w0.js} +27 -27
  162. package/core/built/admin/assets/posts/{label-CmJzmJY7.js → label-BmLTflMF.js} +3 -3
  163. package/core/built/admin/assets/posts/{links-nzud7t_t.js → links-BVcmMZmF.js} +4 -4
  164. package/core/built/admin/assets/posts/{list-page-D_rv4TgN.js → list-page-DX2WRn5T.js} +4 -4
  165. package/core/built/admin/assets/posts/{loading-indicator-DAOD6O2b.js → loading-indicator-C6FD4nS6.js} +3 -3
  166. package/core/built/admin/assets/posts/{mail-CtH0gTpq.js → mail-BMyoNUVM.js} +2 -2
  167. package/core/built/admin/assets/posts/{main-layout-VqvCxOXQ.js → main-layout-ClnxdW1Y.js} +2 -2
  168. package/core/built/admin/assets/posts/{message-circle-D4bCjxKS.js → message-circle-DwfHX-p1.js} +2 -2
  169. package/core/built/admin/assets/posts/{newsletter-BfwFyv6d.js → newsletter-Bid5_Bim.js} +19 -19
  170. package/core/built/admin/assets/posts/{overview-DKGum6ro.js → overview-BXti6Wg_.js} +18 -18
  171. package/core/built/admin/assets/posts/{pencil-Cffx-vm3.js → pencil-ChTk8IpW.js} +2 -2
  172. package/core/built/admin/assets/posts/{plus-D2ekwsq0.js → plus-DIKls8C6.js} +2 -2
  173. package/core/built/admin/assets/posts/{popover-DdbdKflP.js → popover-DVZsAT5u.js} +4 -4
  174. package/core/built/admin/assets/posts/{post-analytics-BleJYoNZ.js → post-analytics-DBL_kS0g.js} +6 -6
  175. package/core/built/admin/assets/posts/{post-analytics-context-DT3Avn9Q.js → post-analytics-context-Dr5y5nxd.js} +6 -6
  176. package/core/built/admin/assets/posts/{post-analytics-header-BktlrM_v.js → post-analytics-header-LH2-Jzgp.js} +13 -13
  177. package/core/built/admin/assets/posts/{post-share-modal-G8v3ZuSg.js → post-share-modal-D4DrfNfJ.js} +6 -6
  178. package/core/built/admin/assets/posts/{posts-CdWV_nlm.js → posts-ByxhcCrn.js} +2 -2
  179. package/core/built/admin/assets/posts/posts.js +1 -1
  180. package/core/built/admin/assets/posts/{search-CXP00fG8.js → search-DZR23LP-.js} +2 -2
  181. package/core/built/admin/assets/posts/{settings-DEXxDYc2.js → settings-CWyOKKnK.js} +2 -2
  182. package/core/built/admin/assets/posts/{sheet-CXHmD_eT.js → sheet-CNe7II5c.js} +3 -3
  183. package/core/built/admin/assets/posts/{site-C6DajagV.js → site-H9RAiQVv.js} +2 -2
  184. package/core/built/admin/assets/posts/{skeleton-Bihnkn8q.js → skeleton-Cn6x1x_C.js} +3 -3
  185. package/core/built/admin/assets/posts/{source-icon-C3oQy3UI.js → source-icon-BZOYujd1.js} +4 -4
  186. package/core/built/admin/assets/posts/{stats-DFicPtCX.js → stats-ugHCg8Oe.js} +4 -4
  187. package/core/built/admin/assets/posts/{table-DSJmeU5t.js → table-dG3Q5X95.js} +2 -2
  188. package/core/built/admin/assets/posts/{tabs-oRdVpN8P.js → tabs--EW8uL5B.js} +4 -4
  189. package/core/built/admin/assets/posts/{tags-6v5Qt_05.js → tags-DVdOfiSf.js} +2 -2
  190. package/core/built/admin/assets/posts/{tags-Upnkm0CF.js → tags-i0HJqNYU.js} +16 -16
  191. package/core/built/admin/assets/posts/{tooltip-Ci7pesWi.js → tooltip-ZvsT1Fs9.js} +4 -4
  192. package/core/built/admin/assets/posts/{trash-2-NCYWjRlg.js → trash-2-BT9fEHUL.js} +2 -2
  193. package/core/built/admin/assets/posts/{value-CcwzOh2_.js → value-DoFcsWDk.js} +2 -2
  194. package/core/built/admin/assets/posts/{virtual-list-window-CNahQBXY.js → virtual-list-window-Bt47XODn.js} +3 -3
  195. package/core/built/admin/assets/posts/{web-C3KrPq0T.js → web-BMTRLT-h.js} +20 -20
  196. package/core/built/admin/assets/posts/{zap-k30mZEuO.js → zap-DcIfEzKX.js} +2 -2
  197. package/core/built/admin/assets/{posts-DAfLuxAA.js → posts-DODOCB1E.js} +1 -1
  198. package/core/built/admin/assets/{power-Drkzg1xX.js → power-BZ7BM82m.js} +1 -1
  199. package/core/built/admin/assets/{referrers-TYxTJ2On.js → referrers-xwNb6L-8.js} +1 -1
  200. package/core/built/admin/assets/{repeat-CTM1qAzl.js → repeat-DHMCQMCA.js} +1 -1
  201. package/core/built/admin/assets/{reply-DXN16g7W.js → reply-DoLURZi2.js} +1 -1
  202. package/core/built/admin/assets/{rocket-DLixlWs0.js → rocket-BDH89dZr.js} +1 -1
  203. package/core/built/admin/assets/{select-DbiLEqYb.js → select-oE39QRll.js} +1 -1
  204. package/core/built/admin/assets/{send-B71C_46D.js → send-QgRN_yRy.js} +1 -1
  205. package/core/built/admin/assets/{settings-BBMPA3MP.js → settings-CF4NLxuS.js} +4 -4
  206. package/core/built/admin/assets/{settings-lSFHFrsJ.js → settings-D7e6KLAi.js} +1 -1
  207. package/core/built/admin/assets/{share-modal-CXrYja6o.js → share-modal-BxIh7i7o.js} +1 -1
  208. package/core/built/admin/assets/{sort-button-WYo-9Kge.js → sort-button-CEe_40Pi.js} +1 -1
  209. package/core/built/admin/assets/{source-icon-D6BzjYPP.js → source-icon-CzTNLO6j.js} +1 -1
  210. package/core/built/admin/assets/{sprout-DVfG_qhy.js → sprout-B2fN41p-.js} +1 -1
  211. package/core/built/admin/assets/{square-BbUJwQJi.js → square-CJZsjE-3.js} +1 -1
  212. package/core/built/admin/assets/{stats-CnXALQ4j.js → stats-jTxCK1CB.js} +1 -1
  213. package/core/built/admin/assets/{stats-view-B-yeMUkl.js → stats-view-B4jz69N8.js} +1 -1
  214. package/core/built/admin/assets/{step-1-DUl_hlpV.js → step-1-BovjhDNc.js} +1 -1
  215. package/core/built/admin/assets/{step-2-DjX_A4Ke.js → step-2-ClG40BfX.js} +1 -1
  216. package/core/built/admin/assets/{step-3-CnDCCA8T.js → step-3-ZMSyEHZI.js} +1 -1
  217. package/core/built/admin/assets/{table-AagTvMa9.js → table-B8Pj96or.js} +1 -1
  218. package/core/built/admin/assets/{tabs-IDJWnQD-.js → tabs-BZosOk0o.js} +1 -1
  219. package/core/built/admin/assets/{tags-CXAcIDw-.js → tags-BpWoYBfB.js} +1 -1
  220. package/core/built/admin/assets/{tags-C3lykbgu.js → tags-DZukMyuU.js} +1 -1
  221. package/core/built/admin/assets/{textarea-Cc3nUXep.js → textarea-BtnzsOk7.js} +1 -1
  222. package/core/built/admin/assets/{thumbs-down-SsjC2lMD.js → thumbs-down-CZTzyz7D.js} +1 -1
  223. package/core/built/admin/assets/{tiers-J8AeZmRd.js → tiers-Do7zBqAk.js} +1 -1
  224. package/core/built/admin/assets/{toggle-group-BzD8yimX.js → toggle-group-abk9FYXi.js} +1 -1
  225. package/core/built/admin/assets/{topic-filter-CA_L6ehz.js → topic-filter-CdMvjkmc.js} +1 -1
  226. package/core/built/admin/assets/{trash-BKhRqxsX.js → trash-DNXRsBf0.js} +1 -1
  227. package/core/built/admin/assets/{underline-_HIgX6e1.js → underline-HXWuVCAi.js} +1 -1
  228. package/core/built/admin/assets/{undo-2-ClkkOS0O.js → undo-2-C2ntNJKC.js} +1 -1
  229. package/core/built/admin/assets/{upload-DEPHbyvo.js → upload-D52l7HIb.js} +1 -1
  230. package/core/built/admin/assets/{use-growth-stats-BM2qWt0C.js → use-growth-stats-Dgs0UxDT.js} +1 -1
  231. package/core/built/admin/assets/{use-simple-pagination-zyklfekn.js → use-simple-pagination-Cj2rVggA.js} +1 -1
  232. package/core/built/admin/assets/{user-round-check-DoaGU2hC.js → user-round-check-C0GdT99c.js} +1 -1
  233. package/core/built/admin/assets/{user-round-x-CwEKNuU6.js → user-round-x-CVCvxuUG.js} +1 -1
  234. package/core/built/admin/assets/{virtual-list-window-C0Cv0gUC.js → virtual-list-window-mdQS2bt_.js} +1 -1
  235. package/core/built/admin/assets/{wallet-cards-BjdG5glh.js → wallet-cards-CtLF01jQ.js} +1 -1
  236. package/core/built/admin/assets/{web-BZNnanCT.js → web-DTib8_n8.js} +1 -1
  237. package/core/built/admin/index.html +6 -6
  238. package/core/frontend/helpers/ghost_foot.js +12 -2
  239. package/core/frontend/helpers/prev_post.js +1 -1
  240. package/core/frontend/helpers/tpl/gift-toast.hbs +130 -0
  241. package/core/frontend/services/proxy.js +9 -0
  242. package/core/frontend/services/routing/controllers/entry/canonical-url.js +15 -0
  243. package/core/frontend/services/routing/controllers/entry/canonical-url.ts +14 -0
  244. package/core/frontend/services/routing/controllers/entry/gift-links.js +82 -0
  245. package/core/frontend/services/routing/controllers/entry/gift-links.ts +92 -0
  246. package/core/frontend/services/routing/controllers/entry/markdown.js +62 -0
  247. package/core/frontend/services/routing/controllers/entry/markdown.ts +66 -0
  248. package/core/frontend/services/routing/controllers/entry.js +96 -105
  249. package/core/frontend/services/routing/controllers/entry.ts +97 -0
  250. package/core/frontend/services/routing/controllers/index.js +1 -1
  251. package/core/frontend/web/middleware/frontend-caching.js +9 -0
  252. package/core/server/adapters/cache/Redis.js +0 -1
  253. package/core/server/adapters/redirects/RedirectsStoreBase.d.ts +0 -4
  254. package/core/server/adapters/scheduling/scheduling-default.js +8 -1
  255. package/core/server/api/endpoints/gift-links.js +23 -16
  256. package/core/server/api/endpoints/gift-links.ts +25 -17
  257. package/core/server/api/endpoints/index.js +0 -1
  258. package/core/server/api/endpoints/previews.js +3 -24
  259. package/core/server/api/endpoints/utils/serializers/output/gift-links.js +4 -4
  260. package/core/server/api/endpoints/utils/serializers/output/gift-links.ts +4 -4
  261. package/core/server/api/endpoints/utils/serializers/output/index.js +0 -1
  262. package/core/server/api/endpoints/utils/validators/input/automation_email_previews.js +8 -9
  263. package/core/server/api/endpoints/utils/validators/input/index.js +0 -1
  264. package/core/server/data/migrations/versions/6.48/2026-06-23-00-00-00-drop-gift-links-revoked-at.js +6 -0
  265. package/core/server/data/migrations/versions/6.48/2026-06-23-00-00-01-rename-gift-links-revoke-all-permission-to-remove-all.js +37 -0
  266. package/core/server/data/migrations/versions/6.48/2026-06-24-00-00-00-drop-gift-links-redemption-columns.js +10 -0
  267. package/core/server/data/schema/fixtures/fixtures.json +2 -2
  268. package/core/server/data/schema/schema.js +1 -4
  269. package/core/server/data/seeders/data-generator.js +4 -1
  270. package/core/server/data/seeders/importers/members-login-events-importer.js +0 -1
  271. package/core/server/data/seeders/importers/members-newsletters-importer.js +0 -1
  272. package/core/server/data/seeders/importers/members-paid-subscription-events-importer.js +0 -1
  273. package/core/server/data/seeders/importers/members-status-events-importer.js +0 -1
  274. package/core/server/data/seeders/importers/members-stripe-customers-importer.js +0 -1
  275. package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +0 -1
  276. package/core/server/data/seeders/importers/members-subscribe-events-importer.js +0 -1
  277. package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +0 -1
  278. package/core/server/lib/lexical.js +62 -36
  279. package/core/server/lib/post-revisions.js +0 -2
  280. package/core/server/lib/post-revisions.ts +0 -3
  281. package/core/server/models/index.js +0 -3
  282. package/core/server/services/auth/reset-authentication.js +0 -2
  283. package/core/server/services/auth/reset-authentication.ts +0 -3
  284. package/core/server/services/auth/session/index.js +0 -1
  285. package/core/server/services/automations/automations-api.js +59 -17
  286. package/core/server/services/automations/automations-api.ts +69 -16
  287. package/core/server/services/automations/database-automations-repository.js +58 -3
  288. package/core/server/services/automations/database-automations-repository.ts +70 -3
  289. package/core/server/services/automations/stale-lock-cutoff.js +7 -0
  290. package/core/server/services/automations/stale-lock-cutoff.ts +5 -0
  291. package/core/server/services/email-address/email-address-parser.js.d.ts +0 -1
  292. package/core/server/services/email-service/batch-sending-service.js +99 -26
  293. package/core/server/services/email-service/email-service-wrapper.js +7 -2
  294. package/core/server/services/email-service/email-service.js +146 -4
  295. package/core/server/services/gift-links/database.js +0 -3
  296. package/core/server/services/gift-links/database.ts +1 -4
  297. package/core/server/services/gift-links/index.js +2 -2
  298. package/core/server/services/gift-links/index.ts +4 -2
  299. package/core/server/services/gift-links/models.js +0 -2
  300. package/core/server/services/gift-links/models.ts +0 -2
  301. package/core/server/services/gift-links/queries.js +2 -2
  302. package/core/server/services/gift-links/queries.ts +2 -2
  303. package/core/server/services/gift-links/serializers.js +0 -2
  304. package/core/server/services/gift-links/serializers.ts +0 -2
  305. package/core/server/services/gift-links/service.js +54 -35
  306. package/core/server/services/gift-links/service.ts +70 -35
  307. package/core/server/services/gifts/gift-reminder-scheduler.js +0 -2
  308. package/core/server/services/gifts/gift-reminder-scheduler.ts +0 -2
  309. package/core/server/services/indexnow.js +8 -1
  310. package/core/server/services/internal-keys/index.js +0 -1
  311. package/core/server/services/internal-keys/index.ts +0 -2
  312. package/core/server/services/lib/dynamic-redirect-manager.d.ts +0 -1
  313. package/core/server/services/lib/in-memory-repository.js +0 -1
  314. package/core/server/services/lib/in-memory-repository.ts +0 -2
  315. package/core/server/services/members/api.js +0 -3
  316. package/core/server/services/members/create-paid-member-shim.js +31 -0
  317. package/core/server/services/members/create-paid-member-shim.ts +31 -0
  318. package/core/server/services/members/emails/signin.js +0 -1
  319. package/core/server/services/members/members-api/members-api.js +0 -2
  320. package/core/server/services/members/members-api/repositories/member-repository.js +0 -3
  321. package/core/server/services/members/service.js +4 -0
  322. package/core/server/services/post-scheduling/index.js +0 -2
  323. package/core/server/services/post-scheduling/index.ts +0 -2
  324. package/core/server/services/post-scheduling/post-scheduling.js +0 -5
  325. package/core/server/services/post-scheduling/post-scheduling.ts +0 -5
  326. package/core/server/services/recommendations/service/bookshelf-repository.js +0 -1
  327. package/core/server/services/recommendations/service/bookshelf-repository.ts +0 -4
  328. package/core/server/services/recommendations/service/incoming-recommendation-service.js +0 -1
  329. package/core/server/services/recommendations/service/incoming-recommendation-service.ts +0 -1
  330. package/core/server/services/recommendations/service/recommendation-controller.js +0 -1
  331. package/core/server/services/recommendations/service/recommendation-controller.ts +0 -1
  332. package/core/server/services/recommendations/service/recommendation-metadata-service.js +0 -1
  333. package/core/server/services/recommendations/service/recommendation-metadata-service.ts +0 -1
  334. package/core/server/services/recommendations/service/recommendation.js +0 -1
  335. package/core/server/services/recommendations/service/recommendation.ts +0 -1
  336. package/core/server/services/remote-flags/index.js +0 -1
  337. package/core/server/services/remote-flags/index.ts +0 -1
  338. package/core/server/services/slack.js +5 -1
  339. package/core/server/services/update-check/index.js +0 -1
  340. package/core/server/services/url/lazy-find-resource.js +0 -1
  341. package/core/server/services/url/lazy-find-resource.ts +0 -2
  342. package/core/server/services/url/lazy-url-service.js +0 -1
  343. package/core/server/services/url/lazy-url-service.ts +0 -2
  344. package/core/server/services/url/permalink-matcher.js +0 -1
  345. package/core/server/services/url/permalink-matcher.ts +0 -2
  346. package/core/server/services/url/router-filter.js +0 -2
  347. package/core/server/services/url/router-filter.ts +0 -2
  348. package/core/server/services/url/url-service-facade.js +0 -1
  349. package/core/server/services/url/url-service-facade.ts +0 -2
  350. package/core/server/services/verification/verification-webhook-service.js +0 -1
  351. package/core/server/services/verification/verification-webhook-service.ts +0 -1
  352. package/core/server/web/api/endpoints/admin/routes.js +7 -7
  353. package/core/shared/events-ts/post-deleted-event.js +0 -2
  354. package/core/shared/events-ts/post-deleted-event.ts +0 -2
  355. package/core/shared/labs.js +0 -1
  356. package/package.json +8 -16
  357. package/pnpm-lock.yaml +162 -113
  358. package/core/built/admin/assets/automations-BthXBzzq.js +0 -1
  359. package/core/built/admin/assets/editor-91xrI2A3.js +0 -8
  360. package/core/built/admin/assets/index-BYb09f-7.css +0 -1
  361. package/core/built/admin/assets/minus-DmrVsJ-z.js +0 -1
  362. package/core/built/admin/assets/modals-dnqxCS3l.js +0 -35
  363. package/core/server/models/outbox.js +0 -24
  364. package/core/server/services/outbox/events/start-outbox-processing-event.js +0 -22
  365. package/core/server/services/outbox/handlers/member-created.js +0 -85
  366. package/core/server/services/outbox/index.js +0 -49
  367. package/core/server/services/outbox/jobs/index.js +0 -30
  368. package/core/server/services/outbox/jobs/lib/constants.js +0 -17
  369. package/core/server/services/outbox/jobs/lib/process-entries.js +0 -117
  370. package/core/server/services/outbox/jobs/lib/process-outbox.js +0 -96
  371. package/core/server/services/outbox/jobs/outbox-job.js +0 -36
  372. package/types/ghost-storage-base.d.ts +0 -22
@@ -40,16 +40,27 @@ exports.GiftLinksService = void 0;
40
40
  exports.generateGiftLinkToken = generateGiftLinkToken;
41
41
  const crypto_1 = __importDefault(require("crypto"));
42
42
  const errors_1 = __importDefault(require("@tryghost/errors"));
43
+ const logging_1 = __importDefault(require("@tryghost/logging"));
43
44
  const zod_1 = require("zod");
44
45
  const models_1 = require("./models");
45
46
  const queries = __importStar(require("./queries"));
46
47
  function generateGiftLinkToken() {
47
48
  return models_1.GiftLinkToken.parse(crypto_1.default.randomBytes(24).toString('base64url'));
48
49
  }
50
+ // The history UI only surfaces a verb-specific label (action_name) for 'edited' events; 'added' and
51
+ // 'deleted' render as the bare event. So 'reset' maps to 'edited' to read as "reset", while
52
+ // 'add'/'remove' read as plain "added"/"deleted".
53
+ const COMMANDS = {
54
+ add: 'added',
55
+ reset: 'edited',
56
+ remove: 'deleted'
57
+ };
49
58
  class GiftLinksService {
50
59
  knex;
51
- constructor({ knex }) {
60
+ Action;
61
+ constructor({ knex, Action }) {
52
62
  this.knex = knex;
63
+ this.Action = Action;
53
64
  }
54
65
  async getPost(postId) {
55
66
  return this.requirePost(postId);
@@ -58,37 +69,32 @@ class GiftLinksService {
58
69
  const row = await queries.liveLinkForToken(token)(this.knex);
59
70
  return row ? { id: row.post_id, giftLinks: [zod_1.z.decode(queries.giftLinkCodec, row)] } : null;
60
71
  }
61
- async issue(postId) {
62
- const post = await this.requirePost(postId);
63
- return post.giftLinks.length ? post : this.mint(postId);
72
+ async isValidTokenForPost(token, postId) {
73
+ return (await this.getPostByToken(token))?.id === postId;
64
74
  }
65
- async reissue(postId) {
75
+ async ensure(context, postId) {
66
76
  const post = await this.requirePost(postId);
67
- return this.mint(postId, post.giftLinks[0]?.token);
77
+ if (post.giftLinks.length) {
78
+ return post;
79
+ }
80
+ const minted = await this.mint(postId);
81
+ await this.recordAction(context, 'add', postId);
82
+ return minted;
68
83
  }
69
- // Stamp revoked_at on the live links, then drop their associations. The link records stay
70
- // as history; liveness is the association, so revoked_at only marks deliberate revocation.
71
- async revokeAll() {
72
- const now = new Date();
73
- let revoked = 0;
74
- await this.knex.transaction(async (trx) => {
75
- await trx('gift_links')
76
- .whereIn('token', trx('post_gift_links').select('gift_link_token'))
77
- .update({ revoked_at: now, updated_at: now });
78
- revoked = await trx('post_gift_links').del();
79
- });
80
- return revoked;
84
+ async create(context, postId) {
85
+ await this.requirePost(postId);
86
+ const minted = await this.mint(postId);
87
+ await this.recordAction(context, 'reset', postId);
88
+ return minted;
81
89
  }
82
- // Keyed by token, not liveness: a read against a since-reissued token still counts for it.
83
- async recordRedemption(token) {
84
- const now = new Date();
85
- return this.knex('gift_links')
86
- .where({ token })
87
- .update({ last_redeemed_at: now, updated_at: now })
88
- .increment('redeemed_count', 1);
90
+ // Remove every live association; the gift_links rows stay as history.
91
+ async removeAll(context) {
92
+ const removed = await this.knex('post_gift_links').del();
93
+ if (removed > 0) {
94
+ await this.recordAction(context, 'remove', null);
95
+ }
96
+ return removed;
89
97
  }
90
- // A missing post is a 404, not a post with no live links: no rows means no post, and the
91
- // remaining rows carrying a token are the live links.
92
98
  async requirePost(postId) {
93
99
  const rows = await queries.liveLinksForPost(postId)(this.knex);
94
100
  if (rows.length === 0) {
@@ -99,16 +105,10 @@ class GiftLinksService {
99
105
  .map(row => zod_1.z.decode(queries.giftLinkCodec, row));
100
106
  return { id: postId, giftLinks };
101
107
  }
102
- // Issue and reissue are one upsert: a new store row, with the live association repointed to
103
- // it. On reissue the replaced link is stamped revoked_at as history. Concurrent issues are
104
- // last-writer-wins, not an error.
105
- async mint(postId, replacing) {
108
+ async mint(postId) {
106
109
  const now = new Date();
107
- const link = { token: generateGiftLinkToken(), redeemedCount: 0, lastRedeemedAt: null, createdAt: now };
110
+ const link = { token: generateGiftLinkToken(), createdAt: now };
108
111
  await this.knex.transaction(async (trx) => {
109
- if (replacing) {
110
- await trx('gift_links').where({ token: replacing }).update({ revoked_at: now, updated_at: now });
111
- }
112
112
  await trx('gift_links').insert({ ...zod_1.z.encode(queries.giftLinkCodec, link), post_id: postId });
113
113
  await trx('post_gift_links')
114
114
  .insert({ post_id: postId, gift_link_token: link.token, created_at: now })
@@ -117,5 +117,24 @@ class GiftLinksService {
117
117
  });
118
118
  return { id: postId, giftLinks: [link] };
119
119
  }
120
+ async recordAction(context, verb, subject) {
121
+ if (!context.actor) {
122
+ return;
123
+ }
124
+ const event = COMMANDS[verb];
125
+ try {
126
+ await this.Action.add({
127
+ event,
128
+ resource_type: 'gift_link',
129
+ resource_id: subject,
130
+ actor_type: context.actor.type,
131
+ actor_id: context.actor.id,
132
+ ...(event === 'edited' ? { context: { action_name: verb } } : {})
133
+ }, { autoRefresh: false });
134
+ }
135
+ catch (err) {
136
+ logging_1.default.error(err);
137
+ }
138
+ }
120
139
  }
121
140
  exports.GiftLinksService = GiftLinksService;
@@ -1,5 +1,6 @@
1
1
  import crypto from 'crypto';
2
2
  import errors from '@tryghost/errors';
3
+ import logging from '@tryghost/logging';
3
4
  import {z} from 'zod';
4
5
  import type {Knex} from 'knex';
5
6
  import {GiftLinkToken, type GiftLink, type Post} from './models';
@@ -9,11 +10,37 @@ export function generateGiftLinkToken(): GiftLinkToken {
9
10
  return GiftLinkToken.parse(crypto.randomBytes(24).toString('base64url'));
10
11
  }
11
12
 
13
+ export interface Actor {
14
+ id: string;
15
+ type: 'user' | 'integration';
16
+ }
17
+
18
+ interface ActionRecorder {
19
+ add(data: Record<string, unknown>, options: {autoRefresh: boolean}): Promise<unknown>;
20
+ }
21
+
22
+ export interface RequestContext {
23
+ actor: Actor | null;
24
+ }
25
+
26
+ // The history UI only surfaces a verb-specific label (action_name) for 'edited' events; 'added' and
27
+ // 'deleted' render as the bare event. So 'reset' maps to 'edited' to read as "reset", while
28
+ // 'add'/'remove' read as plain "added"/"deleted".
29
+ const COMMANDS = {
30
+ add: 'added',
31
+ reset: 'edited',
32
+ remove: 'deleted'
33
+ } as const satisfies Record<string, 'added' | 'edited' | 'deleted'>;
34
+
35
+ type GiftLinkVerb = keyof typeof COMMANDS;
36
+
12
37
  export class GiftLinksService {
13
38
  private knex: Knex;
39
+ private Action: ActionRecorder;
14
40
 
15
- constructor({knex}: {knex: Knex}) {
41
+ constructor({knex, Action}: {knex: Knex; Action: ActionRecorder}) {
16
42
  this.knex = knex;
43
+ this.Action = Action;
17
44
  }
18
45
 
19
46
  async getPost(postId: string): Promise<Post> {
@@ -25,41 +52,36 @@ export class GiftLinksService {
25
52
  return row ? {id: row.post_id, giftLinks: [z.decode(queries.giftLinkCodec, row)]} : null;
26
53
  }
27
54
 
28
- async issue(postId: string): Promise<Post> {
29
- const post = await this.requirePost(postId);
30
- return post.giftLinks.length ? post : this.mint(postId);
55
+ async isValidTokenForPost(token: string, postId: string): Promise<boolean> {
56
+ return (await this.getPostByToken(token))?.id === postId;
31
57
  }
32
58
 
33
- async reissue(postId: string): Promise<Post> {
59
+ async ensure(context: RequestContext, postId: string): Promise<Post> {
34
60
  const post = await this.requirePost(postId);
35
- return this.mint(postId, post.giftLinks[0]?.token);
61
+ if (post.giftLinks.length) {
62
+ return post;
63
+ }
64
+ const minted = await this.mint(postId);
65
+ await this.recordAction(context, 'add', postId);
66
+ return minted;
36
67
  }
37
68
 
38
- // Stamp revoked_at on the live links, then drop their associations. The link records stay
39
- // as history; liveness is the association, so revoked_at only marks deliberate revocation.
40
- async revokeAll(): Promise<number> {
41
- const now = new Date();
42
- let revoked = 0;
43
- await this.knex.transaction(async (trx) => {
44
- await trx('gift_links')
45
- .whereIn('token', trx('post_gift_links').select('gift_link_token'))
46
- .update({revoked_at: now, updated_at: now});
47
- revoked = await trx('post_gift_links').del();
48
- });
49
- return revoked;
69
+ async create(context: RequestContext, postId: string): Promise<Post> {
70
+ await this.requirePost(postId);
71
+ const minted = await this.mint(postId);
72
+ await this.recordAction(context, 'reset', postId);
73
+ return minted;
50
74
  }
51
75
 
52
- // Keyed by token, not liveness: a read against a since-reissued token still counts for it.
53
- async recordRedemption(token: string): Promise<number> {
54
- const now = new Date();
55
- return this.knex('gift_links')
56
- .where({token})
57
- .update({last_redeemed_at: now, updated_at: now})
58
- .increment('redeemed_count', 1);
76
+ // Remove every live association; the gift_links rows stay as history.
77
+ async removeAll(context: RequestContext): Promise<number> {
78
+ const removed = await this.knex('post_gift_links').del();
79
+ if (removed > 0) {
80
+ await this.recordAction(context, 'remove', null);
81
+ }
82
+ return removed;
59
83
  }
60
84
 
61
- // A missing post is a 404, not a post with no live links: no rows means no post, and the
62
- // remaining rows carrying a token are the live links.
63
85
  private async requirePost(postId: string): Promise<Post> {
64
86
  const rows = await queries.liveLinksForPost(postId)(this.knex);
65
87
  if (rows.length === 0) {
@@ -71,16 +93,10 @@ export class GiftLinksService {
71
93
  return {id: postId, giftLinks};
72
94
  }
73
95
 
74
- // Issue and reissue are one upsert: a new store row, with the live association repointed to
75
- // it. On reissue the replaced link is stamped revoked_at as history. Concurrent issues are
76
- // last-writer-wins, not an error.
77
- private async mint(postId: string, replacing?: GiftLinkToken): Promise<Post> {
96
+ private async mint(postId: string): Promise<Post> {
78
97
  const now = new Date();
79
- const link: GiftLink = {token: generateGiftLinkToken(), redeemedCount: 0, lastRedeemedAt: null, createdAt: now};
98
+ const link: GiftLink = {token: generateGiftLinkToken(), createdAt: now};
80
99
  await this.knex.transaction(async (trx) => {
81
- if (replacing) {
82
- await trx('gift_links').where({token: replacing}).update({revoked_at: now, updated_at: now});
83
- }
84
100
  await trx('gift_links').insert({...z.encode(queries.giftLinkCodec, link), post_id: postId});
85
101
  await trx('post_gift_links')
86
102
  .insert({post_id: postId, gift_link_token: link.token, created_at: now})
@@ -89,4 +105,23 @@ export class GiftLinksService {
89
105
  });
90
106
  return {id: postId, giftLinks: [link]};
91
107
  }
108
+
109
+ private async recordAction(context: RequestContext, verb: GiftLinkVerb, subject: string | null): Promise<void> {
110
+ if (!context.actor) {
111
+ return;
112
+ }
113
+ const event = COMMANDS[verb];
114
+ try {
115
+ await this.Action.add({
116
+ event,
117
+ resource_type: 'gift_link',
118
+ resource_id: subject,
119
+ actor_type: context.actor.type,
120
+ actor_id: context.actor.id,
121
+ ...(event === 'edited' ? {context: {action_name: verb}} : {})
122
+ }, {autoRefresh: false});
123
+ } catch (err) {
124
+ logging.error(err);
125
+ }
126
+ }
92
127
  }
@@ -7,9 +7,7 @@ exports.GiftReminderScheduler = void 0;
7
7
  const logging_1 = __importDefault(require("@tryghost/logging"));
8
8
  const constants_1 = require("./constants");
9
9
  // Same-domain (scheduling) primitives, used unconditionally.
10
- // eslint-disable-next-line @typescript-eslint/no-require-imports
11
10
  const urlUtils = require('../../../shared/url-utils');
12
- // eslint-disable-next-line @typescript-eslint/no-require-imports
13
11
  const { getSignedAdminToken } = require('../../adapters/scheduling/utils');
14
12
  const MS_PER_DAY = 24 * 60 * 60 * 1000;
15
13
  const GIFT_REMINDER_LEAD_MS = constants_1.GIFT_REMINDER_LEAD_DAYS * MS_PER_DAY;
@@ -4,9 +4,7 @@ import type {InternalApiKey, InternalKeys} from '../internal-keys';
4
4
  import type {SchedulerAdapter, SchedulerJob} from '../../adapters/scheduling/types';
5
5
  import {GIFT_REMINDER_LEAD_DAYS} from './constants';
6
6
  // Same-domain (scheduling) primitives, used unconditionally.
7
- // eslint-disable-next-line @typescript-eslint/no-require-imports
8
7
  const urlUtils = require('../../../shared/url-utils');
9
- // eslint-disable-next-line @typescript-eslint/no-require-imports
10
8
  const {getSignedAdminToken} = require('../../adapters/scheduling/utils');
11
9
 
12
10
  const MS_PER_DAY = 24 * 60 * 60 * 1000;
@@ -222,7 +222,14 @@ function indexnowListener(model, options) {
222
222
  return;
223
223
  }
224
224
 
225
- ping(model.toJSON()).catch(() => {
225
+ ping({
226
+ ...model.toJSON(),
227
+ // tags and authors are needed so the lazy URL service can evaluate
228
+ // collection filters (e.g. `tag:foo`) when resolving the post URL;
229
+ // without them a tag/author-filtered post resolves to /404/
230
+ authors: model.related('authors').toJSON(),
231
+ tags: model.related('tags').toJSON()
232
+ }).catch(() => {
226
233
  // Errors are already logged inside ping()
227
234
  // This catch is just to prevent unhandled rejection warnings
228
235
  });
@@ -12,7 +12,6 @@ const SLUG_KEY_TYPE = {
12
12
  // method without polluting the file with `any`. The generic constrains
13
13
  // known internal slugs to their seeded type; arbitrary slugs accept any
14
14
  // type.
15
- // eslint-disable-next-line @typescript-eslint/no-require-imports
16
15
  const models = require('../../models');
17
16
  /**
18
17
  * Process-lifetime cache of internal-integration API keys, keyed by slug.
@@ -35,10 +35,8 @@ export type InternalKeys = AutoFillingMap<InternalIntegrationSlug, Promise<Inter
35
35
  // method without polluting the file with `any`. The generic constrains
36
36
  // known internal slugs to their seeded type; arbitrary slugs accept any
37
37
  // type.
38
- // eslint-disable-next-line @typescript-eslint/no-require-imports
39
38
  const models = require('../../models') as {
40
39
  Integration: {
41
- // eslint-disable-next-line no-unused-vars
42
40
  getApiKeyBySlug<S extends string>(slug: S, type: S extends InternalIntegrationSlug ? typeof SLUG_KEY_TYPE[S] : ApiKeyType): Promise<InternalApiKey>;
43
41
  };
44
42
  };
@@ -1,4 +1,3 @@
1
- /* eslint-disable ghost/filenames/match-exported-class */
2
1
  import type {Request, Response, NextFunction} from 'express';
3
2
 
4
3
  export interface DynamicRedirectManagerOptions {
@@ -37,7 +37,6 @@ class InMemoryRepository {
37
37
  for (const order of options.order) {
38
38
  results.sort((a, b) => {
39
39
  if (order.direction === 'asc') {
40
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
40
  return a[order.field] > b[order.field] ? 1 : -1;
42
41
  }
43
42
  else {
@@ -10,7 +10,6 @@ type Order<T> = {
10
10
  direction: 'asc' | 'desc';
11
11
  }
12
12
 
13
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
13
  type OrderOption<T extends Entity<any>> = Order<T>[];
15
14
 
16
15
  export abstract class InMemoryRepository<IDType, T extends Entity<IDType>> {
@@ -52,7 +51,6 @@ export abstract class InMemoryRepository<IDType, T extends Entity<IDType>> {
52
51
  for (const order of options.order) {
53
52
  results.sort((a, b) => {
54
53
  if (order.direction === 'asc') {
55
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
54
  return a[order.field] as any > (b[order.field] as any) ? 1 : -1;
57
55
  } else {
58
56
  return a[order.field] < b[order.field] ? 1 : -1;
@@ -170,7 +170,6 @@ function createApiInstance(config) {
170
170
  `;
171
171
  case 'signin':
172
172
  default:
173
- /* eslint-disable indent */
174
173
  return trimLeadingWhitespace`
175
174
  ${t(`Hey there,`)}
176
175
 
@@ -190,7 +189,6 @@ function createApiInstance(config) {
190
189
  ${t('Sent to {email}', {email})}
191
190
  ${t('If you did not make this request, you can safely ignore this email.')}
192
191
  `;
193
- /* eslint-enable indent */
194
192
  }
195
193
  },
196
194
  getHTML(url, type, email, otc) {
@@ -241,7 +239,6 @@ function createApiInstance(config) {
241
239
  Comment: models.Comment,
242
240
  MemberFeedback: models.MemberFeedback,
243
241
  EmailSpamComplaintEvent: models.EmailSpamComplaintEvent,
244
- Outbox: models.Outbox,
245
242
  Automation: models.Automation,
246
243
  WelcomeEmailAutomationRun: models.WelcomeEmailAutomationRun,
247
244
  AutomatedEmailRecipient: models.AutomatedEmailRecipient,
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createPaidMemberShim = createPaidMemberShim;
7
+ const logging_1 = __importDefault(require("@tryghost/logging"));
8
+ const models = require('../../models');
9
+ /**
10
+ * Build a stand-in "all active paid tiers" member for content gating — NOT a real
11
+ * member. It carries only the `status` and `products` that
12
+ * `contentGating.checkPostAccess` / `checkGatedBlockAccess` read, letting previews
13
+ * (`member_status=paid`) and gift-link reads reveal gated content without a
14
+ * logged-in member. Single source of truth for this security-sensitive grant.
15
+ */
16
+ async function createPaidMemberShim() {
17
+ let products = [];
18
+ try {
19
+ const paidProducts = await models.Product.findAll({ status: 'active', type: 'paid' });
20
+ products = paidProducts.map((product) => ({ slug: product.get('slug') }));
21
+ }
22
+ catch (error) {
23
+ // Fall back to no tiers rather than failing the render — still grants
24
+ // status:paid/members content, just not tier-specific blocks.
25
+ logging_1.default.error('Failed to build paid member shim tiers:', error);
26
+ }
27
+ return {
28
+ status: 'paid',
29
+ products
30
+ };
31
+ }
@@ -0,0 +1,31 @@
1
+ import logging from '@tryghost/logging';
2
+ const models = require('../../models');
3
+
4
+ interface PaidMemberShim {
5
+ status: 'paid';
6
+ products: Array<{slug: string}>;
7
+ }
8
+
9
+ /**
10
+ * Build a stand-in "all active paid tiers" member for content gating — NOT a real
11
+ * member. It carries only the `status` and `products` that
12
+ * `contentGating.checkPostAccess` / `checkGatedBlockAccess` read, letting previews
13
+ * (`member_status=paid`) and gift-link reads reveal gated content without a
14
+ * logged-in member. Single source of truth for this security-sensitive grant.
15
+ */
16
+ export async function createPaidMemberShim(): Promise<PaidMemberShim> {
17
+ let products: Array<{slug: string}> = [];
18
+ try {
19
+ const paidProducts = await models.Product.findAll({status: 'active', type: 'paid'});
20
+ products = paidProducts.map((product: {get(key: string): string}) => ({slug: product.get('slug')}));
21
+ } catch (error) {
22
+ // Fall back to no tiers rather than failing the render — still grants
23
+ // status:paid/members content, just not tier-specific blocks.
24
+ logging.error('Failed to build paid member shim tiers:', error);
25
+ }
26
+
27
+ return {
28
+ status: 'paid',
29
+ products
30
+ };
31
+ }
@@ -1,4 +1,3 @@
1
- /* eslint-disable indent */
2
1
  module.exports = ({t, siteTitle, email, url, otc, accentColor = '#15212A', siteDomain, siteUrl}) => `
3
2
  <!doctype html>
4
3
  <html>
@@ -65,7 +65,6 @@ module.exports = function MembersAPI({
65
65
  Settings,
66
66
  Comment,
67
67
  MemberFeedback,
68
- Outbox,
69
68
  Automation,
70
69
  WelcomeEmailAutomationRun,
71
70
  AutomatedEmailRecipient,
@@ -119,7 +118,6 @@ module.exports = function MembersAPI({
119
118
  OfferRedemption,
120
119
  StripeCustomer,
121
120
  StripeCustomerSubscription,
122
- Outbox,
123
121
  offersAPI
124
122
  });
125
123
 
@@ -64,7 +64,6 @@ module.exports = class MemberRepository {
64
64
  * @param {any} deps.StripeCustomer
65
65
  * @param {any} deps.StripeCustomerSubscription
66
66
  * @param {any} deps.OfferRedemption
67
- * @param {any} deps.Outbox
68
67
  * @param {import('../../../stripe/stripe-api')} deps.stripeAPIService
69
68
  * @param {any} deps.productRepository
70
69
  * @param {any} deps.offersAPI
@@ -86,7 +85,6 @@ module.exports = class MemberRepository {
86
85
  StripeCustomer,
87
86
  StripeCustomerSubscription,
88
87
  OfferRedemption,
89
- Outbox,
90
88
  stripeAPIService,
91
89
  productRepository,
92
90
  offersAPI,
@@ -105,7 +103,6 @@ module.exports = class MemberRepository {
105
103
  this._MemberStatusEvent = MemberStatusEvent;
106
104
  this._MemberProductEvent = MemberProductEvent;
107
105
  this._OfferRedemption = OfferRedemption;
108
- this._Outbox = Outbox;
109
106
  this._StripeCustomer = StripeCustomer;
110
107
  this._StripeCustomerSubscription = StripeCustomerSubscription;
111
108
  this._stripeAPIService = stripeAPIService;
@@ -171,6 +171,10 @@ module.exports = {
171
171
  },
172
172
  contentGating: require('./content-gating'),
173
173
 
174
+ // Create an "all active paid tiers" member shim for rendering gated content
175
+ // without a logged-in member (post previews, gift-links reader path).
176
+ createPaidMemberShim: require('./create-paid-member-shim').createPaidMemberShim,
177
+
174
178
  config: membersConfig,
175
179
 
176
180
  get api() {
@@ -6,9 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const post_scheduling_1 = __importDefault(require("./post-scheduling"));
7
7
  const internal_keys_1 = __importDefault(require("../internal-keys"));
8
8
  // CJS modules without TS declarations — typed loosely at the boundary.
9
- // eslint-disable-next-line @typescript-eslint/no-require-imports
10
9
  const adapterManager = require('../adapter-manager');
11
- // eslint-disable-next-line @typescript-eslint/no-require-imports
12
10
  const urlUtils = require('../../../shared/url-utils');
13
11
  exports.default = new post_scheduling_1.default({
14
12
  apiUrl: urlUtils.urlFor('api', { type: 'admin' }, true),
@@ -2,9 +2,7 @@ import PostScheduling from './post-scheduling';
2
2
  import internalKeys from '../internal-keys';
3
3
 
4
4
  // CJS modules without TS declarations — typed loosely at the boundary.
5
- // eslint-disable-next-line @typescript-eslint/no-require-imports
6
5
  const adapterManager = require('../adapter-manager');
7
- // eslint-disable-next-line @typescript-eslint/no-require-imports
8
6
  const urlUtils = require('../../../shared/url-utils');
9
7
 
10
8
  export default new PostScheduling({
@@ -3,18 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- /* eslint-disable @typescript-eslint/no-explicit-any */
7
6
  const moment_1 = __importDefault(require("moment"));
8
7
  const logging_1 = __importDefault(require("@tryghost/logging"));
9
8
  // CJS-only modules — typed loosely below. models is the Bookshelf registry
10
9
  // without TS declarations; the rest are JS modules without types.
11
- // eslint-disable-next-line @typescript-eslint/no-require-imports
12
10
  const models = require('../../models');
13
- // eslint-disable-next-line @typescript-eslint/no-require-imports
14
11
  const urlUtils = require('../../../shared/url-utils');
15
- // eslint-disable-next-line @typescript-eslint/no-require-imports
16
12
  const { getSignedAdminToken } = require('../../adapters/scheduling/utils');
17
- // eslint-disable-next-line @typescript-eslint/no-require-imports
18
13
  const events = require('../../lib/common/events');
19
14
  // Pages live in the posts table with type:'page', so both types are
20
15
  // queried through models.Post and discriminated via the type filter.
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
1
  import moment from 'moment';
3
2
  import logging from '@tryghost/logging';
4
3
  import type {InternalApiKey, InternalKeys} from '../internal-keys';
@@ -6,13 +5,9 @@ import type {SchedulerAdapter, SchedulerJob} from '../../adapters/scheduling/typ
6
5
 
7
6
  // CJS-only modules — typed loosely below. models is the Bookshelf registry
8
7
  // without TS declarations; the rest are JS modules without types.
9
- // eslint-disable-next-line @typescript-eslint/no-require-imports
10
8
  const models = require('../../models');
11
- // eslint-disable-next-line @typescript-eslint/no-require-imports
12
9
  const urlUtils = require('../../../shared/url-utils');
13
- // eslint-disable-next-line @typescript-eslint/no-require-imports
14
10
  const {getSignedAdminToken} = require('../../adapters/scheduling/utils');
15
- // eslint-disable-next-line @typescript-eslint/no-require-imports
16
11
  const events = require('../../lib/common/events');
17
12
 
18
13
  interface PostSchedulingDeps {
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- /* eslint-disable ghost/filenames/match-exported-class */
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
@@ -1,4 +1,3 @@
1
- /* eslint-disable ghost/filenames/match-exported-class */
2
1
 
3
2
  import {Knex} from 'knex';
4
3
  import {mapKeys, chainTransformers} from '@tryghost/mongo-utils';
@@ -38,11 +37,8 @@ type OptionalPropertyOf<T extends object> = Exclude<{
38
37
  : K
39
38
  }[keyof T], undefined>
40
39
 
41
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
40
  export type OrderOption<T extends Entity<any> = any> = Order<T>[];
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
41
  export type IncludeOption<T extends Entity<any> = any> = OptionalPropertyOf<T>[];
45
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
42
  export type AllOptions<T extends Entity<any> = any> = { filter?: string; order?: OrderOption<T>; page?: number; limit?: number, include?: IncludeOption<T> }
47
43
 
48
44
  export abstract class BookshelfRepository<IDType, T extends Entity<IDType>> {
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- /* eslint-disable ghost/filenames/match-exported-class */
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
@@ -1,4 +1,3 @@
1
- /* eslint-disable ghost/filenames/match-exported-class */
2
1
 
3
2
  import {IncomingRecommendationEmailRenderer} from './incoming-recommendation-email-renderer';
4
3
  import {RecommendationService} from './recommendation-service';
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.RecommendationController = void 0;
7
- /* eslint-disable @typescript-eslint/no-explicit-any */
8
7
  const errors_1 = __importDefault(require("@tryghost/errors"));
9
8
  const unsafe_data_1 = require("./unsafe-data");
10
9
  const RecommendationIncludesMap = {
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
1
  import errors from '@tryghost/errors';
3
2
  import {AddRecommendation, Recommendation, RecommendationPlain} from './recommendation';
4
3
  import {RecommendationService} from './recommendation-service';
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- /* eslint-disable ghost/filenames/match-exported-class */
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.RecommendationMetadataService = void 0;
5
4
  class RecommendationMetadataService {