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.
- package/MigratorConfig.js +0 -1
- package/bin/create-migration.js +1 -1
- package/bin/generate-golden-email.js +0 -1
- package/components/tryghost-i18n-0.0.0.tgz +0 -0
- package/core/boot.js +13 -7
- package/core/built/admin/assets/{PolarAngleAxis-CLluELUg.js → PolarAngleAxis-DufzOBEz.js} +1 -1
- package/core/built/admin/assets/{_baseAssignValue-Dz1iqdwD.js → _baseAssignValue-BjUm4QeA.js} +1 -1
- package/core/built/admin/assets/{a-large-small-BA74vHPp.js → a-large-small-D0RF_WS9.js} +1 -1
- package/core/built/admin/assets/{account-migration-B-NqdKuN.js → account-migration-B7n6ezrZ.js} +1 -1
- package/core/built/admin/assets/activitypub/{account-migration-ClmVrAXr.js → account-migration-BJeRnMCl.js} +3 -3
- package/core/built/admin/assets/activitypub/activitypub.js +1 -1
- package/core/built/admin/assets/activitypub/{at-sign-9F3qd4Nn.js → at-sign-BygVOKdj.js} +2 -2
- package/core/built/admin/assets/activitypub/{avatar-flipboard-jBHA13Ej.js → avatar-flipboard-CNcjI8lK.js} +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-1irhvVtF.js → bluesky-sharing-mgBNeRfA.js} +4 -4
- package/core/built/admin/assets/activitypub/{copy-DXRvsGiK.js → copy-BMChXIQc.js} +2 -2
- package/core/built/admin/assets/activitypub/{deleted-feed-item-67VQJde4.js → deleted-feed-item-D-spb6V1.js} +2 -2
- package/core/built/admin/assets/activitypub/{edit-profile-BfpbEj98.js → edit-profile-CDQ3V8-c.js} +4 -4
- package/core/built/admin/assets/activitypub/{feed-DUrI7SPC.js → feed-Vqr3WU-V.js} +4 -4
- package/core/built/admin/assets/activitypub/{hash-CMtB10PN.js → hash-D7SSXVOg.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-2xq8SJ7A.js → inbox-BHk5Dw27.js} +2 -2
- package/core/built/admin/assets/activitypub/{index-BT97xLpd.js → index-BejkeH-m.js} +2 -2
- package/core/built/admin/assets/activitypub/{index-DssHQAjK.js → index-BqL23J-m.js} +32 -32
- package/core/built/admin/assets/activitypub/{index-Ba6FXt8y.js → index-CHhvjNuG.js} +6 -6
- package/core/built/admin/assets/activitypub/{index-ERtz4Bvy.js → index-CZsNO9hA.js} +5 -5
- package/core/built/admin/assets/activitypub/{index-sgY7lLrg.js → index-CaIhRYzz.js} +3 -3
- package/core/built/admin/assets/activitypub/{index-D1EWoXrK.js → index-DA2MkQVu.js} +2 -2
- package/core/built/admin/assets/activitypub/{index-sudOvKcY.js → index-DHhFcmfu.js} +21 -21
- package/core/built/admin/assets/activitypub/{index-Ccighz1t.js → index-sh2bDSls.js} +4 -4
- package/core/built/admin/assets/activitypub/{label-KQSsSjmN.js → label-D80yhOIm.js} +2 -2
- package/core/built/admin/assets/activitypub/{moderation-B78if-r0.js → moderation-LJNmKBCi.js} +3 -3
- package/core/built/admin/assets/activitypub/{note-Bfr7ovn7.js → note-CyjKLcQ-.js} +4 -4
- package/core/built/admin/assets/activitypub/{reply-CehesW8Z.js → reply-BiiCFx7G.js} +2 -2
- package/core/built/admin/assets/activitypub/{separator-B_Ly_Qq8.js → separator-CY3PMmtI.js} +2 -2
- package/core/built/admin/assets/activitypub/{settings-D6R97p7v.js → settings-BQy6Gr7R.js} +3 -3
- package/core/built/admin/assets/activitypub/{step-1-Cl1YxgZ1.js → step-1-DCqRwgf3.js} +3 -3
- package/core/built/admin/assets/activitypub/{step-2-DDyR--Qe.js → step-2-DQlhehTO.js} +5 -5
- package/core/built/admin/assets/activitypub/{step-3-Don8gv0n.js → step-3-DAUCAcxW.js} +7 -7
- package/core/built/admin/assets/activitypub/{tabs-DTpfm-wu.js → tabs-B_6UuI7r.js} +3 -3
- package/core/built/admin/assets/activitypub/{topic-filter-Oee10885.js → topic-filter--FT1A_dc.js} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
- package/core/built/admin/assets/admin-x-settings/{code-editor-view-CGZuiDGx.js → code-editor-view-Bp_sCJR0.js} +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-CwEblQZC.js → index-BPXA3pTW.js} +5 -5
- package/core/built/admin/assets/admin-x-settings/{index-rr_UntGE.js → index-BS375mg1.js} +3 -3
- package/core/built/admin/assets/admin-x-settings/{index-BpM6W2br.js → index-B_PlQoEG.js} +3 -3
- package/core/built/admin/assets/admin-x-settings/{index-BGdS5xw4.js → index-BflhAbu2.js} +3 -3
- package/core/built/admin/assets/admin-x-settings/{index-DtWUeJhp.js → index-CftMe8fe.js} +3 -3
- package/core/built/admin/assets/admin-x-settings/{index-B65inCwj.js → index-DRB7FH6y.js} +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-DSX261S9.js → index-DijZ3oAM.js} +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-DF6YEs01.js → index-cV0Lof9H.js} +1526 -1500
- package/core/built/admin/assets/admin-x-settings/{index-CluZYkUC.js → index-qc4x3vZj.js} +3 -3
- package/core/built/admin/assets/admin-x-settings/{modals-Bf4KOU31.js → modals-CkjuEByw.js} +55 -67
- package/core/built/admin/assets/{arrow-right-BxP3aeA5.js → arrow-right-BF77Yx73.js} +1 -1
- package/core/built/admin/assets/{at-sign-Bf0y-jim.js → at-sign-DhJF3n_V.js} +1 -1
- package/core/built/admin/assets/{audience-DHR1WgFK.js → audience-DHPKKayV.js} +1 -1
- package/core/built/admin/assets/{automated-emails-DbJbDLib.js → automated-emails-DInKYTEC.js} +1 -1
- package/core/built/admin/assets/{automations-aLgTzSsZ.js → automations-DJpeZw9T.js} +1 -1
- package/core/built/admin/assets/automations-DpQKN9j0.js +1 -0
- package/core/built/admin/assets/{avatar-flipboard-B0F2LMW5.js → avatar-flipboard-yRdmFC6R.js} +1 -1
- package/core/built/admin/assets/{bluesky-sharing-DjhtIuyr.js → bluesky-sharing-qSiCERoR.js} +1 -1
- package/core/built/admin/assets/{chart-BGwxlD0z.js → chart-CP2N9ZC-.js} +1 -1
- package/core/built/admin/assets/{chevron-up-C2FeVzre.js → chevron-up-BQ6fOpFR.js} +1 -1
- package/core/built/admin/assets/{chunk.524.31b31f7958dfae110016.js → chunk.524.ad4560630d4d62fbceb5.js} +4 -4
- package/core/built/admin/assets/{chunk.582.a855020953886af6e83b.js → chunk.582.fd4878e4e0af31ef86c0.js} +6 -6
- package/core/built/admin/assets/{chunk.972.258e6b1dab79b2189f1c.js → chunk.98.69968e0f393d82c2949c.js} +4 -4
- package/core/built/admin/assets/{code-editor-view-DzPkm_nJ.js → code-editor-view-CVODiRVJ.js} +1 -1
- package/core/built/admin/assets/{comments-DgItXUWN.js → comments-CP-NxopD.js} +1 -1
- package/core/built/admin/assets/{content-helpers-BNefU_PE.js → content-helpers-Crzkusiq.js} +1 -1
- package/core/built/admin/assets/{copy-DoNNUZlb.js → copy-r1LFsU75.js} +1 -1
- package/core/built/admin/assets/{data-list-CO1cZQRU.js → data-list-CzSc7z-2.js} +1 -1
- package/core/built/admin/assets/{deleted-feed-item-DC2wSAhv.js → deleted-feed-item-PyEM8FiX.js} +1 -1
- package/core/built/admin/assets/{dropzone-BTODLafn.js → dropzone-DI8A9qO6.js} +1 -1
- package/core/built/admin/assets/{edit-profile-BMMpmWIZ.js → edit-profile-DlJ64lV7.js} +1 -1
- package/core/built/admin/assets/editor-CevNZicQ.js +8 -0
- package/core/built/admin/assets/{empty-indicator-Dza0FQlj.js → empty-indicator-Dxg05yWg.js} +1 -1
- package/core/built/admin/assets/{en-yf9qAqTu.js → en-D93GVp3o.js} +1 -1
- package/core/built/admin/assets/{eye-CAqnnfQF.js → eye-6POPPpTw.js} +1 -1
- package/core/built/admin/assets/{feed-BkNsbWiF.js → feed-P_RMYb5x.js} +1 -1
- package/core/built/admin/assets/{field-Ddb1ZOqM.js → field-DeNjwWrL.js} +1 -1
- package/core/built/admin/assets/{filter-query-core-5Mac92kh.js → filter-query-core-DFs5WSmA.js} +1 -1
- package/core/built/admin/assets/{filters-BCb4bgtg.js → filters-C_BSQgb7.js} +1 -1
- package/core/built/admin/assets/{gh-chart-C6zkIg8k.js → gh-chart-pNHAbeQn.js} +1 -1
- package/core/built/admin/assets/{ghost-5313258fd425ced5db6516acde01ba36.js → ghost-3f5b3569e0beec61266cb74077677fbc.js} +3 -3
- package/core/built/admin/assets/{growth-ezUlN8OE.js → growth-B83tVOYO.js} +1 -1
- package/core/built/admin/assets/{hash-DE2OmChI.js → hash-BCTATV5W.js} +1 -1
- package/core/built/admin/assets/{inbox-OthiHvlV.js → inbox-rE3c5suT.js} +1 -1
- package/core/built/admin/assets/{index-BLyzLfyx.js → index-7EiRc5Ay.js} +1 -1
- package/core/built/admin/assets/{index-CV5v0eFE.js → index-B5bpZGTI.js} +1 -1
- package/core/built/admin/assets/index-BNtzAd7H.css +1 -0
- package/core/built/admin/assets/{index-BC1yWeaJ.js → index-BT33w2Io.js} +1 -1
- package/core/built/admin/assets/{index-DjffQ3VJ.js → index-BbkXWdhb.js} +1 -1
- package/core/built/admin/assets/{index-DH6PA3W6.js → index-BfhSrnrJ.js} +1 -1
- package/core/built/admin/assets/{index-CRvK0Iac.js → index-BmR_OUpb.js} +1 -1
- package/core/built/admin/assets/{index-CNV7fxKZ.js → index-BuhMgn5c.js} +1 -1
- package/core/built/admin/assets/{index-pkixJbdq.js → index-C-075SzJ.js} +34 -34
- package/core/built/admin/assets/{index-DJoByVS8.js → index-CB3hJd9E.js} +1 -1
- package/core/built/admin/assets/{index-D3bb-MEJ.js → index-CCISLIQd.js} +1 -1
- package/core/built/admin/assets/{index-BIEhcKiV.js → index-Cnptpx11.js} +1 -1
- package/core/built/admin/assets/{index-DK1cu59e.js → index-CrBRU81r.js} +1 -1
- package/core/built/admin/assets/{index-B0_p1-R0.js → index-CscUHFJp.js} +1 -1
- package/core/built/admin/assets/{index-Bi5qzf86.js → index-D3ZzfuJt.js} +1 -1
- package/core/built/admin/assets/{index-CKPny_6u.js → index-D4wn-U0V.js} +1 -1
- package/core/built/admin/assets/{index-YzcsD17L.js → index-DNRlkUeu.js} +1 -1
- package/core/built/admin/assets/{index-BoMsDCxD.js → index-D_G6negZ.js} +1 -1
- package/core/built/admin/assets/{index-CwsmINtV.js → index-DfxHSK1s.js} +1 -1
- package/core/built/admin/assets/{index-X91I8PcS.js → index-Dpc3COTl.js} +1 -1
- package/core/built/admin/assets/{index-c1h-EQpd.js → index-UsbnU2jy.js} +1 -1
- package/core/built/admin/assets/{index-oKgNVmwC.js → index-VfrJzh5m.js} +1 -1
- package/core/built/admin/assets/{index-D5MrQBSe.js → index-fbxc8Dpt.js} +1 -1
- package/core/built/admin/assets/{input-group-BOLMrDfJ.js → input-group-BLygwiDK.js} +1 -1
- package/core/built/admin/assets/{koenig-lexical-DlzcWUPw.js → koenig-lexical-B9U3sBS5.js} +1 -1
- package/core/built/admin/assets/{kpi-card-BlF7JKRC.js → kpi-card-Bmnvvp4X.js} +1 -1
- package/core/built/admin/assets/{kpi-card-HDshm3lO.js → kpi-card-CGVtzdgJ.js} +1 -1
- package/core/built/admin/assets/{kpi-tabs-Dty6zMSP.js → kpi-tabs-DxbvMkIU.js} +1 -1
- package/core/built/admin/assets/{kpis-CFz4r5wW.js → kpis-CQBAGVjP.js} +1 -1
- package/core/built/admin/assets/{label-CVzNcbjb.js → label-DpTwHQi_.js} +1 -1
- package/core/built/admin/assets/{links-D9dHwDlP.js → links-Bdw25FJF.js} +1 -1
- package/core/built/admin/assets/{list-page-shoQED7N.js → list-page-BvTQwP5F.js} +1 -1
- package/core/built/admin/assets/{loader-circle-cad701gH.js → loader-circle-3HJkQKWf.js} +1 -1
- package/core/built/admin/assets/{mail-DG4PKpZy.js → mail-DvrqP73n.js} +1 -1
- package/core/built/admin/assets/{main-layout-BmFla3Se.js → main-layout-BAPpm0bz.js} +1 -1
- package/core/built/admin/assets/{members-d19Z6k1C.js → members-CF4CzJSf.js} +1 -1
- package/core/built/admin/assets/minus-DJIePlnU.js +1 -0
- package/core/built/admin/assets/modals-CVsVi0zu.js +35 -0
- package/core/built/admin/assets/{moderation-BWBLnh4h.js → moderation-BX1KH5QL.js} +1 -1
- package/core/built/admin/assets/{newsletter-DNY4MroI.js → newsletter-BlKeb58e.js} +1 -1
- package/core/built/admin/assets/{newsletters-B10iBPP-.js → newsletters-3In8H0Z5.js} +1 -1
- package/core/built/admin/assets/{note-S0b6wjRR.js → note-ybwJCAxm.js} +1 -1
- package/core/built/admin/assets/{offers-B-9mZqKd.js → offers-Cl0ZNEMr.js} +1 -1
- package/core/built/admin/assets/{onboarding-route-AMFn0X5G.js → onboarding-route-A3ECeMAi.js} +1 -1
- package/core/built/admin/assets/{overview-WKadyZRW.js → overview-DrMrfsk-.js} +1 -1
- package/core/built/admin/assets/{pagemenu-BofQcFaF.js → pagemenu-O7HbsehH.js} +1 -1
- package/core/built/admin/assets/{pencil-LfMcD0vS.js → pencil-CknTbJeE.js} +1 -1
- package/core/built/admin/assets/{pin-CayUjL8e.js → pin-BNs-JdQ3.js} +1 -1
- package/core/built/admin/assets/{post-analytics-DMHvt3Jl.js → post-analytics-Dk1VloZp.js} +1 -1
- package/core/built/admin/assets/{post-analytics-context-10cqioP1.js → post-analytics-context-kPL94Ivz.js} +1 -1
- package/core/built/admin/assets/{post-analytics-header-DlICE18K.js → post-analytics-header-CpMOozq-.js} +1 -1
- package/core/built/admin/assets/{post-share-modal-Cfwy2UwD.js → post-share-modal-F0dobdhF.js} +1 -1
- package/core/built/admin/assets/posts/{alert-dialog-cQK32v9G.js → alert-dialog-NoPLULhG.js} +5 -5
- package/core/built/admin/assets/posts/{app-utils-DQ2hixop.js → app-utils-BiM9QO4L.js} +3 -3
- package/core/built/admin/assets/posts/{automations-BqkU9-zY.js → automations-BgIAmq9f.js} +3 -3
- package/core/built/admin/assets/posts/{automations-CoilKpVH.js → automations-D_XwO405.js} +30 -30
- package/core/built/admin/assets/posts/{avatar-BejAO6Rj.js → avatar-BYsYOpmq.js} +5 -5
- package/core/built/admin/assets/posts/{badge-BYGRyd2f.js → badge-B54vLono.js} +2 -2
- package/core/built/admin/assets/posts/{button-CG2Dpjqy.js → button-DMLfwOQt.js} +3 -3
- package/core/built/admin/assets/posts/{check-fsC5BvGC.js → check-D6qDi62T.js} +2 -2
- package/core/built/admin/assets/posts/{comments-CsyF5C1S.js → comments-CyYCbvUG.js} +26 -26
- package/core/built/admin/assets/posts/{data-list-JslRF2F5.js → data-list-B0DrMm-x.js} +4 -4
- package/core/built/admin/assets/posts/{dialog-3KY3A8t5.js → dialog-DtEZpY1q.js} +3 -3
- package/core/built/admin/assets/posts/{editor-3HPW_xW4.js → editor-LJHLmUoW.js} +1943 -1943
- package/core/built/admin/assets/posts/{ellipsis-BhK5S70U.js → ellipsis-JeIF0Biz.js} +2 -2
- package/core/built/admin/assets/posts/{empty-indicator-C9DbE9wZ.js → empty-indicator-dktzN32y.js} +2 -2
- package/core/built/admin/assets/posts/{filters-BCBDCnQF.js → filters-D1L-LU_m.js} +10 -10
- package/core/built/admin/assets/posts/{get-site-timezone-83C41MGz.js → get-site-timezone-dsyl8nlB.js} +3 -3
- package/core/built/admin/assets/posts/{growth-COoL1kMe.js → growth-yX8UB_ce.js} +12 -12
- package/core/built/admin/assets/posts/{heading-D3VqNO3z.js → heading-CNte43wH.js} +2 -2
- package/core/built/admin/assets/posts/{hooks-5YpJYWOw.js → hooks-BIgv7QBp.js} +2 -2
- package/core/built/admin/assets/posts/{index-Dqn5WIFh.js → index-2FO6Vy0r.js} +11 -11
- package/core/built/admin/assets/posts/{input-C1qcZBGw.js → input-BycmlCp8.js} +3 -3
- package/core/built/admin/assets/posts/{input-surface-C4vUAdbV.js → input-surface-vY3ACaso.js} +2 -2
- package/core/built/admin/assets/posts/{koenig-lexical-NZjxFY0X.js → koenig-lexical-Cq8SUcZC.js} +2 -2
- package/core/built/admin/assets/posts/{kpis-C2FEXoUT.js → kpis-CAJcU1w0.js} +27 -27
- package/core/built/admin/assets/posts/{label-CmJzmJY7.js → label-BmLTflMF.js} +3 -3
- package/core/built/admin/assets/posts/{links-nzud7t_t.js → links-BVcmMZmF.js} +4 -4
- package/core/built/admin/assets/posts/{list-page-D_rv4TgN.js → list-page-DX2WRn5T.js} +4 -4
- package/core/built/admin/assets/posts/{loading-indicator-DAOD6O2b.js → loading-indicator-C6FD4nS6.js} +3 -3
- package/core/built/admin/assets/posts/{mail-CtH0gTpq.js → mail-BMyoNUVM.js} +2 -2
- package/core/built/admin/assets/posts/{main-layout-VqvCxOXQ.js → main-layout-ClnxdW1Y.js} +2 -2
- package/core/built/admin/assets/posts/{message-circle-D4bCjxKS.js → message-circle-DwfHX-p1.js} +2 -2
- package/core/built/admin/assets/posts/{newsletter-BfwFyv6d.js → newsletter-Bid5_Bim.js} +19 -19
- package/core/built/admin/assets/posts/{overview-DKGum6ro.js → overview-BXti6Wg_.js} +18 -18
- package/core/built/admin/assets/posts/{pencil-Cffx-vm3.js → pencil-ChTk8IpW.js} +2 -2
- package/core/built/admin/assets/posts/{plus-D2ekwsq0.js → plus-DIKls8C6.js} +2 -2
- package/core/built/admin/assets/posts/{popover-DdbdKflP.js → popover-DVZsAT5u.js} +4 -4
- package/core/built/admin/assets/posts/{post-analytics-BleJYoNZ.js → post-analytics-DBL_kS0g.js} +6 -6
- package/core/built/admin/assets/posts/{post-analytics-context-DT3Avn9Q.js → post-analytics-context-Dr5y5nxd.js} +6 -6
- package/core/built/admin/assets/posts/{post-analytics-header-BktlrM_v.js → post-analytics-header-LH2-Jzgp.js} +13 -13
- package/core/built/admin/assets/posts/{post-share-modal-G8v3ZuSg.js → post-share-modal-D4DrfNfJ.js} +6 -6
- package/core/built/admin/assets/posts/{posts-CdWV_nlm.js → posts-ByxhcCrn.js} +2 -2
- package/core/built/admin/assets/posts/posts.js +1 -1
- package/core/built/admin/assets/posts/{search-CXP00fG8.js → search-DZR23LP-.js} +2 -2
- package/core/built/admin/assets/posts/{settings-DEXxDYc2.js → settings-CWyOKKnK.js} +2 -2
- package/core/built/admin/assets/posts/{sheet-CXHmD_eT.js → sheet-CNe7II5c.js} +3 -3
- package/core/built/admin/assets/posts/{site-C6DajagV.js → site-H9RAiQVv.js} +2 -2
- package/core/built/admin/assets/posts/{skeleton-Bihnkn8q.js → skeleton-Cn6x1x_C.js} +3 -3
- package/core/built/admin/assets/posts/{source-icon-C3oQy3UI.js → source-icon-BZOYujd1.js} +4 -4
- package/core/built/admin/assets/posts/{stats-DFicPtCX.js → stats-ugHCg8Oe.js} +4 -4
- package/core/built/admin/assets/posts/{table-DSJmeU5t.js → table-dG3Q5X95.js} +2 -2
- package/core/built/admin/assets/posts/{tabs-oRdVpN8P.js → tabs--EW8uL5B.js} +4 -4
- package/core/built/admin/assets/posts/{tags-6v5Qt_05.js → tags-DVdOfiSf.js} +2 -2
- package/core/built/admin/assets/posts/{tags-Upnkm0CF.js → tags-i0HJqNYU.js} +16 -16
- package/core/built/admin/assets/posts/{tooltip-Ci7pesWi.js → tooltip-ZvsT1Fs9.js} +4 -4
- package/core/built/admin/assets/posts/{trash-2-NCYWjRlg.js → trash-2-BT9fEHUL.js} +2 -2
- package/core/built/admin/assets/posts/{value-CcwzOh2_.js → value-DoFcsWDk.js} +2 -2
- package/core/built/admin/assets/posts/{virtual-list-window-CNahQBXY.js → virtual-list-window-Bt47XODn.js} +3 -3
- package/core/built/admin/assets/posts/{web-C3KrPq0T.js → web-BMTRLT-h.js} +20 -20
- package/core/built/admin/assets/posts/{zap-k30mZEuO.js → zap-DcIfEzKX.js} +2 -2
- package/core/built/admin/assets/{posts-DAfLuxAA.js → posts-DODOCB1E.js} +1 -1
- package/core/built/admin/assets/{power-Drkzg1xX.js → power-BZ7BM82m.js} +1 -1
- package/core/built/admin/assets/{referrers-TYxTJ2On.js → referrers-xwNb6L-8.js} +1 -1
- package/core/built/admin/assets/{repeat-CTM1qAzl.js → repeat-DHMCQMCA.js} +1 -1
- package/core/built/admin/assets/{reply-DXN16g7W.js → reply-DoLURZi2.js} +1 -1
- package/core/built/admin/assets/{rocket-DLixlWs0.js → rocket-BDH89dZr.js} +1 -1
- package/core/built/admin/assets/{select-DbiLEqYb.js → select-oE39QRll.js} +1 -1
- package/core/built/admin/assets/{send-B71C_46D.js → send-QgRN_yRy.js} +1 -1
- package/core/built/admin/assets/{settings-BBMPA3MP.js → settings-CF4NLxuS.js} +4 -4
- package/core/built/admin/assets/{settings-lSFHFrsJ.js → settings-D7e6KLAi.js} +1 -1
- package/core/built/admin/assets/{share-modal-CXrYja6o.js → share-modal-BxIh7i7o.js} +1 -1
- package/core/built/admin/assets/{sort-button-WYo-9Kge.js → sort-button-CEe_40Pi.js} +1 -1
- package/core/built/admin/assets/{source-icon-D6BzjYPP.js → source-icon-CzTNLO6j.js} +1 -1
- package/core/built/admin/assets/{sprout-DVfG_qhy.js → sprout-B2fN41p-.js} +1 -1
- package/core/built/admin/assets/{square-BbUJwQJi.js → square-CJZsjE-3.js} +1 -1
- package/core/built/admin/assets/{stats-CnXALQ4j.js → stats-jTxCK1CB.js} +1 -1
- package/core/built/admin/assets/{stats-view-B-yeMUkl.js → stats-view-B4jz69N8.js} +1 -1
- package/core/built/admin/assets/{step-1-DUl_hlpV.js → step-1-BovjhDNc.js} +1 -1
- package/core/built/admin/assets/{step-2-DjX_A4Ke.js → step-2-ClG40BfX.js} +1 -1
- package/core/built/admin/assets/{step-3-CnDCCA8T.js → step-3-ZMSyEHZI.js} +1 -1
- package/core/built/admin/assets/{table-AagTvMa9.js → table-B8Pj96or.js} +1 -1
- package/core/built/admin/assets/{tabs-IDJWnQD-.js → tabs-BZosOk0o.js} +1 -1
- package/core/built/admin/assets/{tags-CXAcIDw-.js → tags-BpWoYBfB.js} +1 -1
- package/core/built/admin/assets/{tags-C3lykbgu.js → tags-DZukMyuU.js} +1 -1
- package/core/built/admin/assets/{textarea-Cc3nUXep.js → textarea-BtnzsOk7.js} +1 -1
- package/core/built/admin/assets/{thumbs-down-SsjC2lMD.js → thumbs-down-CZTzyz7D.js} +1 -1
- package/core/built/admin/assets/{tiers-J8AeZmRd.js → tiers-Do7zBqAk.js} +1 -1
- package/core/built/admin/assets/{toggle-group-BzD8yimX.js → toggle-group-abk9FYXi.js} +1 -1
- package/core/built/admin/assets/{topic-filter-CA_L6ehz.js → topic-filter-CdMvjkmc.js} +1 -1
- package/core/built/admin/assets/{trash-BKhRqxsX.js → trash-DNXRsBf0.js} +1 -1
- package/core/built/admin/assets/{underline-_HIgX6e1.js → underline-HXWuVCAi.js} +1 -1
- package/core/built/admin/assets/{undo-2-ClkkOS0O.js → undo-2-C2ntNJKC.js} +1 -1
- package/core/built/admin/assets/{upload-DEPHbyvo.js → upload-D52l7HIb.js} +1 -1
- package/core/built/admin/assets/{use-growth-stats-BM2qWt0C.js → use-growth-stats-Dgs0UxDT.js} +1 -1
- package/core/built/admin/assets/{use-simple-pagination-zyklfekn.js → use-simple-pagination-Cj2rVggA.js} +1 -1
- package/core/built/admin/assets/{user-round-check-DoaGU2hC.js → user-round-check-C0GdT99c.js} +1 -1
- package/core/built/admin/assets/{user-round-x-CwEKNuU6.js → user-round-x-CVCvxuUG.js} +1 -1
- package/core/built/admin/assets/{virtual-list-window-C0Cv0gUC.js → virtual-list-window-mdQS2bt_.js} +1 -1
- package/core/built/admin/assets/{wallet-cards-BjdG5glh.js → wallet-cards-CtLF01jQ.js} +1 -1
- package/core/built/admin/assets/{web-BZNnanCT.js → web-DTib8_n8.js} +1 -1
- package/core/built/admin/index.html +6 -6
- package/core/frontend/helpers/ghost_foot.js +12 -2
- package/core/frontend/helpers/prev_post.js +1 -1
- package/core/frontend/helpers/tpl/gift-toast.hbs +130 -0
- package/core/frontend/services/proxy.js +9 -0
- package/core/frontend/services/routing/controllers/entry/canonical-url.js +15 -0
- package/core/frontend/services/routing/controllers/entry/canonical-url.ts +14 -0
- package/core/frontend/services/routing/controllers/entry/gift-links.js +82 -0
- package/core/frontend/services/routing/controllers/entry/gift-links.ts +92 -0
- package/core/frontend/services/routing/controllers/entry/markdown.js +62 -0
- package/core/frontend/services/routing/controllers/entry/markdown.ts +66 -0
- package/core/frontend/services/routing/controllers/entry.js +96 -105
- package/core/frontend/services/routing/controllers/entry.ts +97 -0
- package/core/frontend/services/routing/controllers/index.js +1 -1
- package/core/frontend/web/middleware/frontend-caching.js +9 -0
- package/core/server/adapters/cache/Redis.js +0 -1
- package/core/server/adapters/redirects/RedirectsStoreBase.d.ts +0 -4
- package/core/server/adapters/scheduling/scheduling-default.js +8 -1
- package/core/server/api/endpoints/gift-links.js +23 -16
- package/core/server/api/endpoints/gift-links.ts +25 -17
- package/core/server/api/endpoints/index.js +0 -1
- package/core/server/api/endpoints/previews.js +3 -24
- package/core/server/api/endpoints/utils/serializers/output/gift-links.js +4 -4
- package/core/server/api/endpoints/utils/serializers/output/gift-links.ts +4 -4
- package/core/server/api/endpoints/utils/serializers/output/index.js +0 -1
- package/core/server/api/endpoints/utils/validators/input/automation_email_previews.js +8 -9
- package/core/server/api/endpoints/utils/validators/input/index.js +0 -1
- package/core/server/data/migrations/versions/6.48/2026-06-23-00-00-00-drop-gift-links-revoked-at.js +6 -0
- 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
- package/core/server/data/migrations/versions/6.48/2026-06-24-00-00-00-drop-gift-links-redemption-columns.js +10 -0
- package/core/server/data/schema/fixtures/fixtures.json +2 -2
- package/core/server/data/schema/schema.js +1 -4
- package/core/server/data/seeders/data-generator.js +4 -1
- package/core/server/data/seeders/importers/members-login-events-importer.js +0 -1
- package/core/server/data/seeders/importers/members-newsletters-importer.js +0 -1
- package/core/server/data/seeders/importers/members-paid-subscription-events-importer.js +0 -1
- package/core/server/data/seeders/importers/members-status-events-importer.js +0 -1
- package/core/server/data/seeders/importers/members-stripe-customers-importer.js +0 -1
- package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +0 -1
- package/core/server/data/seeders/importers/members-subscribe-events-importer.js +0 -1
- package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +0 -1
- package/core/server/lib/lexical.js +62 -36
- package/core/server/lib/post-revisions.js +0 -2
- package/core/server/lib/post-revisions.ts +0 -3
- package/core/server/models/index.js +0 -3
- package/core/server/services/auth/reset-authentication.js +0 -2
- package/core/server/services/auth/reset-authentication.ts +0 -3
- package/core/server/services/auth/session/index.js +0 -1
- package/core/server/services/automations/automations-api.js +59 -17
- package/core/server/services/automations/automations-api.ts +69 -16
- package/core/server/services/automations/database-automations-repository.js +58 -3
- package/core/server/services/automations/database-automations-repository.ts +70 -3
- package/core/server/services/automations/stale-lock-cutoff.js +7 -0
- package/core/server/services/automations/stale-lock-cutoff.ts +5 -0
- package/core/server/services/email-address/email-address-parser.js.d.ts +0 -1
- package/core/server/services/email-service/batch-sending-service.js +99 -26
- package/core/server/services/email-service/email-service-wrapper.js +7 -2
- package/core/server/services/email-service/email-service.js +146 -4
- package/core/server/services/gift-links/database.js +0 -3
- package/core/server/services/gift-links/database.ts +1 -4
- package/core/server/services/gift-links/index.js +2 -2
- package/core/server/services/gift-links/index.ts +4 -2
- package/core/server/services/gift-links/models.js +0 -2
- package/core/server/services/gift-links/models.ts +0 -2
- package/core/server/services/gift-links/queries.js +2 -2
- package/core/server/services/gift-links/queries.ts +2 -2
- package/core/server/services/gift-links/serializers.js +0 -2
- package/core/server/services/gift-links/serializers.ts +0 -2
- package/core/server/services/gift-links/service.js +54 -35
- package/core/server/services/gift-links/service.ts +70 -35
- package/core/server/services/gifts/gift-reminder-scheduler.js +0 -2
- package/core/server/services/gifts/gift-reminder-scheduler.ts +0 -2
- package/core/server/services/indexnow.js +8 -1
- package/core/server/services/internal-keys/index.js +0 -1
- package/core/server/services/internal-keys/index.ts +0 -2
- package/core/server/services/lib/dynamic-redirect-manager.d.ts +0 -1
- package/core/server/services/lib/in-memory-repository.js +0 -1
- package/core/server/services/lib/in-memory-repository.ts +0 -2
- package/core/server/services/members/api.js +0 -3
- package/core/server/services/members/create-paid-member-shim.js +31 -0
- package/core/server/services/members/create-paid-member-shim.ts +31 -0
- package/core/server/services/members/emails/signin.js +0 -1
- package/core/server/services/members/members-api/members-api.js +0 -2
- package/core/server/services/members/members-api/repositories/member-repository.js +0 -3
- package/core/server/services/members/service.js +4 -0
- package/core/server/services/post-scheduling/index.js +0 -2
- package/core/server/services/post-scheduling/index.ts +0 -2
- package/core/server/services/post-scheduling/post-scheduling.js +0 -5
- package/core/server/services/post-scheduling/post-scheduling.ts +0 -5
- package/core/server/services/recommendations/service/bookshelf-repository.js +0 -1
- package/core/server/services/recommendations/service/bookshelf-repository.ts +0 -4
- package/core/server/services/recommendations/service/incoming-recommendation-service.js +0 -1
- package/core/server/services/recommendations/service/incoming-recommendation-service.ts +0 -1
- package/core/server/services/recommendations/service/recommendation-controller.js +0 -1
- package/core/server/services/recommendations/service/recommendation-controller.ts +0 -1
- package/core/server/services/recommendations/service/recommendation-metadata-service.js +0 -1
- package/core/server/services/recommendations/service/recommendation-metadata-service.ts +0 -1
- package/core/server/services/recommendations/service/recommendation.js +0 -1
- package/core/server/services/recommendations/service/recommendation.ts +0 -1
- package/core/server/services/remote-flags/index.js +0 -1
- package/core/server/services/remote-flags/index.ts +0 -1
- package/core/server/services/slack.js +5 -1
- package/core/server/services/update-check/index.js +0 -1
- package/core/server/services/url/lazy-find-resource.js +0 -1
- package/core/server/services/url/lazy-find-resource.ts +0 -2
- package/core/server/services/url/lazy-url-service.js +0 -1
- package/core/server/services/url/lazy-url-service.ts +0 -2
- package/core/server/services/url/permalink-matcher.js +0 -1
- package/core/server/services/url/permalink-matcher.ts +0 -2
- package/core/server/services/url/router-filter.js +0 -2
- package/core/server/services/url/router-filter.ts +0 -2
- package/core/server/services/url/url-service-facade.js +0 -1
- package/core/server/services/url/url-service-facade.ts +0 -2
- package/core/server/services/verification/verification-webhook-service.js +0 -1
- package/core/server/services/verification/verification-webhook-service.ts +0 -1
- package/core/server/web/api/endpoints/admin/routes.js +7 -7
- package/core/shared/events-ts/post-deleted-event.js +0 -2
- package/core/shared/events-ts/post-deleted-event.ts +0 -2
- package/core/shared/labs.js +0 -1
- package/package.json +8 -16
- package/pnpm-lock.yaml +162 -113
- package/core/built/admin/assets/automations-BthXBzzq.js +0 -1
- package/core/built/admin/assets/editor-91xrI2A3.js +0 -8
- package/core/built/admin/assets/index-BYb09f-7.css +0 -1
- package/core/built/admin/assets/minus-DmrVsJ-z.js +0 -1
- package/core/built/admin/assets/modals-dnqxCS3l.js +0 -35
- package/core/server/models/outbox.js +0 -24
- package/core/server/services/outbox/events/start-outbox-processing-event.js +0 -22
- package/core/server/services/outbox/handlers/member-created.js +0 -85
- package/core/server/services/outbox/index.js +0 -49
- package/core/server/services/outbox/jobs/index.js +0 -30
- package/core/server/services/outbox/jobs/lib/constants.js +0 -17
- package/core/server/services/outbox/jobs/lib/process-entries.js +0 -117
- package/core/server/services/outbox/jobs/lib/process-outbox.js +0 -96
- package/core/server/services/outbox/jobs/outbox-job.js +0 -36
- package/types/ghost-storage-base.d.ts +0 -22
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const ghostBookshelf = require('./base');
|
|
2
|
-
|
|
3
|
-
const OUTBOX_STATUSES = {
|
|
4
|
-
PENDING: 'pending',
|
|
5
|
-
PROCESSING: 'processing',
|
|
6
|
-
FAILED: 'failed',
|
|
7
|
-
COMPLETED: 'completed'
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const Outbox = ghostBookshelf.Model.extend({
|
|
11
|
-
tableName: 'outbox',
|
|
12
|
-
|
|
13
|
-
defaults() {
|
|
14
|
-
return {
|
|
15
|
-
status: OUTBOX_STATUSES.PENDING,
|
|
16
|
-
retry_count: 0
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
module.exports = {
|
|
22
|
-
Outbox: ghostBookshelf.model('Outbox', Outbox),
|
|
23
|
-
OUTBOX_STATUSES
|
|
24
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This is an event that is used to circumvent the job manager that currently isn't able to run scheduled jobs on the main thread (not offloaded).
|
|
3
|
-
* We simply emit this event in the job manager and listen for it on the main thread.
|
|
4
|
-
*/
|
|
5
|
-
module.exports = class StartOutboxProcessingEvent {
|
|
6
|
-
/**
|
|
7
|
-
* @param {any} data
|
|
8
|
-
* @param {Date} timestamp
|
|
9
|
-
*/
|
|
10
|
-
constructor(data, timestamp) {
|
|
11
|
-
this.data = data;
|
|
12
|
-
this.timestamp = timestamp;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param {any} [data]
|
|
17
|
-
* @param {Date} [timestamp]
|
|
18
|
-
*/
|
|
19
|
-
static create(data, timestamp) {
|
|
20
|
-
return new StartOutboxProcessingEvent(data, timestamp ?? new Date());
|
|
21
|
-
}
|
|
22
|
-
};
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
const {OUTBOX_LOG_KEY} = require('../jobs/lib/constants');
|
|
2
|
-
const memberWelcomeEmailService = require('../../member-welcome-emails/service');
|
|
3
|
-
const logging = require('@tryghost/logging');
|
|
4
|
-
const {Automation, AutomatedEmailRecipient} = require('../../../models');
|
|
5
|
-
const {MEMBER_WELCOME_EMAIL_SLUGS} = require('../../member-welcome-emails/constants');
|
|
6
|
-
|
|
7
|
-
const LOG_KEY = `${OUTBOX_LOG_KEY}[MEMBER-WELCOME-EMAIL]`;
|
|
8
|
-
|
|
9
|
-
async function handle({payload}) {
|
|
10
|
-
await memberWelcomeEmailService.api.send({member: payload, memberStatus: payload.status});
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
const slug = MEMBER_WELCOME_EMAIL_SLUGS[payload.status];
|
|
14
|
-
if (!slug) {
|
|
15
|
-
logging.warn({
|
|
16
|
-
system: {
|
|
17
|
-
event: 'outbox.member_created.no_slug_mapping',
|
|
18
|
-
member_status: payload.status
|
|
19
|
-
}
|
|
20
|
-
}, `${LOG_KEY} No automated email slug found for member status`);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const automation = await Automation.findOne({slug}, {withRelated: ['welcomeEmailAutomatedEmail']});
|
|
25
|
-
if (!automation) {
|
|
26
|
-
logging.warn({
|
|
27
|
-
system: {
|
|
28
|
-
event: 'outbox.member_created.no_automated_email',
|
|
29
|
-
slug
|
|
30
|
-
}
|
|
31
|
-
}, `${LOG_KEY} No automated email found for slug: ${slug}`);
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// NOTE(NY-1190): This naively assumes each drip sequence will have
|
|
36
|
-
// just one email. When we change that assumption, this line will need
|
|
37
|
-
// to change to something like:
|
|
38
|
-
//
|
|
39
|
-
// ```
|
|
40
|
-
// SELECT * FROM welcome_email_automated_emails
|
|
41
|
-
// WHERE welcome_email_automation_id IS ?
|
|
42
|
-
// AND id NOT IN (
|
|
43
|
-
// SELECT next_id FROM welcome_email_automated_emails
|
|
44
|
-
// WHERE next_id IS NOT NULL
|
|
45
|
-
// AND welcome_email_automation_id IS ?
|
|
46
|
-
// );
|
|
47
|
-
// ```
|
|
48
|
-
const email = automation.related('welcomeEmailAutomatedEmail');
|
|
49
|
-
if (!email || !email.id) {
|
|
50
|
-
logging.warn({
|
|
51
|
-
system: {
|
|
52
|
-
event: 'outbox.member_created.no_automated_email',
|
|
53
|
-
slug
|
|
54
|
-
}
|
|
55
|
-
}, `${LOG_KEY} No automated email content found for slug: ${slug}`);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
await AutomatedEmailRecipient.add({
|
|
60
|
-
member_id: payload.memberId,
|
|
61
|
-
automated_email_id: email.id,
|
|
62
|
-
member_uuid: payload.uuid,
|
|
63
|
-
member_email: payload.email,
|
|
64
|
-
member_name: payload.name
|
|
65
|
-
});
|
|
66
|
-
} catch (err) {
|
|
67
|
-
logging.error({
|
|
68
|
-
system: {
|
|
69
|
-
event: 'outbox.member_created.track_send_failed'
|
|
70
|
-
},
|
|
71
|
-
err
|
|
72
|
-
}, `${LOG_KEY} Failed to track automated email send`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function getLogInfo(payload) {
|
|
77
|
-
const email = payload?.email || 'unknown member';
|
|
78
|
-
return payload?.name ? `${payload.name} (${email})` : email;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
module.exports = {
|
|
82
|
-
handle,
|
|
83
|
-
getLogInfo,
|
|
84
|
-
LOG_KEY
|
|
85
|
-
};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
const logging = require('@tryghost/logging');
|
|
2
|
-
const jobs = require('./jobs');
|
|
3
|
-
const StartOutboxProcessingEvent = require('./events/start-outbox-processing-event');
|
|
4
|
-
const domainEvents = require('@tryghost/domain-events');
|
|
5
|
-
const processOutbox = require('./jobs/lib/process-outbox');
|
|
6
|
-
const {OUTBOX_LOG_KEY} = require('./jobs/lib/constants');
|
|
7
|
-
|
|
8
|
-
class OutboxServiceWrapper {
|
|
9
|
-
constructor({jobs: jobsDep = jobs, processOutbox: processOutboxDep = processOutbox} = {}) {
|
|
10
|
-
this.jobs = jobsDep;
|
|
11
|
-
this.processOutbox = processOutboxDep;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
init() {
|
|
15
|
-
if (this.initialized) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
this.processing = false;
|
|
20
|
-
this.jobs.scheduleOutboxJob();
|
|
21
|
-
domainEvents.subscribe(StartOutboxProcessingEvent, async () => {
|
|
22
|
-
await this.startProcessing();
|
|
23
|
-
});
|
|
24
|
-
this.initialized = true;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async startProcessing() {
|
|
28
|
-
if (this.processing) {
|
|
29
|
-
logging.info({system: {event: 'outbox.processing.skipped_already_running'}}, `${OUTBOX_LOG_KEY}: Outbox job already running, skipping`);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
this.processing = true;
|
|
33
|
-
try {
|
|
34
|
-
const statusMessage = await this.processOutbox();
|
|
35
|
-
logging.info(statusMessage);
|
|
36
|
-
} catch (err) {
|
|
37
|
-
logging.error({system: {event: 'outbox.processing.error'}, err}, `${OUTBOX_LOG_KEY}: Error while processing outbox`);
|
|
38
|
-
} finally {
|
|
39
|
-
this.processing = false;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function createOutboxService(deps) {
|
|
45
|
-
return new OutboxServiceWrapper(deps);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
module.exports = createOutboxService();
|
|
49
|
-
module.exports.createOutboxService = createOutboxService;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const jobsService = require('../../jobs');
|
|
3
|
-
|
|
4
|
-
let hasScheduled = {
|
|
5
|
-
processOutbox: false
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
module.exports = {
|
|
9
|
-
scheduleOutboxJob() {
|
|
10
|
-
if (hasScheduled.processOutbox) {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// use a random seconds value to avoid spikes to the database on the minute
|
|
15
|
-
const s = Math.floor(Math.random() * 60); // 0-59
|
|
16
|
-
// run every 5 minutes, on 1,6,11..., 2,7,12..., 3,8,13..., etc
|
|
17
|
-
const m = Math.floor(Math.random() * 5); // 0-4
|
|
18
|
-
|
|
19
|
-
const cronSchedule = `${s} ${m}/5 * * * *`;
|
|
20
|
-
|
|
21
|
-
jobsService.addJob({
|
|
22
|
-
at: cronSchedule,
|
|
23
|
-
job: path.resolve(__dirname, 'outbox-job.js'),
|
|
24
|
-
name: 'process-outbox'
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
hasScheduled.processOutbox = true;
|
|
28
|
-
return hasScheduled.processOutbox;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
const BATCH_SIZE = 100;
|
|
2
|
-
const MAX_ENTRIES_PER_JOB = BATCH_SIZE * 10;
|
|
3
|
-
const MAX_RETRIES = 1;
|
|
4
|
-
const OUTBOX_LOG_KEY = '[OUTBOX]';
|
|
5
|
-
|
|
6
|
-
const MESSAGES = {
|
|
7
|
-
CANCELLED: 'Outbox processing cancelled',
|
|
8
|
-
NO_ENTRIES: 'No pending outbox entries to process'
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
module.exports = {
|
|
12
|
-
BATCH_SIZE,
|
|
13
|
-
MAX_ENTRIES_PER_JOB,
|
|
14
|
-
MAX_RETRIES,
|
|
15
|
-
OUTBOX_LOG_KEY,
|
|
16
|
-
MESSAGES
|
|
17
|
-
};
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
const logging = require('@tryghost/logging');
|
|
2
|
-
const {MAX_RETRIES, OUTBOX_LOG_KEY} = require('./constants');
|
|
3
|
-
const {OUTBOX_STATUSES} = require('../../../../models/outbox');
|
|
4
|
-
const MemberCreatedEvent = require('../../../../../shared/events/member-created-event');
|
|
5
|
-
const memberCreatedHandler = require('../../handlers/member-created');
|
|
6
|
-
|
|
7
|
-
const EVENT_HANDLERS = {
|
|
8
|
-
[MemberCreatedEvent.name]: memberCreatedHandler
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
async function deleteProcessedEntry({db, entryId}) {
|
|
12
|
-
await db.knex('outbox')
|
|
13
|
-
.where('id', entryId)
|
|
14
|
-
.delete();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async function updateFailedEntry({db, entryId, retryCount, errorMessage}) {
|
|
18
|
-
const newRetryCount = retryCount + 1;
|
|
19
|
-
const newStatus = newRetryCount <= MAX_RETRIES ? OUTBOX_STATUSES.PENDING : OUTBOX_STATUSES.FAILED;
|
|
20
|
-
const truncatedMessage = (errorMessage ?? 'Unknown error').toString().slice(0, 2000);
|
|
21
|
-
|
|
22
|
-
await db.knex('outbox')
|
|
23
|
-
.where('id', entryId)
|
|
24
|
-
.update({
|
|
25
|
-
status: newStatus,
|
|
26
|
-
retry_count: newRetryCount,
|
|
27
|
-
last_retry_at: db.knex.raw('CURRENT_TIMESTAMP'),
|
|
28
|
-
message: truncatedMessage,
|
|
29
|
-
updated_at: db.knex.raw('CURRENT_TIMESTAMP')
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function markEntryCompleted({db, entryId}) {
|
|
34
|
-
await db.knex('outbox')
|
|
35
|
-
.where('id', entryId)
|
|
36
|
-
.update({
|
|
37
|
-
status: OUTBOX_STATUSES.COMPLETED,
|
|
38
|
-
message: 'Processed, but failed to delete outbox entry',
|
|
39
|
-
updated_at: db.knex.raw('CURRENT_TIMESTAMP')
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function processEntry({db, entry}) {
|
|
44
|
-
const handler = EVENT_HANDLERS[entry.event_type];
|
|
45
|
-
if (!handler) {
|
|
46
|
-
logging.warn({
|
|
47
|
-
system: {
|
|
48
|
-
event: 'outbox.entry.no_handler',
|
|
49
|
-
event_type: entry.event_type
|
|
50
|
-
}
|
|
51
|
-
}, `${OUTBOX_LOG_KEY} No handler for event type: ${entry.event_type}`);
|
|
52
|
-
await updateFailedEntry({db, entryId: entry.id, retryCount: entry.retry_count, errorMessage: `No handler for event type: ${entry.event_type}`});
|
|
53
|
-
return {success: false};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let payload;
|
|
57
|
-
try {
|
|
58
|
-
payload = JSON.parse(entry.payload);
|
|
59
|
-
await handler.handle({payload});
|
|
60
|
-
} catch (err) {
|
|
61
|
-
const errorMessage = err?.message ?? 'Unknown error';
|
|
62
|
-
await updateFailedEntry({db, entryId: entry.id, retryCount: entry.retry_count, errorMessage});
|
|
63
|
-
|
|
64
|
-
if (!payload) {
|
|
65
|
-
logging.error({
|
|
66
|
-
system: {
|
|
67
|
-
event: 'outbox.entry.payload_parse_failed',
|
|
68
|
-
entry_id: entry.id
|
|
69
|
-
},
|
|
70
|
-
err
|
|
71
|
-
}, `${handler.LOG_KEY} Failed to parse payload for entry ${entry.id}.`);
|
|
72
|
-
} else {
|
|
73
|
-
logging.error({
|
|
74
|
-
system: {
|
|
75
|
-
event: 'outbox.entry.send_failed',
|
|
76
|
-
entry_id: entry.id
|
|
77
|
-
},
|
|
78
|
-
err
|
|
79
|
-
}, `${handler.LOG_KEY} Failed to send to ${handler.getLogInfo(payload)}.`);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return {success: false};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
await deleteProcessedEntry({db, entryId: entry.id});
|
|
87
|
-
} catch (err) {
|
|
88
|
-
await markEntryCompleted({db, entryId: entry.id});
|
|
89
|
-
logging.error({
|
|
90
|
-
system: {
|
|
91
|
-
event: 'outbox.entry.delete_failed',
|
|
92
|
-
entry_id: entry.id
|
|
93
|
-
},
|
|
94
|
-
err
|
|
95
|
-
}, `${handler.LOG_KEY} Sent to ${handler.getLogInfo(payload)} but failed to delete outbox entry ${entry.id}.`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return {success: true};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async function processEntries({db, entries}) {
|
|
102
|
-
let processed = 0;
|
|
103
|
-
let failed = 0;
|
|
104
|
-
|
|
105
|
-
for (const entry of entries) {
|
|
106
|
-
const result = await processEntry({db, entry});
|
|
107
|
-
if (result.success) {
|
|
108
|
-
processed += 1;
|
|
109
|
-
} else {
|
|
110
|
-
failed += 1;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return {processed, failed};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
module.exports = processEntries;
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
const logging = require('@tryghost/logging');
|
|
2
|
-
const db = require('../../../../data/db');
|
|
3
|
-
const MemberCreatedEvent = require('../../../../../shared/events/member-created-event');
|
|
4
|
-
const {OUTBOX_STATUSES} = require('../../../../models/outbox');
|
|
5
|
-
const {MESSAGES, MAX_ENTRIES_PER_JOB, BATCH_SIZE, OUTBOX_LOG_KEY} = require('./constants');
|
|
6
|
-
const processEntries = require('./process-entries');
|
|
7
|
-
const memberWelcomeEmailService = require('../../../member-welcome-emails/service');
|
|
8
|
-
|
|
9
|
-
async function fetchPendingEntries({batchSize, jobStartISO}) {
|
|
10
|
-
let entries = [];
|
|
11
|
-
await db.knex.transaction(async (trx) => {
|
|
12
|
-
const query = trx('outbox')
|
|
13
|
-
.where('event_type', MemberCreatedEvent.name)
|
|
14
|
-
.where('status', OUTBOX_STATUSES.PENDING)
|
|
15
|
-
.where(function () {
|
|
16
|
-
this.whereNull('last_retry_at')
|
|
17
|
-
.orWhere('last_retry_at', '<', jobStartISO);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
entries = await query
|
|
21
|
-
.orderBy('created_at', 'asc')
|
|
22
|
-
.limit(batchSize)
|
|
23
|
-
.forUpdate()
|
|
24
|
-
.select('*');
|
|
25
|
-
|
|
26
|
-
if (entries.length > 0) {
|
|
27
|
-
const ids = entries.map(e => e.id);
|
|
28
|
-
await trx('outbox')
|
|
29
|
-
.whereIn('id', ids)
|
|
30
|
-
.update({
|
|
31
|
-
status: OUTBOX_STATUSES.PROCESSING,
|
|
32
|
-
updated_at: db.knex.raw('CURRENT_TIMESTAMP')
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
return entries;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async function processOutbox() {
|
|
41
|
-
const jobStartMs = Date.now();
|
|
42
|
-
const jobStartISO = new Date(jobStartMs).toISOString().slice(0, 19).replace('T', ' ');
|
|
43
|
-
|
|
44
|
-
memberWelcomeEmailService.init();
|
|
45
|
-
try {
|
|
46
|
-
await memberWelcomeEmailService.api.loadMemberWelcomeEmails();
|
|
47
|
-
} catch (err) {
|
|
48
|
-
logging.error({
|
|
49
|
-
system: {
|
|
50
|
-
event: 'outbox.init.failed'
|
|
51
|
-
},
|
|
52
|
-
err
|
|
53
|
-
}, `${OUTBOX_LOG_KEY} Service initialization failed.`);
|
|
54
|
-
return `${OUTBOX_LOG_KEY} Job aborted: Service initialization failed`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let totalProcessed = 0;
|
|
58
|
-
let totalFailed = 0;
|
|
59
|
-
|
|
60
|
-
while (totalProcessed + totalFailed < MAX_ENTRIES_PER_JOB) {
|
|
61
|
-
const remainingCapacity = MAX_ENTRIES_PER_JOB - (totalProcessed + totalFailed);
|
|
62
|
-
const fetchSize = Math.min(BATCH_SIZE, remainingCapacity);
|
|
63
|
-
|
|
64
|
-
const entries = await fetchPendingEntries({batchSize: fetchSize, jobStartISO});
|
|
65
|
-
if (entries.length === 0) {
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const batchStartMs = Date.now();
|
|
70
|
-
const {processed, failed} = await processEntries({db, entries});
|
|
71
|
-
const batchDurationMs = Date.now() - batchStartMs;
|
|
72
|
-
const batchRate = ((processed + failed) / (Math.max(batchDurationMs, 1) / 1000)).toFixed(1);
|
|
73
|
-
|
|
74
|
-
totalProcessed += processed;
|
|
75
|
-
totalFailed += failed;
|
|
76
|
-
|
|
77
|
-
logging.info({
|
|
78
|
-
system: {
|
|
79
|
-
event: 'outbox.batch.complete',
|
|
80
|
-
entries_processed: processed,
|
|
81
|
-
entries_failed: failed,
|
|
82
|
-
duration_ms: batchDurationMs
|
|
83
|
-
}
|
|
84
|
-
}, `${OUTBOX_LOG_KEY} Batch complete: ${processed} processed, ${failed} failed in ${(batchDurationMs / 1000).toFixed(2)}s (${batchRate} entries/sec)`);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const durationMs = Date.now() - jobStartMs;
|
|
88
|
-
|
|
89
|
-
if (totalProcessed + totalFailed === 0) {
|
|
90
|
-
return `${OUTBOX_LOG_KEY} ${MESSAGES.NO_ENTRIES}`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return `${OUTBOX_LOG_KEY} Job complete: Processed ${totalProcessed} outbox entries, ${totalFailed} failed in ${(durationMs / 1000).toFixed(2)}s`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
module.exports = processOutbox;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const {parentPort} = require('worker_threads');
|
|
2
|
-
const StartOutboxProcessingEvent = require('../events/start-outbox-processing-event');
|
|
3
|
-
|
|
4
|
-
function cancel() {
|
|
5
|
-
if (parentPort) {
|
|
6
|
-
parentPort.postMessage('Outbox job cancelled before completion');
|
|
7
|
-
parentPort.postMessage('cancelled');
|
|
8
|
-
} else {
|
|
9
|
-
setTimeout(() => {
|
|
10
|
-
process.exit(0);
|
|
11
|
-
}, 1000);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (parentPort) {
|
|
16
|
-
parentPort.once('message', (message) => {
|
|
17
|
-
if (message === 'cancel') {
|
|
18
|
-
return cancel();
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
(async () => {
|
|
24
|
-
if (parentPort) {
|
|
25
|
-
parentPort.postMessage({
|
|
26
|
-
event: {
|
|
27
|
-
type: StartOutboxProcessingEvent.name
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
parentPort.postMessage('done');
|
|
31
|
-
} else {
|
|
32
|
-
setTimeout(() => {
|
|
33
|
-
process.exit(0);
|
|
34
|
-
}, 1000);
|
|
35
|
-
}
|
|
36
|
-
})();
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
declare module 'ghost-storage-base' {
|
|
2
|
-
import {RequestHandler} from 'express';
|
|
3
|
-
|
|
4
|
-
export type StorageFile = {
|
|
5
|
-
name: string;
|
|
6
|
-
path: string;
|
|
7
|
-
type?: string;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export default abstract class StorageBase {
|
|
11
|
-
protected storagePath: string;
|
|
12
|
-
getTargetDir(baseDir?: string): string;
|
|
13
|
-
getUniqueFileName(file: StorageFile, targetDir: string): Promise<string>;
|
|
14
|
-
abstract save(file: StorageFile, targetDir?: string): Promise<string>;
|
|
15
|
-
abstract saveRaw(buffer: Buffer, targetPath: string): Promise<string>;
|
|
16
|
-
abstract exists(fileName: string, targetDir: string): Promise<boolean>;
|
|
17
|
-
abstract delete(fileName: string, targetDir: string): Promise<void>;
|
|
18
|
-
abstract read(file: {path: string}): Promise<Buffer>;
|
|
19
|
-
abstract serve(): RequestHandler;
|
|
20
|
-
abstract urlToPath(url: string): string;
|
|
21
|
-
}
|
|
22
|
-
}
|