ghost 6.53.0 → 6.54.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/ghost-storage-base-3.0.0.tgz +0 -0
- package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
- package/components/tryghost-adapter-base-scheduling-0.2.0.tgz +0 -0
- package/components/tryghost-adapter-base-sso-0.1.1.tgz +0 -0
- package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
- package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
- package/components/tryghost-i18n-0.0.0.tgz +0 -0
- package/components/tryghost-kg-converters-1.2.3.tgz +0 -0
- package/components/tryghost-kg-default-nodes-2.1.3.tgz +0 -0
- package/components/tryghost-kg-lexical-html-renderer-1.4.3.tgz +0 -0
- package/core/boot.js +9 -6
- package/core/built/admin/assets/Combination-CJG7Flp-.js +41 -0
- package/core/built/admin/assets/Growth-BTP1LthE.js +3 -0
- package/core/built/admin/assets/Newsletters-CSEX0myc.js +1 -0
- package/core/built/admin/assets/Overview-BjACEsJF.js +1 -0
- package/core/built/admin/assets/{PolarAngleAxis-pciQ0MOy.js → PolarAngleAxis-BGjf7sBu.js} +1 -1
- package/core/built/admin/assets/{RadialBarChart-DWmw2PcX.js → RadialBarChart-zeFf9mBz.js} +1 -1
- package/core/built/admin/assets/Web-CxxxjCcv.js +2 -0
- package/core/built/admin/assets/account-migration-BklF2I_I.js +1 -0
- package/core/built/admin/assets/activitypub/{account-migration-BPZG37DJ.js → account-migration-CNovr6W-.js} +13 -13
- package/core/built/admin/assets/activitypub/activitypub.js +8 -8
- package/core/built/admin/assets/activitypub/{avatar-ZYco0ITb.js → avatar-B3DEDB1l.js} +10 -10
- package/core/built/admin/assets/activitypub/{avatar-flipboard-D541lc4F.js → avatar-flipboard-Cqrg0XMx.js} +3 -3
- package/core/built/admin/assets/activitypub/{bluesky-sharing-NOHUtHjl.js → bluesky-sharing-Ceslb1_M.js} +38 -37
- package/core/built/admin/assets/activitypub/{chunk-KS7C4IRE-B-GOFDPZ.js → chunk-KS7C4IRE-D4HEcEwi.js} +716 -710
- package/core/built/admin/assets/activitypub/{content-formatters-bwrp4iEO.js → content-formatters-BpQARh28.js} +229 -181
- package/core/built/admin/assets/activitypub/{copy-C7m7ovHw.js → copy-D9UWIAan.js} +2 -2
- package/core/built/admin/assets/activitypub/{dist-BqkDUQxJ2.js → dist-ByFmDSNP2.js} +64 -63
- package/core/built/admin/assets/activitypub/{dist-B5ira32t.js → dist-DHAjBcV3.js} +5 -5
- package/core/built/admin/assets/activitypub/{domain-iqE4YXwD.js → domain-C1qQvJ8C.js} +33 -33
- package/core/built/admin/assets/activitypub/{edit-profile-B8MFYh28.js → edit-profile-BcH-jEfM.js} +46 -45
- package/core/built/admin/assets/activitypub/{explore-BbdKodp3.js → explore-AxwBh9dI.js} +20 -20
- package/core/built/admin/assets/activitypub/{feed-Cl3A5owG.js → feed-BaOlbh7a.js} +15 -15
- package/core/built/admin/assets/activitypub/{field-DL6WyR-c.js → field-B7mYYQpN.js} +13 -13
- package/core/built/admin/assets/activitypub/{hash-6G3DzwL9.js → hash-BC9Q0N4c.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-YmhuBice.js → inbox-DQ4ZnC1m.js} +2 -2
- package/core/built/admin/assets/activitypub/inbox-vXez-5uJ.js +1221 -0
- package/core/built/admin/assets/activitypub/{label-DGbLjDvE.js → label-Chv5T8bw.js} +6 -6
- package/core/built/admin/assets/activitypub/layout-CziktJXo.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-qnBtk1zS.js → moderation-DtSM2i1I.js} +32 -31
- package/core/built/admin/assets/activitypub/{note-C7ZRoSJv.js → note-Dckp4S-2.js} +21 -21
- package/core/built/admin/assets/activitypub/{notifications-DiEA4b1o.js → notifications-CG5T22vg.js} +17 -17
- package/core/built/admin/assets/activitypub/{onboarding-_JVgEwgV.js → onboarding-BFDkzeR2.js} +2 -2
- package/core/built/admin/assets/activitypub/{onboarding-DG4zu3qM.js → onboarding-D6rcBdPe.js} +5 -5
- package/core/built/admin/assets/activitypub/{preferences-B3FtocnP.js → preferences-D_799jdl.js} +1607 -1606
- package/core/built/admin/assets/activitypub/{profile-D8ZJfYXB.js → profile-D2JfXBQl.js} +264 -263
- package/core/built/admin/assets/activitypub/{reply-C1vggenw.js → reply-CpdMeAO5.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-BOii-V9n.js → routes-CCHe2dQp.js} +1317 -1298
- package/core/built/admin/assets/activitypub/{separator-1gNokN5S.js → separator-BI1FLsYM.js} +4 -4
- package/core/built/admin/assets/activitypub/{settings--9Sb0nbl.js → settings-kx-9Enkz.js} +14 -14
- package/core/built/admin/assets/activitypub/{site-fkMmqv0V.js → site-x4_IjVJ0.js} +10 -10
- package/core/built/admin/assets/activitypub/{step-1-QhivSMw2.js → step-1-DIDg4aHb.js} +15 -15
- package/core/built/admin/assets/activitypub/{step-2-pMk9YwqD.js → step-2-BfGe8BYt.js} +7 -7
- package/core/built/admin/assets/activitypub/{step-3-DvmVC1fo.js → step-3-mE9spAqw.js} +12 -12
- package/core/built/admin/assets/activitypub/{tabs-Dc0FEEYD.js → tabs-CyPRQQ1N.js} +241 -237
- package/core/built/admin/assets/activitypub/{topic-filter-CuDyM5bD.js → topic-filter-DLHBZT93.js} +4 -4
- package/core/built/admin/assets/activitypub/use-activity-pub-queries-VzbN99u_.js +1957 -0
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Drx1kdAK.js → use-navigate-with-base-path-CAwXTmqH.js} +165 -175
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-BHkCHcW5.js → use-reply-chain-data-BAB6fNGt.js} +8 -8
- package/core/built/admin/assets/activitypub/users-BLeiOTHc.js +1464 -0
- package/core/built/admin/assets/activitypub/{x-BHCEe-c2.js → x-C8tAnXly.js} +2 -2
- package/core/built/admin/assets/{audience-adiFehTD.js → audience-X_XsZivI.js} +1 -1
- package/core/built/admin/assets/{automated-emails-UWM02CMr.js → automated-emails-of1MvVsv.js} +1 -1
- package/core/built/admin/assets/automations-B7-y3dXt.js +1 -0
- package/core/built/admin/assets/automations-DRFjW5fw.js +1 -0
- package/core/built/admin/assets/{avatar-flipboard-Lz3F9fNT.js → avatar-flipboard-C6Kj3Awu.js} +1 -1
- package/core/built/admin/assets/bluesky-sharing-BbbjWdzs.js +1 -0
- package/core/built/admin/assets/box-BWbhXh21.js +1 -0
- package/core/built/admin/assets/breadcrumb-B-M9Ip_2.js +1 -0
- package/core/built/admin/assets/card-DGoDJzrn.js +1 -0
- package/core/built/admin/assets/{chart-ChpW-NzQ.js → chart-BuRT2Y6p.js} +14 -14
- package/core/built/admin/assets/chart-helpers-xiSsW8r0.js +1 -0
- package/core/built/admin/assets/checkbox-EhJKHFdZ.js +1 -0
- package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js → chunk.211.6f7328d63c41536451b3.js} +2025 -2819
- package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js.LICENSE.txt → chunk.211.6f7328d63c41536451b3.js.LICENSE.txt} +1 -62
- package/core/built/admin/assets/{chunk.831.0703a12e49f51cec3f3a.js → chunk.361.3cdb584b973959e52ccc.js} +78 -85
- package/core/built/admin/assets/chunk.524.8365cd9280405c0f6216.js +25 -0
- package/core/built/admin/assets/chunk.582.61d078937e6102769f2c.js +27 -0
- package/core/built/admin/assets/code-editor-view-CZtJFGhR.js +1 -0
- package/core/built/admin/assets/comments-CvyXxOyN.js +1 -0
- package/core/built/admin/assets/container-BYz2Ed39.js +1 -0
- package/core/built/admin/assets/data-list-16rkJYYi.js +1 -0
- package/core/built/admin/assets/date-range-select-CTlyo8zW.js +1 -0
- package/core/built/admin/assets/disabled-sources-indicator-qs2GfLvl.js +1 -0
- package/core/built/admin/assets/{dist-DJ6c4_De.js → dist-2Tnz2Yfq.js} +1 -1
- package/core/built/admin/assets/{dist-CsekE4FL.js → dist-CQJY6SVY.js} +1 -1
- package/core/built/admin/assets/dist-CjY-f5Z1.js +1 -0
- package/core/built/admin/assets/dist-DGzPJ_bO.js +4 -0
- package/core/built/admin/assets/dist-DIC8yz5C.js +1 -0
- package/core/built/admin/assets/{dist-BbGrW05X.js → dist-DyViJwIy.js} +1 -1
- package/core/built/admin/assets/dist-Ndy-PuGN.js +1 -0
- package/core/built/admin/assets/dist-P_ohUlTi.js +1 -0
- package/core/built/admin/assets/domain-CPNXKVOV.js +1 -0
- package/core/built/admin/assets/dropzone-BmCXnw6J.js +5 -0
- package/core/built/admin/assets/edit-profile-SGrJve5M.js +1 -0
- package/core/built/admin/assets/editor-BOG2YPUm.js +8 -0
- package/core/built/admin/assets/empty-indicator-oX1u1Pkn.js +1 -0
- package/core/built/admin/assets/esm-CFX93H5M.js +2 -0
- package/core/built/admin/assets/explore-CUYLv9G9.js +1 -0
- package/core/built/admin/assets/feed-CPdJMttL.js +1 -0
- package/core/built/admin/assets/field-D0XISCK2.js +1 -0
- package/core/built/admin/assets/{filter-sources-v39ihhhV.js → filter-sources-Bieps75g.js} +1 -1
- package/core/built/admin/assets/filters-CuB-A7ma.js +1 -0
- package/core/built/admin/assets/filters-bXkkWro8.js +1 -0
- package/core/built/admin/assets/framework-provider-CmtnPXIT.js +4 -0
- package/core/built/admin/assets/{ghost-b57f077997b739a8ae9a70772dc016cb.js → ghost-05f9a7182ed56903dba05878a5b8422b.js} +46 -41
- package/core/built/admin/assets/ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css +1 -0
- package/core/built/admin/assets/gift-link-modal-su8MsRdg.js +1 -0
- package/core/built/admin/assets/{gift-links-CY3GwiVi.js → gift-links-nBxJjZiQ.js} +1 -1
- package/core/built/admin/assets/growth-Ba6S5FQX.js +1 -0
- package/core/built/admin/assets/hooks-BApwwBE0.js +2 -0
- package/core/built/admin/assets/{inbox-TEISAmth.js → inbox-Xx1CdnfO.js} +38 -38
- package/core/built/admin/assets/index-D8PbzuT9.css +1 -0
- package/core/built/admin/assets/index-ukW_0Uie.js +67 -0
- package/core/built/admin/assets/inline-EMAm3okk.js +1 -0
- package/core/built/admin/assets/input-group-CGOXcy4l.js +1 -0
- package/core/built/admin/assets/input-surface-BpAjZXY5.js +1 -0
- package/core/built/admin/assets/{react-dom-C6aoWSfl.js → jsx-runtime-DX3WBWVO.js} +1 -1
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +5 -2
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +2 -2
- package/core/built/admin/assets/{koenig-lexical-Di7b48ED.js → koenig-lexical-B61IALf5.js} +2 -2
- package/core/built/admin/assets/kpi-card-BlZaG1Lo.js +1 -0
- package/core/built/admin/assets/kpi-card-DCdlyaSS.js +1 -0
- package/core/built/admin/assets/kpi-helpers-DpAuS1Nb.js +1 -0
- package/core/built/admin/assets/kpi-tabs-Dme44bQS.js +1 -0
- package/core/built/admin/assets/label-dSs5aepE.js +1 -0
- package/core/built/admin/assets/label-picker-Uq91atex.js +1 -0
- package/core/built/admin/assets/{labels-GbxlXWtf.js → labels-Cyayfd-e.js} +1 -1
- package/core/built/admin/assets/layout-WUcz6tu1.js +1 -0
- package/core/built/admin/assets/limit-service-9fwD33lU.js +20 -0
- package/core/built/admin/assets/link-helpers-tOlxmuH5.js +1 -0
- package/core/built/admin/assets/list-page-B6ANtzkd.js +1 -0
- package/core/built/admin/assets/mailchimp-Ds_NQ04w.svg +9 -0
- package/core/built/admin/assets/member-custom-fields-NCzrMuba.js +1 -0
- package/core/built/admin/assets/member-detail-DPWDtYnN.js +1 -0
- package/core/built/admin/assets/members-B9rO7qr4.js +10 -0
- package/core/built/admin/assets/modals-CxRaan1J.js +31 -0
- package/core/built/admin/assets/moderation-D8zon60E.js +1 -0
- package/core/built/admin/assets/multi-select-combobox-1wYm3nle.js +1 -0
- package/core/built/admin/assets/newsletter-DbYMRxRS.js +1 -0
- package/core/built/admin/assets/{newsletters-DZm3yLj8.js → newsletters-D1jbtV-h.js} +1 -1
- package/core/built/admin/assets/note-PiWPnnrh.js +1 -0
- package/core/built/admin/assets/notifications-DEgqqB9G.js +1 -0
- package/core/built/admin/assets/nql-lang-B7faUf8D.js +19 -0
- package/core/built/admin/assets/{offers-D11QtPXX.js → offers-CrY6nSRR.js} +1 -1
- package/core/built/admin/assets/onboarding-route-BzF6HeVn.js +1 -0
- package/core/built/admin/assets/overview-DixLeIqY.js +1 -0
- package/core/built/admin/assets/page-header-op0eN36I.js +1 -0
- package/core/built/admin/assets/{pages-BnObVRrf.js → pages-BbNWFcGj.js} +1 -1
- package/core/built/admin/assets/pintura-CXOmq-5H.svg +15 -0
- package/core/built/admin/assets/post-analytics-WwRDEnrV.js +1 -0
- package/core/built/admin/assets/post-analytics-header-DsMoLx0R.js +1 -0
- package/core/built/admin/assets/{post-analytics-provider-DSfBCtnj.js → post-analytics-provider-BJCPLMIb.js} +1 -1
- package/core/built/admin/assets/post-share-modal-Dx-MEjhI.js +1 -0
- package/core/built/admin/assets/{posts-CwH8VJvB.js → posts-EWpZIjkr.js} +1 -1
- package/core/built/admin/assets/preferences-D7-j6A4C.js +5 -0
- package/core/built/admin/assets/profile-Dl69QPp0.js +1 -0
- package/core/built/admin/assets/{referrers-nxR52jPI.js → referrers-BCfFYSHc.js} +1 -1
- package/core/built/admin/assets/router-provider-C1R4AZ2o.js +1 -0
- package/core/built/admin/assets/select-C1qDZnW4.js +1 -0
- package/core/built/admin/assets/settings-BbmC_Iqq.js +4 -0
- package/core/built/admin/assets/settings-H6HxFgfI.js +1 -0
- package/core/built/admin/assets/shade-app-B3heOAfz-CGXQwWeO.js +3 -0
- package/core/built/admin/assets/share-modal-BJCadJyp.js +1 -0
- package/core/built/admin/assets/social-urls-BPL1nADp.js +8 -0
- package/core/built/admin/assets/sort-button-DyYlfYp7.js +1 -0
- package/core/built/admin/assets/source-icon-_ubRDbg_.js +1 -0
- package/core/built/admin/assets/stack-xiN0eQ6Z.js +1 -0
- package/core/built/admin/assets/stats-BQZMGMvn.js +1 -0
- package/core/built/admin/assets/stats-view-Doei-qCX.js +1 -0
- package/core/built/admin/assets/step-1-IKiLBPoC.js +1 -0
- package/core/built/admin/assets/step-2-jJ41PsDN.js +1 -0
- package/core/built/admin/assets/step-3-CaqFAEqf.js +2 -0
- package/core/built/admin/assets/switch-t-WyENU2.js +1 -0
- package/core/built/admin/assets/table-DxUL78jU.js +1 -0
- package/core/built/admin/assets/tabs-BQcJQ1ke.js +1 -0
- package/core/built/admin/assets/tags-CNujGwkT.js +1 -0
- package/core/built/admin/assets/text-DwtjwGkh.js +1 -0
- package/core/built/admin/assets/textarea-Bjccvh_E.js +1 -0
- package/core/built/admin/assets/{tiers-EghDzCKc.js → tiers-BgYLWRJv.js} +1 -1
- package/core/built/admin/assets/toggle-group-BeEpQ69p.js +1 -0
- package/core/built/admin/assets/topic-filter-Bb5MOD-1.js +1 -0
- package/core/built/admin/assets/{use-analytics-data-0l_OHtnR.js → use-analytics-data-Cds6XDjg.js} +1 -1
- package/core/built/admin/assets/use-filter-params-DjXkhO54.js +1 -0
- package/core/built/admin/assets/use-growth-stats-D8uf98-G.js +1 -0
- package/core/built/admin/assets/{use-post-referrers-DwI31Ril.js → use-post-referrers-CRtgyuXB.js} +1 -1
- package/core/built/admin/assets/use-reply-chain-data-DbKYX50v.js +1 -0
- package/core/built/admin/assets/use-simple-pagination-DC01kpo0.js +1 -0
- package/core/built/admin/assets/{use-tinybird-query-DvZBBMG7.js → use-tinybird-query-C7bQRJWw.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-CQtebkvU.js → use-tinybird-token-Az4tam7_.js} +1 -1
- package/core/built/admin/assets/{users-Pc8IRjk9.js → users-CcSCQFcQ.js} +1 -1
- package/core/built/admin/assets/virtual-list-Dhuh9fGx.js +1 -0
- package/core/built/admin/assets/web-LtHNiNBV.js +1 -0
- package/core/built/admin/index.html +22 -22
- package/core/frontend/apps/private-blogging/index.js +1 -1
- package/core/frontend/apps/private-blogging/lib/middleware.js +1 -1
- package/core/frontend/helpers/split.js +2 -1
- package/core/frontend/meta/asset-url.js +1 -1
- package/core/frontend/meta/author-image.js +1 -1
- package/core/frontend/meta/blog-logo.js +1 -1
- package/core/frontend/meta/canonical-url.js +1 -1
- package/core/frontend/meta/cover-image.js +1 -1
- package/core/frontend/meta/get-meta.js +1 -1
- package/core/frontend/meta/og-image.js +1 -1
- package/core/frontend/meta/paginated-url.js +1 -1
- package/core/frontend/meta/twitter-image.js +1 -1
- package/core/frontend/meta/url.js +1 -1
- package/core/frontend/services/assets-minification/admin-auth-assets.js +1 -1
- package/core/frontend/services/llms/handler.js +1 -1
- package/core/frontend/services/proxy.js +42 -3
- package/core/frontend/services/routing/collection-router.js +1 -1
- package/core/frontend/services/routing/controllers/email-post.js +1 -1
- package/core/frontend/services/routing/controllers/entry/markdown.js +1 -1
- package/core/frontend/services/routing/controllers/entry/markdown.ts +1 -1
- package/core/frontend/services/routing/controllers/entry.js +1 -1
- package/core/frontend/services/routing/controllers/entry.ts +1 -1
- package/core/frontend/services/routing/controllers/previews.js +6 -7
- package/core/frontend/services/routing/controllers/unsubscribe.js +7 -3
- package/core/frontend/services/routing/email-router.js +1 -1
- package/core/frontend/services/routing/events.js +12 -0
- package/core/frontend/services/routing/middleware/page-param.js +1 -1
- package/core/frontend/services/routing/parent-router.js +1 -1
- package/core/frontend/services/routing/preview-router.js +1 -1
- package/core/frontend/services/routing/router-manager.js +4 -8
- package/core/frontend/services/routing/rss-router.js +1 -1
- package/core/frontend/services/routing/static-pages-router.js +1 -1
- package/core/frontend/services/routing/static-routes-router.js +1 -1
- package/core/frontend/services/routing/taxonomy-router.js +1 -1
- package/core/frontend/services/rss/generate-feed.js +1 -1
- package/core/frontend/services/sitemap/base-site-map-generator.js +23 -4
- package/core/frontend/services/sitemap/site-map-index-generator.js +1 -1
- package/core/frontend/services/sitemap/site-map-manager.js +14 -8
- package/core/frontend/services/sitemap/utils.js +1 -1
- package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +1 -1
- package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +1 -1
- package/core/frontend/utils/images.js +1 -1
- package/core/frontend/web/middleware/admin-toolbar.js +1 -1
- package/core/frontend/web/middleware/handle-image-sizes.js +2 -2
- package/core/frontend/web/middleware/redirect-ghost-to-admin.js +1 -1
- package/core/frontend/web/routers/serve-favicon.js +1 -1
- package/core/frontend/web/routers/serve-public-file.js +1 -1
- package/core/frontend/web/site.js +5 -5
- package/core/server/adapters/cache/AdapterCacheMemoryTTL.js +2 -2
- package/core/server/adapters/cache/MemoryCache.js +2 -2
- package/core/server/adapters/cache/Redis.js +1 -1
- package/core/server/adapters/cache/index.js +1 -1
- package/core/server/adapters/lib/redis/AdapterCacheRedis.js +2 -2
- package/core/server/adapters/route-settings/FileStore.js +2 -8
- package/core/server/adapters/route-settings/FileStore.ts +1 -6
- package/core/server/adapters/route-settings/S3RouteSettingsStore.js +206 -0
- package/core/server/adapters/route-settings/S3RouteSettingsStore.ts +199 -0
- package/core/server/adapters/route-settings/utils.js +13 -0
- package/core/server/adapters/route-settings/utils.ts +7 -0
- package/core/server/adapters/scheduling/deps.d.ts +0 -2
- package/core/server/adapters/scheduling/error-capture.js +76 -0
- package/core/server/adapters/scheduling/error-capture.ts +91 -0
- package/core/server/adapters/scheduling/utils.js +18 -34
- package/core/server/adapters/scheduling/utils.ts +36 -0
- package/core/server/adapters/storage/LocalFilesStorage.js +13 -11
- package/core/server/adapters/storage/LocalFilesStorage.ts +24 -0
- package/core/server/adapters/storage/LocalImagesStorage.js +14 -12
- package/core/server/adapters/storage/LocalImagesStorage.ts +24 -0
- package/core/server/adapters/storage/LocalMediaStorage.js +13 -11
- package/core/server/adapters/storage/LocalMediaStorage.ts +24 -0
- package/core/server/adapters/storage/LocalStorageBase.js +107 -167
- package/core/server/adapters/storage/LocalStorageBase.ts +342 -0
- package/core/server/adapters/storage/S3Storage.js +2 -2
- package/core/server/adapters/storage/S3Storage.ts +1 -1
- package/core/server/adapters/storage/utils.js +36 -50
- package/core/server/adapters/storage/utils.ts +60 -0
- package/core/server/api/endpoints/authentication.js +1 -1
- package/core/server/api/endpoints/db.js +6 -0
- package/core/server/api/endpoints/featurebase.js +1 -1
- package/core/server/api/endpoints/files.js +2 -2
- package/core/server/api/endpoints/images.js +2 -2
- package/core/server/api/endpoints/libraries.d.ts +0 -1
- package/core/server/api/endpoints/media.js +8 -5
- package/core/server/api/endpoints/member-custom-fields.js +4 -1
- package/core/server/api/endpoints/member-custom-fields.ts +4 -1
- package/core/server/api/endpoints/members.js +25 -28
- package/core/server/api/endpoints/pages.js +6 -1
- package/core/server/api/endpoints/posts.js +28 -3
- package/core/server/api/endpoints/search-index-public.js +4 -3
- package/core/server/api/endpoints/search-index.js +5 -4
- package/core/server/api/endpoints/settings-public.js +1 -1
- package/core/server/api/endpoints/settings.js +3 -1
- package/core/server/api/endpoints/utils/serializers/input/utils/url.js +9 -1
- package/core/server/api/endpoints/utils/serializers/output/default.js +7 -0
- package/core/server/api/endpoints/utils/serializers/output/files.js +1 -1
- package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +4 -1
- package/core/server/api/endpoints/utils/serializers/output/media.js +1 -1
- package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +7 -4
- package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.ts +8 -4
- package/core/server/api/endpoints/utils/serializers/output/members.js +27 -106
- package/core/server/api/endpoints/utils/serializers/output/pages.js +7 -0
- package/core/server/api/endpoints/utils/serializers/output/posts.js +13 -0
- package/core/server/api/endpoints/utils/serializers/output/utils/url.js +1 -1
- package/core/server/api/endpoints/utils/validators/input/members.js +2 -52
- package/core/server/data/db/backup.js +1 -1
- package/core/server/data/exporter/export-filename.js +2 -1
- package/core/server/data/importer/handlers/image.js +3 -3
- package/core/server/data/importer/import-manager.js +6 -4
- package/core/server/data/importer/importers/content-file-importer.js +2 -2
- package/core/server/data/importer/importers/data/revue-subscriber-importer.js +6 -10
- package/core/server/data/importer/importers/json-to-html.js +24 -4
- package/core/server/data/migrations/utils/schema.js +4 -2
- package/core/server/data/migrations/versions/6.54/2026-07-19-16-59-00-add-content-import-permission.js +10 -0
- package/core/server/data/migrations/versions/6.54/2026-07-20-13-59-21-drop-email-tracked-sent-count-from-automation-action-revisions.js +7 -0
- package/core/server/data/migrations/versions/6.54/2026-07-21-01-58-20-add-automation-run-steps-poller-index.js +3 -0
- package/core/server/data/migrations/versions/6.54/2026-07-21-21-08-15-add-automated-email-recipients-mailgun-message-id-index.js +3 -0
- package/core/server/data/migrations/versions/6.54/2026-07-22-10-41-08-add-click-tracking-to-automated-email-recipients.js +13 -0
- package/core/server/data/migrations/versions/6.54/2026-07-22-15-10-30-add-email-clicked-count-to-automation-action-revisions.js +7 -0
- package/core/server/data/migrations/versions/6.54/2026-07-23-10-24-18-add-automation-action-revision-to-redirects.js +9 -0
- package/core/server/data/schema/commands.js +37 -3
- package/core/server/data/schema/fixtures/fixtures.json +7 -0
- package/core/server/data/schema/lib/default-index-name.js +20 -0
- package/core/server/data/schema/schema.js +40 -17
- package/core/server/data/seeders/data-generator.js +4 -2
- package/core/server/lib/image/image-size.js +7 -23
- package/core/server/lib/image/image-utils.js +16 -2
- package/core/server/lib/image/index.js +4 -4
- package/core/server/lib/lexical.js +3 -3
- package/core/server/lib/mobiledoc.js +2 -2
- package/core/server/lib/request-external.js +1 -1
- package/core/server/lib/validate-password.js +1 -1
- package/core/server/models/action.js +9 -0
- package/core/server/models/base/plugins/generate-slug.js +1 -1
- package/core/server/models/collection.js +1 -1
- package/core/server/models/custom-theme-setting.js +1 -1
- package/core/server/models/member.js +73 -0
- package/core/server/models/newsletter.js +1 -1
- package/core/server/models/post.js +19 -5
- package/core/server/models/posts-meta.js +1 -1
- package/core/server/models/redirect.js +1 -1
- package/core/server/models/settings.js +1 -1
- package/core/server/models/snippet.js +1 -1
- package/core/server/models/tag.js +1 -1
- package/core/server/models/user.js +47 -71
- package/core/server/models/welcome-email-automated-email.js +1 -1
- package/core/server/services/activitypub/activity-pub-service-wrapper.js +1 -1
- package/core/server/services/adapter-manager/adapter-manager.js +5 -1
- package/core/server/services/adapter-manager/adapter-manager.ts +7 -2
- package/core/server/services/adapter-manager/index.js +18 -15
- package/core/server/services/adapter-manager/index.ts +23 -17
- package/core/server/services/adapter-manager/utils.js +124 -14
- package/core/server/services/adapter-manager/utils.ts +130 -14
- package/core/server/services/api-version-compatibility/mw-version-rewrites.js +1 -1
- package/core/server/services/audience-feedback/index.js +1 -1
- package/core/server/services/auth/passwordreset.js +1 -1
- package/core/server/services/auth/session/express-session.js +1 -1
- package/core/server/services/auth/session/index.js +2 -2
- package/core/server/services/auth/session/session-service.js +29 -2
- package/core/server/services/automations/automations-api.js +8 -25
- package/core/server/services/automations/automations-api.ts +8 -37
- package/core/server/services/automations/automations-repository.ts +16 -0
- package/core/server/services/automations/database-automations-repository.js +37 -4
- package/core/server/services/automations/database-automations-repository.ts +41 -4
- package/core/server/services/automations/poll.js +16 -12
- package/core/server/services/automations/poll.ts +17 -15
- package/core/server/services/automations/service.js +1 -1
- package/core/server/services/automations/service.ts +3 -13
- package/core/server/services/automations/welcome-email-automation-poll.js +2 -1
- package/core/server/services/comments/comments-service-emails.js +4 -1
- package/core/server/services/comments/index.js +1 -1
- package/core/server/services/custom-redirects/index.js +2 -2
- package/core/server/services/email-analytics/email-analytics-service-wrapper.js +14 -13
- package/core/server/services/email-analytics/email-analytics-service.js +1 -1
- package/core/server/services/email-analytics/events/start-email-analytics-job-event.js +11 -15
- package/core/server/services/email-analytics/events/start-email-analytics-job-event.ts +15 -0
- package/core/server/services/email-analytics/index.js +2 -3
- package/core/server/services/email-analytics/index.ts +1 -2
- package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.js +1 -6
- package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.ts +0 -9
- package/core/server/services/email-analytics/jobs/fetch-latest/index.js +1 -1
- package/core/server/services/email-analytics/jobs/index.js +0 -2
- package/core/server/services/email-service/email-service-wrapper.js +1 -1
- package/core/server/services/email-service/email-service.js +20 -4
- package/core/server/services/explore-ping/explore-ping-service.js +24 -39
- package/core/server/services/explore-ping/explore-ping-service.ts +198 -0
- package/core/server/services/explore-ping/index.js +11 -11
- package/core/server/services/explore-ping/index.ts +42 -0
- package/core/server/services/gifts/gift-reminder-scheduler.js +1 -1
- package/core/server/services/gifts/gift-reminder-scheduler.ts +1 -1
- package/core/server/services/gifts/gift-service-wrapper.js +1 -1
- package/core/server/services/identity-tokens/identity-token-service-wrapper.js +1 -1
- package/core/server/services/indexnow-ping/constants.js +30 -0
- package/core/server/services/indexnow-ping/constants.ts +32 -0
- package/core/server/services/indexnow-ping/index.js +29 -253
- package/core/server/services/indexnow-ping/index.ts +37 -0
- package/core/server/services/indexnow-ping/indexnow-ping-service.js +229 -0
- package/core/server/services/indexnow-ping/indexnow-ping-service.ts +319 -0
- package/core/server/services/invites/index.js +1 -1
- package/core/server/services/lib/mailgun-client.js +3 -3
- package/core/server/services/link-redirection/index.js +2 -2
- package/core/server/services/link-redirection/link-redirect-repository.js +1 -1
- package/core/server/services/link-redirection/link-redirect.js +12 -13
- package/core/server/services/link-redirection/link-redirect.ts +22 -0
- package/core/server/services/link-redirection/link-redirects-service.js +1 -1
- package/core/server/services/link-tracking/full-post-link.js +2 -2
- package/core/server/services/link-tracking/index.js +1 -1
- package/core/server/services/mail/ghost-mailer.js +1 -1
- package/core/server/services/mail/index.js +1 -1
- package/core/server/services/media-inliner/external-media-inliner.js +2 -2
- package/core/server/services/media-inliner/service.js +4 -3
- package/core/server/services/member-attribution/index.js +1 -1
- package/core/server/services/member-welcome-emails/service.js +1 -1
- package/core/server/services/members/api.js +8 -2
- package/core/server/services/members/import-export/config.js +30 -0
- package/core/server/services/members/import-export/config.ts +34 -0
- package/core/server/services/members/import-export/csv/index.js +10 -0
- package/core/server/services/members/import-export/csv/index.ts +2 -0
- package/core/server/services/members/import-export/csv/parse.js +64 -0
- package/core/server/services/members/import-export/csv/parse.ts +69 -0
- package/core/server/services/members/import-export/csv/serialize.js +13 -0
- package/core/server/services/members/import-export/csv/serialize.ts +18 -0
- package/core/server/services/members/import-export/export/exporter.js +202 -0
- package/core/server/services/members/import-export/export/exporter.ts +325 -0
- package/core/server/services/members/import-export/import/completion-email.js +65 -0
- package/core/server/services/members/import-export/import/completion-email.ts +119 -0
- package/core/server/services/members/import-export/import/importer.js +276 -0
- package/core/server/services/members/import-export/import/importer.ts +430 -0
- package/core/server/services/members/import-export/import/reader.js +32 -0
- package/core/server/services/members/import-export/import/reader.ts +33 -0
- package/core/server/services/members/import-export/import/row.js +33 -0
- package/core/server/services/members/import-export/import/row.ts +52 -0
- package/core/server/services/members/import-export/import/spool.js +30 -0
- package/core/server/services/members/import-export/import/spool.ts +38 -0
- package/core/server/services/members/import-export/index.js +90 -0
- package/core/server/services/members/import-export/index.ts +118 -0
- package/core/server/services/members/members-api/controllers/router-controller.js +7 -0
- package/core/server/services/members/members-api/members-api.js +4 -2
- package/core/server/services/members/members-api/repositories/event-repository.js +13 -2
- package/core/server/services/members/members-api/services/member-bread-service.js +42 -19
- package/core/server/services/members/middleware.js +1 -1
- package/core/server/services/members/service.js +28 -17
- package/core/server/services/members/stripe-connect.js +1 -1
- package/core/server/services/members-custom-fields/actions.js +3 -0
- package/core/server/services/members-custom-fields/actions.ts +6 -2
- package/core/server/services/members-custom-fields/config.js +34 -0
- package/core/server/services/members-custom-fields/config.ts +38 -0
- package/core/server/services/members-custom-fields/definitions-service.js +156 -21
- package/core/server/services/members-custom-fields/definitions-service.ts +170 -25
- package/core/server/services/members-custom-fields/index.js +16 -3
- package/core/server/services/members-custom-fields/index.ts +17 -3
- package/core/server/services/members-custom-fields/values-service.js +56 -10
- package/core/server/services/members-custom-fields/values-service.ts +62 -10
- package/core/server/services/mentions/mention-sending-service.js +22 -2
- package/core/server/services/mentions/service.js +21 -5
- package/core/server/services/newsletters/index.js +1 -1
- package/core/server/services/oembed/oembed-service.js +122 -33
- package/core/server/services/oembed/service.js +4 -2
- package/core/server/services/offers/service.js +1 -1
- package/core/server/services/post-scheduling/index.js +4 -3
- package/core/server/services/post-scheduling/index.ts +4 -3
- package/core/server/services/post-scheduling/post-scheduling.js +1 -1
- package/core/server/services/post-scheduling/post-scheduling.ts +1 -1
- package/core/server/services/posts/post-email-handler.js +13 -6
- package/core/server/services/posts/post-scheduling.js +1 -1
- package/core/server/services/posts/posts-exporter.js +6 -4
- package/core/server/services/posts/posts-service-instance.js +1 -1
- package/core/server/services/posts/posts-service.js +4 -4
- package/core/server/services/posts-public/service.js +1 -1
- package/core/server/services/public-config/site.js +1 -1
- package/core/server/services/recommendations/recommendation-service-wrapper.js +1 -1
- package/core/server/services/recommendations/service/libraries.d.ts +0 -2
- package/core/server/services/route-settings/dynamic-routing-service.js +2 -3
- package/core/server/services/route-settings/index.js +1 -1
- package/core/server/services/route-settings/route-settings-parser.js +134 -124
- package/core/server/services/route-settings/route-settings-parser.ts +160 -125
- package/core/server/services/route-settings/validation-errors.js +178 -0
- package/core/server/services/route-settings/validation-errors.ts +196 -0
- package/core/server/services/settings/settings-service.js +2 -2
- package/core/server/services/settings-helpers/index.js +1 -1
- package/core/server/services/slack-notifications/service.js +1 -1
- package/core/server/services/slack-ping/constants.js +16 -0
- package/core/server/services/slack-ping/constants.ts +15 -0
- package/core/server/services/slack-ping/index.js +26 -204
- package/core/server/services/slack-ping/index.ts +35 -0
- package/core/server/services/slack-ping/slack-ping-service.js +214 -0
- package/core/server/services/slack-ping/slack-ping-service.ts +296 -0
- package/core/server/services/staff/index.js +1 -1
- package/core/server/services/stats/posts-stats-service.js +1 -1
- package/core/server/services/stats/service.js +1 -1
- package/core/server/services/stripe/service.js +1 -1
- package/core/server/services/tags-public/service.js +1 -1
- package/core/server/services/themes/storage.js +9 -0
- package/core/server/services/themes/theme-storage.js +1 -1
- package/core/server/services/themes/validate.js +1 -1
- package/core/server/services/update-check/index.js +1 -1
- package/core/server/services/url/lazy-url-service.js +66 -6
- package/core/server/services/url/lazy-url-service.ts +73 -6
- package/core/server/services/url/url-generator.js +1 -1
- package/core/server/services/url/url-service-facade.js +68 -3
- package/core/server/services/url/url-service-facade.ts +79 -4
- package/core/server/services/url/url-service.js +1 -1
- package/core/server/services/url/urls.js +1 -1
- package/core/server/services/webhooks/index.js +19 -2
- package/core/server/services/webhooks/listen.js +6 -11
- package/core/server/services/webhooks/payload.js +1 -3
- package/core/server/services/webhooks/serialize.js +16 -1
- package/core/server/web/admin/app.js +1 -1
- package/core/server/web/admin/middleware/redirect-admin-urls.js +1 -1
- package/core/server/web/api/endpoints/admin/routes.js +1 -0
- package/core/server/web/api/middleware/cors.js +1 -1
- package/core/server/web/api/middleware/upload.js +4 -0
- package/core/server/web/gift-preview/controller.js +1 -1
- package/core/server/web/shared/middleware/redirect-amp-urls.js +1 -1
- package/core/server/web/shared/middleware/uncapitalise.js +2 -2
- package/core/server/web/shared/middleware/url-redirects.js +1 -1
- package/core/shared/config/defaults.json +10 -2
- package/core/shared/config/overrides.json +4 -0
- package/core/shared/express.js +6 -1
- package/core/shared/labs.js +2 -1
- package/core/shared/url-utils.js +19 -15
- package/core/shared/url-utils.ts +20 -0
- package/ghost.js +0 -1
- package/package.json +30 -35
- package/pnpm-lock.yaml +681 -2789
- package/pnpm-workspace.yaml +31 -17
- package/components/tryghost-adapter-base-scheduling-0.0.0.tgz +0 -0
- package/components/tryghost-adapter-base-sso-0.0.0.tgz +0 -0
- package/core/built/admin/assets/Combination--5EZGaDs.js +0 -43
- package/core/built/admin/assets/Growth-C0NoKcHQ.js +0 -3
- package/core/built/admin/assets/Newsletters-Ed8kDjdy.js +0 -1
- package/core/built/admin/assets/Overview-CArPgRZt.js +0 -1
- package/core/built/admin/assets/Web-CjjYoVM3.js +0 -2
- package/core/built/admin/assets/account-migration-mfa5mNI9.js +0 -1
- package/core/built/admin/assets/activitypub/inbox-B3rjKMTv.js +0 -1221
- package/core/built/admin/assets/activitypub/layout-jcurg3rU.js +0 -1
- package/core/built/admin/assets/activitypub/use-activity-pub-queries-yqGRcnLn.js +0 -2569
- package/core/built/admin/assets/activitypub/users-CfyHIsTG.js +0 -1316
- package/core/built/admin/assets/automations-DkUnxNdv.js +0 -1
- package/core/built/admin/assets/automations-vjXofmV_.js +0 -1
- package/core/built/admin/assets/bluesky-sharing-T-pO3RcP.js +0 -1
- package/core/built/admin/assets/breadcrumb-CekPYTCn.js +0 -1
- package/core/built/admin/assets/button--i2uMDDn.js +0 -4
- package/core/built/admin/assets/card-CSWz_BXq.js +0 -1
- package/core/built/admin/assets/chart-helpers-C_4Ka_vT.js +0 -1
- package/core/built/admin/assets/chunk.524.8ce2c741473e2f0929dc.js +0 -25
- package/core/built/admin/assets/chunk.582.453459d6228d2955408b.js +0 -27
- package/core/built/admin/assets/code-editor-view-BfkwQto2.js +0 -1
- package/core/built/admin/assets/command-K75Jzs0G.js +0 -1
- package/core/built/admin/assets/comments-BEIi1DH-.js +0 -1
- package/core/built/admin/assets/container-BNXvlcjA.js +0 -1
- package/core/built/admin/assets/data-list-BmK5QMab.js +0 -1
- package/core/built/admin/assets/date-range-select-5sKzwbt7.js +0 -1
- package/core/built/admin/assets/disabled-sources-indicator-L_ssJTNr.js +0 -1
- package/core/built/admin/assets/dist-BBIJuyPg.js +0 -1
- package/core/built/admin/assets/dist-BHE0dp6o.js +0 -1
- package/core/built/admin/assets/dist-CT46_f_J.js +0 -1
- package/core/built/admin/assets/dist-DW0QXQO3.js +0 -1
- package/core/built/admin/assets/dist-DxFLceO5.js +0 -1
- package/core/built/admin/assets/dist-QcACAOAD.js +0 -1
- package/core/built/admin/assets/dist-duxRDcQu.js +0 -177
- package/core/built/admin/assets/domain-CLaPZ9Rc.js +0 -1
- package/core/built/admin/assets/dropzone-E0bSX4_a.js +0 -5
- package/core/built/admin/assets/edit-profile-DqNPKaA4.js +0 -1
- package/core/built/admin/assets/editor-CkLXQDRp.js +0 -8
- package/core/built/admin/assets/empty-indicator-BTtOlgIo.js +0 -1
- package/core/built/admin/assets/esm-TSfGW7nz.js +0 -2
- package/core/built/admin/assets/explore-BEstLxKr.js +0 -1
- package/core/built/admin/assets/feed-C58p2voG.js +0 -1
- package/core/built/admin/assets/field-BSbDUHPv.js +0 -1
- package/core/built/admin/assets/filters-BgYv8Gt7.js +0 -1
- package/core/built/admin/assets/filters-DvenFkmK.js +0 -1
- package/core/built/admin/assets/framework-provider-jQktxm9P.js +0 -4
- package/core/built/admin/assets/ghost-dark-8590dea6cd695ff90f27d262c4464538.css +0 -1
- package/core/built/admin/assets/gift-link-modal-BPjXkEFt.js +0 -1
- package/core/built/admin/assets/growth-D4JNiVTe.js +0 -1
- package/core/built/admin/assets/hooks-Cjxexi_I.js +0 -2
- package/core/built/admin/assets/index-BacwlcOy.js +0 -67
- package/core/built/admin/assets/index-DxRNHH0o.css +0 -1
- package/core/built/admin/assets/inline-C22rnPro.js +0 -1
- package/core/built/admin/assets/input-group-CKfrILLP.js +0 -1
- package/core/built/admin/assets/jsx-runtime-CtMZ-PAS.js +0 -1
- package/core/built/admin/assets/kpi-card-DZxQKAIb.js +0 -1
- package/core/built/admin/assets/kpi-card-FidQ5zg3.js +0 -1
- package/core/built/admin/assets/kpi-helpers-C5T8Vaf1.js +0 -1
- package/core/built/admin/assets/kpi-tabs-_VRK6hGV.js +0 -1
- package/core/built/admin/assets/label-Cza7hPgn.js +0 -1
- package/core/built/admin/assets/label-picker-DgC_zLaw.js +0 -1
- package/core/built/admin/assets/layout-BxsXnKFX.js +0 -1
- package/core/built/admin/assets/limit-service-CTurluJQ.js +0 -20
- package/core/built/admin/assets/link-helpers-C3Gqy2cz.js +0 -1
- package/core/built/admin/assets/list-page-BtqCnow_.js +0 -1
- package/core/built/admin/assets/member-custom-fields-9uXFBqSt.js +0 -1
- package/core/built/admin/assets/member-detail-Dq6ZDIxo.js +0 -1
- package/core/built/admin/assets/members-CUWD9jal.js +0 -10
- package/core/built/admin/assets/modals-CIdwHVga.js +0 -31
- package/core/built/admin/assets/moderation-DTt04UDA.js +0 -1
- package/core/built/admin/assets/newsletter-cC8vcc9h.js +0 -1
- package/core/built/admin/assets/note-DZU0IY9e.js +0 -1
- package/core/built/admin/assets/notifications-NoHpBHJ4.js +0 -1
- package/core/built/admin/assets/nql-lang-CvCSOQG3.js +0 -19
- package/core/built/admin/assets/onboarding-route-Deg2hNm8.js +0 -1
- package/core/built/admin/assets/overview-BQPt_9w3.js +0 -1
- package/core/built/admin/assets/page-header-D6bEqPo2.js +0 -1
- package/core/built/admin/assets/post-analytics-header-BPw_B2_D.js +0 -1
- package/core/built/admin/assets/post-analytics-kp2_--XO.js +0 -1
- package/core/built/admin/assets/post-share-modal-Cave3Z4W.js +0 -1
- package/core/built/admin/assets/preferences-C7h3j_uy.js +0 -5
- package/core/built/admin/assets/profile-B2x4q2oB.js +0 -1
- package/core/built/admin/assets/router-provider-5fsX1CYn.js +0 -1
- package/core/built/admin/assets/select-PhPjIBBT.js +0 -1
- package/core/built/admin/assets/settings-D5P9Gwgo.js +0 -6
- package/core/built/admin/assets/settings-zUOzQV5I.js +0 -1
- package/core/built/admin/assets/share-modal-EfpfbuWF.js +0 -1
- package/core/built/admin/assets/social-urls-DgAF08Xc.js +0 -18
- package/core/built/admin/assets/sort-button-WOQYJm2H.js +0 -1
- package/core/built/admin/assets/source-icon-hm8Cj-Gx.js +0 -1
- package/core/built/admin/assets/stats-CnQDb62m.js +0 -1
- package/core/built/admin/assets/stats-view-CCfTJgSe.js +0 -1
- package/core/built/admin/assets/step-1-BGlhY4DS.js +0 -1
- package/core/built/admin/assets/step-2-D3sDEyFH.js +0 -1
- package/core/built/admin/assets/step-3-CvZoUdsc.js +0 -2
- package/core/built/admin/assets/switch-CNjkOmwz.js +0 -1
- package/core/built/admin/assets/table-C5nZYPnW.js +0 -1
- package/core/built/admin/assets/tabs-dtOcExye.js +0 -1
- package/core/built/admin/assets/tags-Dhm0FB_g.js +0 -1
- package/core/built/admin/assets/textarea-CeKw3wmV.js +0 -1
- package/core/built/admin/assets/toggle-group-DfhZIMTW.js +0 -1
- package/core/built/admin/assets/topic-filter-Cxe1Il41.js +0 -1
- package/core/built/admin/assets/typeof-Ca-duI-z.js +0 -1
- package/core/built/admin/assets/use-filter-params-Bub6BqNy.js +0 -1
- package/core/built/admin/assets/use-growth-stats-BJORomv0.js +0 -1
- package/core/built/admin/assets/use-reply-chain-data-B89YjVoo.js +0 -1
- package/core/built/admin/assets/use-simple-pagination-BL2SYXKi.js +0 -1
- package/core/built/admin/assets/virtual-list-DNJOSK9I.js +0 -1
- package/core/built/admin/assets/web-BHUE3YQc.js +0 -1
- package/core/server/adapters/scheduling/scheduling-base.js +0 -5
- package/core/server/adapters/sso/SSOBase.js +0 -5
- package/core/server/adapters/storage/index.js +0 -17
- package/core/server/services/mail/templates/newsletter.html +0 -876
- package/core/server/services/members/exporter/query.js +0 -206
- package/core/server/services/members/importer/index.js +0 -30
- package/core/server/services/members/importer/labels.js +0 -125
- package/core/server/services/members/importer/members-csv-importer.js +0 -502
- /package/core/server/services/members/{importer → import-export/import}/email-template.js +0 -0
- /package/core/server/services/members/{importer/members-csv-importer-stripe-utils.js → import-export/import/stripe-utils.js} +0 -0
|
@@ -25,6 +25,7 @@ export interface WaitAction {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export interface AutomationEmailStats {
|
|
28
|
+
email_clicked_count: number;
|
|
28
29
|
email_sent_count: number;
|
|
29
30
|
email_opened_count: number;
|
|
30
31
|
opened_rate: number | null;
|
|
@@ -81,6 +82,17 @@ export type AutomatedEmailEvents = {
|
|
|
81
82
|
automationActionRevisionId: string;
|
|
82
83
|
};
|
|
83
84
|
|
|
85
|
+
export type RecordEmailSentOptions = Readonly<{
|
|
86
|
+
automationActionRevisionId: string;
|
|
87
|
+
mailgunMessageId?: string;
|
|
88
|
+
memberEmail: string;
|
|
89
|
+
memberId: string;
|
|
90
|
+
memberName: string | null;
|
|
91
|
+
memberUuid: string;
|
|
92
|
+
trackClicks: boolean;
|
|
93
|
+
trackOpens: boolean;
|
|
94
|
+
}>;
|
|
95
|
+
|
|
84
96
|
type AutomationStepBase = {
|
|
85
97
|
id: string;
|
|
86
98
|
locked_by: string;
|
|
@@ -167,6 +179,10 @@ export interface AutomationsRepository {
|
|
|
167
179
|
step: Pick<AutomationStepToRun, 'id' | 'locked_by'>,
|
|
168
180
|
retryAt: Readonly<Date>
|
|
169
181
|
): Promise<boolean>;
|
|
182
|
+
/**
|
|
183
|
+
* Record a sent email and increment its action revision's sent count.
|
|
184
|
+
*/
|
|
185
|
+
recordEmailSent(options: RecordEmailSentOptions): Promise<void>;
|
|
170
186
|
/**
|
|
171
187
|
* Fetch sent emails by their Mailgun IDs.
|
|
172
188
|
*/
|
|
@@ -94,6 +94,29 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier })
|
|
|
94
94
|
async retryStep(step, retryAt) {
|
|
95
95
|
return await knex.transaction(trx => retryStep(trx, step, retryAt));
|
|
96
96
|
},
|
|
97
|
+
async recordEmailSent(options) {
|
|
98
|
+
await knex.transaction(async (trx) => {
|
|
99
|
+
await trx('automation_action_revisions')
|
|
100
|
+
.where('id', options.automationActionRevisionId)
|
|
101
|
+
.update({
|
|
102
|
+
email_sent_count: trx.raw('COALESCE(??, 0) + ?', ['email_sent_count', 1])
|
|
103
|
+
});
|
|
104
|
+
const now = toDatabaseDate(new Date());
|
|
105
|
+
await trx('automated_email_recipients').insert({
|
|
106
|
+
id: (0, bson_objectid_1.default)().toHexString(),
|
|
107
|
+
member_id: options.memberId,
|
|
108
|
+
member_uuid: options.memberUuid,
|
|
109
|
+
member_email: options.memberEmail,
|
|
110
|
+
member_name: options.memberName,
|
|
111
|
+
automation_action_revision_id: options.automationActionRevisionId,
|
|
112
|
+
...(options.mailgunMessageId ? { mailgun_message_id: options.mailgunMessageId } : {}),
|
|
113
|
+
track_clicks: options.trackClicks,
|
|
114
|
+
track_opens: options.trackOpens,
|
|
115
|
+
created_at: now,
|
|
116
|
+
updated_at: now
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
},
|
|
97
120
|
async getAutomatedEmailRecipientsByMailgunIds(mailgunMessageIds) {
|
|
98
121
|
if (mailgunMessageIds.length === 0) {
|
|
99
122
|
return [];
|
|
@@ -128,7 +151,10 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier })
|
|
|
128
151
|
newOpensPerRevision.set(automationActionRevisionId, (newOpensPerRevision.get(automationActionRevisionId) ?? 0) + 1);
|
|
129
152
|
}
|
|
130
153
|
}
|
|
131
|
-
|
|
154
|
+
// Keep lock acquisition order consistent across concurrent transactions to avoid deadlocks.
|
|
155
|
+
const revisions = [...newOpensPerRevision.entries()]
|
|
156
|
+
.sort(([left], [right]) => left.localeCompare(right));
|
|
157
|
+
for (const [id, opens] of revisions) {
|
|
132
158
|
await trx('automation_action_revisions')
|
|
133
159
|
.where({ id })
|
|
134
160
|
.update({
|
|
@@ -329,6 +355,7 @@ async function fetchAndLockSteps(trx, limit) {
|
|
|
329
355
|
.innerJoin('automations as automation', 'automation.id', 'run.automation_id')
|
|
330
356
|
.innerJoin('automation_action_revisions as revision', 'revision.id', 'step.automation_action_revision_id')
|
|
331
357
|
.innerJoin('automation_actions as action', 'action.id', 'revision.action_id')
|
|
358
|
+
.whereIn('step.id', candidateIds)
|
|
332
359
|
.where('step.locked_by', lockId)
|
|
333
360
|
.orderBy([
|
|
334
361
|
'step.ready_at',
|
|
@@ -342,13 +369,14 @@ async function fetchAndLockSteps(trx, limit) {
|
|
|
342
369
|
}
|
|
343
370
|
async function findNextPendingReadyAt(trx, staleLockCutoff) {
|
|
344
371
|
const row = await trx('automation_run_steps')
|
|
345
|
-
.
|
|
372
|
+
.select({ next_ready_at: 'ready_at' })
|
|
346
373
|
.where('status', 'pending')
|
|
347
374
|
.where((builder) => {
|
|
348
375
|
builder
|
|
349
376
|
.whereNull('locked_by')
|
|
350
377
|
.orWhere('locked_at', '<', toDatabaseDate(staleLockCutoff));
|
|
351
378
|
})
|
|
379
|
+
.orderBy('ready_at')
|
|
352
380
|
.first();
|
|
353
381
|
return row?.next_ready_at ? new Date(row.next_ready_at) : null;
|
|
354
382
|
}
|
|
@@ -874,6 +902,7 @@ async function loadActionStats(trx, actionIds) {
|
|
|
874
902
|
const rows = await trx('automation_action_revisions')
|
|
875
903
|
.select('action_id')
|
|
876
904
|
.sum({
|
|
905
|
+
email_clicked_count: 'email_clicked_count',
|
|
877
906
|
email_sent_count: 'email_sent_count',
|
|
878
907
|
email_opened_count: 'email_opened_count'
|
|
879
908
|
})
|
|
@@ -925,22 +954,26 @@ function buildActionPayload(row, stats) {
|
|
|
925
954
|
}
|
|
926
955
|
}
|
|
927
956
|
const EMPTY_EMAIL_STATS = {
|
|
957
|
+
email_clicked_count: 0,
|
|
928
958
|
email_sent_count: 0,
|
|
929
959
|
email_opened_count: 0,
|
|
930
960
|
opened_rate: null,
|
|
931
961
|
clicked_rate: null
|
|
932
962
|
};
|
|
933
963
|
function buildEmailStats(row) {
|
|
964
|
+
const emailClickedCount = row.email_clicked_count ?? 0;
|
|
934
965
|
const emailSentCount = row.email_sent_count ?? 0;
|
|
935
966
|
const emailOpenedCount = row.email_opened_count ?? 0;
|
|
936
967
|
return {
|
|
968
|
+
email_clicked_count: emailClickedCount,
|
|
937
969
|
email_sent_count: emailSentCount,
|
|
938
970
|
email_opened_count: emailOpenedCount,
|
|
939
971
|
opened_rate: emailSentCount
|
|
940
972
|
? Math.round(emailOpenedCount / emailSentCount * 100)
|
|
941
973
|
: null,
|
|
942
|
-
|
|
943
|
-
|
|
974
|
+
clicked_rate: emailSentCount
|
|
975
|
+
? Math.round(emailClickedCount / emailSentCount * 100)
|
|
976
|
+
: null
|
|
944
977
|
};
|
|
945
978
|
}
|
|
946
979
|
function requireValue(row, field) {
|
|
@@ -65,6 +65,7 @@ interface ActionRow {
|
|
|
65
65
|
|
|
66
66
|
type ActionStatsRow = {
|
|
67
67
|
action_id: string;
|
|
68
|
+
email_clicked_count: number | null;
|
|
68
69
|
email_sent_count: number | null;
|
|
69
70
|
email_opened_count: number | null;
|
|
70
71
|
};
|
|
@@ -224,6 +225,31 @@ export function createDatabaseAutomationsRepository({
|
|
|
224
225
|
return await knex.transaction(trx => retryStep(trx, step, retryAt));
|
|
225
226
|
},
|
|
226
227
|
|
|
228
|
+
async recordEmailSent(options): Promise<void> {
|
|
229
|
+
await knex.transaction(async (trx) => {
|
|
230
|
+
await trx('automation_action_revisions')
|
|
231
|
+
.where('id', options.automationActionRevisionId)
|
|
232
|
+
.update({
|
|
233
|
+
email_sent_count: trx.raw('COALESCE(??, 0) + ?', ['email_sent_count', 1])
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const now = toDatabaseDate(new Date());
|
|
237
|
+
await trx('automated_email_recipients').insert({
|
|
238
|
+
id: ObjectId().toHexString(),
|
|
239
|
+
member_id: options.memberId,
|
|
240
|
+
member_uuid: options.memberUuid,
|
|
241
|
+
member_email: options.memberEmail,
|
|
242
|
+
member_name: options.memberName,
|
|
243
|
+
automation_action_revision_id: options.automationActionRevisionId,
|
|
244
|
+
...(options.mailgunMessageId ? {mailgun_message_id: options.mailgunMessageId} : {}),
|
|
245
|
+
track_clicks: options.trackClicks,
|
|
246
|
+
track_opens: options.trackOpens,
|
|
247
|
+
created_at: now,
|
|
248
|
+
updated_at: now
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
|
|
227
253
|
async getAutomatedEmailRecipientsByMailgunIds(mailgunMessageIds) {
|
|
228
254
|
if (mailgunMessageIds.length === 0) {
|
|
229
255
|
return [];
|
|
@@ -266,7 +292,11 @@ export function createDatabaseAutomationsRepository({
|
|
|
266
292
|
}
|
|
267
293
|
}
|
|
268
294
|
|
|
269
|
-
|
|
295
|
+
// Keep lock acquisition order consistent across concurrent transactions to avoid deadlocks.
|
|
296
|
+
const revisions = [...newOpensPerRevision.entries()]
|
|
297
|
+
.sort(([left], [right]) => left.localeCompare(right));
|
|
298
|
+
|
|
299
|
+
for (const [id, opens] of revisions) {
|
|
270
300
|
await trx('automation_action_revisions')
|
|
271
301
|
.where({id})
|
|
272
302
|
.update({
|
|
@@ -542,6 +572,7 @@ async function fetchAndLockSteps(trx: Knex.Transaction, limit: number): Promise<
|
|
|
542
572
|
.innerJoin('automations as automation', 'automation.id', 'run.automation_id')
|
|
543
573
|
.innerJoin('automation_action_revisions as revision', 'revision.id', 'step.automation_action_revision_id')
|
|
544
574
|
.innerJoin('automation_actions as action', 'action.id', 'revision.action_id')
|
|
575
|
+
.whereIn('step.id', candidateIds)
|
|
545
576
|
.where('step.locked_by', lockId)
|
|
546
577
|
.orderBy([
|
|
547
578
|
'step.ready_at',
|
|
@@ -557,13 +588,14 @@ async function fetchAndLockSteps(trx: Knex.Transaction, limit: number): Promise<
|
|
|
557
588
|
|
|
558
589
|
async function findNextPendingReadyAt(trx: Knex.Transaction, staleLockCutoff: Readonly<Date>): Promise<Date | null> {
|
|
559
590
|
const row = await trx('automation_run_steps')
|
|
560
|
-
.
|
|
591
|
+
.select({next_ready_at: 'ready_at'})
|
|
561
592
|
.where('status', 'pending')
|
|
562
593
|
.where((builder) => {
|
|
563
594
|
builder
|
|
564
595
|
.whereNull('locked_by')
|
|
565
596
|
.orWhere('locked_at', '<', toDatabaseDate(staleLockCutoff));
|
|
566
597
|
})
|
|
598
|
+
.orderBy('ready_at')
|
|
567
599
|
.first();
|
|
568
600
|
return row?.next_ready_at ? new Date(row.next_ready_at) : null;
|
|
569
601
|
}
|
|
@@ -1233,6 +1265,7 @@ async function loadActionStats(
|
|
|
1233
1265
|
const rows: ActionStatsRow[] = await trx('automation_action_revisions')
|
|
1234
1266
|
.select('action_id')
|
|
1235
1267
|
.sum({
|
|
1268
|
+
email_clicked_count: 'email_clicked_count',
|
|
1236
1269
|
email_sent_count: 'email_sent_count',
|
|
1237
1270
|
email_opened_count: 'email_opened_count'
|
|
1238
1271
|
})
|
|
@@ -1288,6 +1321,7 @@ function buildActionPayload(row: ActionRow, stats: AutomationEmailStats | null):
|
|
|
1288
1321
|
}
|
|
1289
1322
|
|
|
1290
1323
|
const EMPTY_EMAIL_STATS: AutomationEmailStats = {
|
|
1324
|
+
email_clicked_count: 0,
|
|
1291
1325
|
email_sent_count: 0,
|
|
1292
1326
|
email_opened_count: 0,
|
|
1293
1327
|
opened_rate: null,
|
|
@@ -1295,16 +1329,19 @@ const EMPTY_EMAIL_STATS: AutomationEmailStats = {
|
|
|
1295
1329
|
};
|
|
1296
1330
|
|
|
1297
1331
|
function buildEmailStats(row: ActionStatsRow): AutomationEmailStats {
|
|
1332
|
+
const emailClickedCount = row.email_clicked_count ?? 0;
|
|
1298
1333
|
const emailSentCount = row.email_sent_count ?? 0;
|
|
1299
1334
|
const emailOpenedCount = row.email_opened_count ?? 0;
|
|
1300
1335
|
return {
|
|
1336
|
+
email_clicked_count: emailClickedCount,
|
|
1301
1337
|
email_sent_count: emailSentCount,
|
|
1302
1338
|
email_opened_count: emailOpenedCount,
|
|
1303
1339
|
opened_rate: emailSentCount
|
|
1304
1340
|
? Math.round(emailOpenedCount / emailSentCount * 100)
|
|
1305
1341
|
: null,
|
|
1306
|
-
|
|
1307
|
-
|
|
1342
|
+
clicked_rate: emailSentCount
|
|
1343
|
+
? Math.round(emailClickedCount / emailSentCount * 100)
|
|
1344
|
+
: null
|
|
1308
1345
|
};
|
|
1309
1346
|
}
|
|
1310
1347
|
|
|
@@ -112,6 +112,7 @@ const processStep = async ({ automationsApi, memberWelcomeEmailService, schedule
|
|
|
112
112
|
break;
|
|
113
113
|
}
|
|
114
114
|
memberWelcomeEmailService.init();
|
|
115
|
+
const trackClicks = Boolean(settingsCache.get('email_track_clicks'));
|
|
115
116
|
const trackOpens = Boolean(settingsCache.get('email_track_opens'));
|
|
116
117
|
const sendResult = await memberWelcomeEmailService.api.sendAutomationEmail({
|
|
117
118
|
email: {
|
|
@@ -138,6 +139,7 @@ const processStep = async ({ automationsApi, memberWelcomeEmailService, schedule
|
|
|
138
139
|
memberId: step.member_id,
|
|
139
140
|
memberName: member.get('name'),
|
|
140
141
|
memberUuid: member.get('uuid'),
|
|
142
|
+
trackClicks,
|
|
141
143
|
trackOpens: trackOpensForRecipient
|
|
142
144
|
});
|
|
143
145
|
}
|
|
@@ -151,18 +153,20 @@ const processStep = async ({ automationsApi, memberWelcomeEmailService, schedule
|
|
|
151
153
|
}
|
|
152
154
|
}, `[AUTOMATIONS] Failed to record automated email recipient for step ${step.id}`);
|
|
153
155
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
156
|
+
if (mailgunMessageId) {
|
|
157
|
+
try {
|
|
158
|
+
await scheduleAutomationEmailAnalyticsJob();
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
logging_1.default.error({
|
|
162
|
+
err,
|
|
163
|
+
system: {
|
|
164
|
+
event: 'automations.poll.analytics_scheduling_failed',
|
|
165
|
+
member_id: step.member_id,
|
|
166
|
+
step_id: step.id
|
|
167
|
+
}
|
|
168
|
+
}, `[AUTOMATIONS] Failed to schedule email analytics job for step ${step.id}`);
|
|
169
|
+
}
|
|
166
170
|
}
|
|
167
171
|
break;
|
|
168
172
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {AutomationStepToRun, AutomationsRepository} from './automations-repository';
|
|
2
|
-
import type {RecordEmailSentOptions} from './automations-api';
|
|
3
2
|
import {getMailgunMessageId} from './mailgun-message-id';
|
|
4
3
|
import logging from '@tryghost/logging';
|
|
5
4
|
import errors from '@tryghost/errors';
|
|
@@ -44,10 +43,9 @@ type PollOptions = {
|
|
|
44
43
|
'fetchAndLockSteps' |
|
|
45
44
|
'finishStepAndEnqueueNext' |
|
|
46
45
|
'markStepTerminal' |
|
|
46
|
+
'recordEmailSent' |
|
|
47
47
|
'retryStep'
|
|
48
|
-
|
|
49
|
-
recordEmailSent(options: RecordEmailSentOptions): Promise<void>;
|
|
50
|
-
};
|
|
48
|
+
>;
|
|
51
49
|
enqueueAnotherPollAt: (date: Readonly<Date>) => unknown;
|
|
52
50
|
scheduleAutomationEmailAnalyticsJob: () => Promise<void>;
|
|
53
51
|
memberWelcomeEmailService: MemberWelcomeEmailService;
|
|
@@ -185,6 +183,7 @@ const processStep = async ({
|
|
|
185
183
|
break;
|
|
186
184
|
}
|
|
187
185
|
memberWelcomeEmailService.init();
|
|
186
|
+
const trackClicks = Boolean(settingsCache.get('email_track_clicks'));
|
|
188
187
|
const trackOpens = Boolean(settingsCache.get('email_track_opens'));
|
|
189
188
|
const sendResult = await memberWelcomeEmailService.api.sendAutomationEmail({
|
|
190
189
|
email: {
|
|
@@ -211,6 +210,7 @@ const processStep = async ({
|
|
|
211
210
|
memberId: step.member_id,
|
|
212
211
|
memberName: member.get('name'),
|
|
213
212
|
memberUuid: member.get('uuid'),
|
|
213
|
+
trackClicks,
|
|
214
214
|
trackOpens: trackOpensForRecipient
|
|
215
215
|
});
|
|
216
216
|
} catch (err) {
|
|
@@ -223,17 +223,19 @@ const processStep = async ({
|
|
|
223
223
|
}
|
|
224
224
|
}, `[AUTOMATIONS] Failed to record automated email recipient for step ${step.id}`);
|
|
225
225
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
226
|
+
if (mailgunMessageId) {
|
|
227
|
+
try {
|
|
228
|
+
await scheduleAutomationEmailAnalyticsJob();
|
|
229
|
+
} catch (err) {
|
|
230
|
+
logging.error({
|
|
231
|
+
err,
|
|
232
|
+
system: {
|
|
233
|
+
event: 'automations.poll.analytics_scheduling_failed',
|
|
234
|
+
member_id: step.member_id,
|
|
235
|
+
step_id: step.id
|
|
236
|
+
}
|
|
237
|
+
}, `[AUTOMATIONS] Failed to schedule email analytics job for step ${step.id}`);
|
|
238
|
+
}
|
|
237
239
|
}
|
|
238
240
|
break;
|
|
239
241
|
}
|
|
@@ -45,7 +45,7 @@ const promises_1 = require("node:timers/promises");
|
|
|
45
45
|
const soonest_timer_1 = require("../../lib/soonest-timer");
|
|
46
46
|
// @ts-expect-error This module currently lacks type definitions.
|
|
47
47
|
const jobs_1 = __importDefault(require("../email-analytics/jobs"));
|
|
48
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
48
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
49
49
|
const logging = require('@tryghost/logging');
|
|
50
50
|
const { getSignedAdminToken } = require('../../adapters/scheduling/utils');
|
|
51
51
|
const StartAutomationsPollEvent = require('./events/start-automations-poll-event');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
+
import type {SchedulerAdapter} from '@tryghost/adapter-base-scheduling';
|
|
2
3
|
import type {InternalKeys} from '../internal-keys';
|
|
3
4
|
// @ts-expect-error @tryghost/domain-events currently lacks type declarations.
|
|
4
5
|
import type DomainEvents from '@tryghost/domain-events';
|
|
@@ -10,29 +11,18 @@ import {SoonestTimer} from '../../lib/soonest-timer';
|
|
|
10
11
|
// @ts-expect-error This module currently lacks type definitions.
|
|
11
12
|
import emailAnalyticsJobs from '../email-analytics/jobs';
|
|
12
13
|
|
|
13
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
14
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
14
15
|
const logging = require('@tryghost/logging');
|
|
15
16
|
const {getSignedAdminToken} = require('../../adapters/scheduling/utils');
|
|
16
17
|
const StartAutomationsPollEvent = require('./events/start-automations-poll-event');
|
|
17
18
|
const {welcomeEmailAutomationPoll} = require('./welcome-email-automation-poll');
|
|
18
19
|
const memberWelcomeEmailService = require('../member-welcome-emails/service');
|
|
19
20
|
|
|
20
|
-
type SchedulerAdapter = {
|
|
21
|
-
schedule(job: {
|
|
22
|
-
extra: {
|
|
23
|
-
httpMethod: string;
|
|
24
|
-
};
|
|
25
|
-
time: number;
|
|
26
|
-
url: string;
|
|
27
|
-
}): void;
|
|
28
|
-
register(rescheduler: {rescheduleAll: () => unknown}): void;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
21
|
type AutomationsServiceOptions = {
|
|
32
22
|
apiUrl: string;
|
|
33
23
|
domainEvents: Pick<DomainEvents, 'dispatch' | 'subscribe'>;
|
|
34
24
|
internalKeys: InternalKeys;
|
|
35
|
-
schedulerAdapter: SchedulerAdapter
|
|
25
|
+
schedulerAdapter: Pick<SchedulerAdapter, 'schedule' | 'register'>;
|
|
36
26
|
};
|
|
37
27
|
|
|
38
28
|
const scheduleAutomationEmailAnalyticsJob = () => (
|
|
@@ -235,7 +235,8 @@ async function processRun({
|
|
|
235
235
|
member_uuid: member.get('uuid'),
|
|
236
236
|
member_email: member.get('email'),
|
|
237
237
|
member_name: member.get('name'),
|
|
238
|
-
track_opens: false
|
|
238
|
+
track_opens: false,
|
|
239
|
+
track_clicks: false
|
|
239
240
|
}, {transacting});
|
|
240
241
|
|
|
241
242
|
await markExited(run.id, 'finished', transacting);
|
|
@@ -26,7 +26,10 @@ class CommentsServiceEmails {
|
|
|
26
26
|
*/
|
|
27
27
|
getPostUrl(post, commentId) {
|
|
28
28
|
const postData = toPlain(post);
|
|
29
|
-
|
|
29
|
+
// Comments live on pages as well as posts; the URL service routes by
|
|
30
|
+
// the passed type, so a page typed 'posts' resolves to /404/.
|
|
31
|
+
const routerType = postData.type === 'page' ? 'pages' : 'posts';
|
|
32
|
+
const baseUrl = this.urlService.facade.getUrlForResource({...postData, type: routerType}, {absolute: true});
|
|
30
33
|
return `${baseUrl}#ghost-comments-${commentId}`;
|
|
31
34
|
}
|
|
32
35
|
|
|
@@ -11,7 +11,7 @@ class CommentsServiceWrapper {
|
|
|
11
11
|
const mailer = new GhostMailer();
|
|
12
12
|
const settingsCache = require('../../../shared/settings-cache');
|
|
13
13
|
const urlService = require('../url');
|
|
14
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
14
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
15
15
|
const membersService = require('../members');
|
|
16
16
|
const db = require('../../data/db');
|
|
17
17
|
const settingsHelpers = require('../settings-helpers');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const config = require('../../../shared/config');
|
|
2
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
3
|
-
const adapterManager = require('../adapter-manager');
|
|
2
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
3
|
+
const adapterManager = require('../adapter-manager').default;
|
|
4
4
|
|
|
5
5
|
const DynamicRedirectManager = require('../lib/dynamic-redirect-manager');
|
|
6
6
|
const {RedirectsService} = require('./redirects-service');
|
|
@@ -8,6 +8,7 @@ const domainEvents = require('@tryghost/domain-events');
|
|
|
8
8
|
|
|
9
9
|
class EmailAnalyticsServiceWrapper {
|
|
10
10
|
/** @type {string} */ #logName;
|
|
11
|
+
#fetching = false;
|
|
11
12
|
#restoredSchedule = false;
|
|
12
13
|
|
|
13
14
|
get #logPrefix() {
|
|
@@ -128,9 +129,9 @@ class EmailAnalyticsServiceWrapper {
|
|
|
128
129
|
logging.warn(`${this.#logPrefix} Opened events processing is ${lagMinutes.toFixed(1)} minutes behind (threshold: ${lagThreshold})`);
|
|
129
130
|
}
|
|
130
131
|
|
|
131
|
-
const
|
|
132
|
+
const fetchStartedAt = Date.now();
|
|
132
133
|
const fetchResult = await this.service.fetchLatestOpenedEvents({maxEvents});
|
|
133
|
-
const totalDuration = Date.now() -
|
|
134
|
+
const totalDuration = Date.now() - fetchStartedAt;
|
|
134
135
|
|
|
135
136
|
this._logJobCompletion('latest-opened', fetchResult, totalDuration);
|
|
136
137
|
|
|
@@ -138,9 +139,9 @@ class EmailAnalyticsServiceWrapper {
|
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
async fetchLatestNonOpenedEvents({maxEvents} = {maxEvents: Infinity}) {
|
|
141
|
-
const
|
|
142
|
+
const fetchStartedAt = Date.now();
|
|
142
143
|
const fetchResult = await this.service.fetchLatestNonOpenedEvents({maxEvents});
|
|
143
|
-
const totalDuration = Date.now() -
|
|
144
|
+
const totalDuration = Date.now() - fetchStartedAt;
|
|
144
145
|
|
|
145
146
|
this._logJobCompletion('latest', fetchResult, totalDuration);
|
|
146
147
|
|
|
@@ -148,9 +149,9 @@ class EmailAnalyticsServiceWrapper {
|
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
async fetchMissing({maxEvents} = {maxEvents: Infinity}) {
|
|
151
|
-
const
|
|
152
|
+
const fetchStartedAt = Date.now();
|
|
152
153
|
const fetchResult = await this.service.fetchMissing({maxEvents});
|
|
153
|
-
const totalDuration = Date.now() -
|
|
154
|
+
const totalDuration = Date.now() - fetchStartedAt;
|
|
154
155
|
|
|
155
156
|
this._logJobCompletion('missing', fetchResult, totalDuration);
|
|
156
157
|
|
|
@@ -162,9 +163,9 @@ class EmailAnalyticsServiceWrapper {
|
|
|
162
163
|
return 0;
|
|
163
164
|
}
|
|
164
165
|
|
|
165
|
-
const
|
|
166
|
+
const fetchStartedAt = Date.now();
|
|
166
167
|
const fetchResult = await this.service.fetchScheduled({maxEvents});
|
|
167
|
-
const totalDuration = Date.now() -
|
|
168
|
+
const totalDuration = Date.now() - fetchStartedAt;
|
|
168
169
|
|
|
169
170
|
this._logJobCompletion('scheduled', fetchResult, totalDuration);
|
|
170
171
|
|
|
@@ -177,11 +178,11 @@ class EmailAnalyticsServiceWrapper {
|
|
|
177
178
|
await this.service.restoreScheduled();
|
|
178
179
|
}
|
|
179
180
|
|
|
180
|
-
if (this
|
|
181
|
+
if (this.#fetching) {
|
|
181
182
|
logging.info(`Email analytics fetch for ${this.#logName} already running, skipping`);
|
|
182
183
|
return;
|
|
183
184
|
}
|
|
184
|
-
this
|
|
185
|
+
this.#fetching = true;
|
|
185
186
|
|
|
186
187
|
// NOTE: Data shows we can process ~2500 events per minute on Pro for a large-ish db (150k members).
|
|
187
188
|
// This can vary locally, but we should be conservative with the number of events we fetch.
|
|
@@ -216,18 +217,18 @@ class EmailAnalyticsServiceWrapper {
|
|
|
216
217
|
logging.info(`${this.#logPrefix} Job complete - No events`);
|
|
217
218
|
}
|
|
218
219
|
|
|
219
|
-
this
|
|
220
|
+
this.#fetching = false;
|
|
220
221
|
} catch (e) {
|
|
221
222
|
logging.error(e, `Error while fetching email analytics for ${this.#logName}`);
|
|
222
223
|
|
|
223
224
|
// Log again only the error, otherwise we lose the stack trace
|
|
224
225
|
logging.error(e);
|
|
225
226
|
}
|
|
226
|
-
this
|
|
227
|
+
this.#fetching = false;
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
_restartFetch(reason) {
|
|
230
|
-
this
|
|
231
|
+
this.#fetching = false;
|
|
231
232
|
logging.info(`${this.#logPrefix} Restarting fetch due to ${reason}`);
|
|
232
233
|
this.startFetch();
|
|
233
234
|
}
|
|
@@ -105,7 +105,7 @@ module.exports = class EmailAnalyticsService {
|
|
|
105
105
|
* @param {object} dependencies
|
|
106
106
|
* @param {object} dependencies.queries
|
|
107
107
|
* @param {object} dependencies.provider
|
|
108
|
-
* @param {PrometheusClient} dependencies.prometheusClient
|
|
108
|
+
* @param {PrometheusClient} [dependencies.prometheusClient]
|
|
109
109
|
* @param {() => BatchEventProcessor} dependencies.createEventProcessor
|
|
110
110
|
* @param {JobNames} dependencies.jobNames
|
|
111
111
|
* @param {CursorSeed} dependencies.cursorSeed
|
|
@@ -1,22 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StartEmailAnalyticsJobEvent = void 0;
|
|
1
4
|
/**
|
|
2
5
|
* 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
6
|
* We simply emit this event in the job manager and listen for it on the main thread.
|
|
4
7
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* @param {Date} timestamp
|
|
9
|
-
*/
|
|
10
|
-
constructor(data, timestamp) {
|
|
11
|
-
this.data = data;
|
|
8
|
+
class StartEmailAnalyticsJobEvent {
|
|
9
|
+
timestamp;
|
|
10
|
+
constructor(timestamp) {
|
|
12
11
|
this.timestamp = timestamp;
|
|
13
12
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* @param {any} [data]
|
|
17
|
-
* @param {Date} [timestamp]
|
|
18
|
-
*/
|
|
19
|
-
static create(data, timestamp) {
|
|
20
|
-
return new StartEmailAnalyticsJobEvent(data, timestamp ?? new Date);
|
|
13
|
+
static create(timestamp = new Date()) {
|
|
14
|
+
return new StartEmailAnalyticsJobEvent(timestamp);
|
|
21
15
|
}
|
|
22
|
-
}
|
|
16
|
+
}
|
|
17
|
+
exports.StartEmailAnalyticsJobEvent = StartEmailAnalyticsJobEvent;
|
|
18
|
+
;
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
export class StartEmailAnalyticsJobEvent {
|
|
6
|
+
readonly timestamp: Date;
|
|
7
|
+
|
|
8
|
+
constructor(timestamp: Date) {
|
|
9
|
+
this.timestamp = timestamp;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static create(timestamp = new Date()) {
|
|
13
|
+
return new StartEmailAnalyticsJobEvent(timestamp);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -59,8 +59,7 @@ const domain_events_1 = __importDefault(require("@tryghost/domain-events"));
|
|
|
59
59
|
const prometheus_client_1 = __importDefault(require("../../../shared/prometheus-client"));
|
|
60
60
|
// @ts-expect-error This module lacks type definitions.
|
|
61
61
|
const queries_1 = __importDefault(require("./lib/queries"));
|
|
62
|
-
|
|
63
|
-
const start_email_analytics_job_event_1 = __importDefault(require("./events/start-email-analytics-job-event"));
|
|
62
|
+
const start_email_analytics_job_event_1 = require("./events/start-email-analytics-job-event");
|
|
64
63
|
const start_automation_email_analytics_job_event_1 = require("./events/start-automation-email-analytics-job-event");
|
|
65
64
|
const constants_1 = require("../member-welcome-emails/constants");
|
|
66
65
|
const automationsApi = __importStar(require("../automations/automations-api"));
|
|
@@ -93,7 +92,7 @@ const init = () => {
|
|
|
93
92
|
newsletterMailgunTags.push(config_1.default.get('bulkEmail:mailgun:tag'));
|
|
94
93
|
}
|
|
95
94
|
exports.newsletters.init({
|
|
96
|
-
event: start_email_analytics_job_event_1.
|
|
95
|
+
event: start_email_analytics_job_event_1.StartEmailAnalyticsJobEvent,
|
|
97
96
|
mailgunTags: newsletterMailgunTags,
|
|
98
97
|
jobNames: {
|
|
99
98
|
latestNonOpened: 'email-analytics-latest-others',
|
|
@@ -20,8 +20,7 @@ import domainEvents from '@tryghost/domain-events';
|
|
|
20
20
|
import prometheusClient from '../../../shared/prometheus-client';
|
|
21
21
|
// @ts-expect-error This module lacks type definitions.
|
|
22
22
|
import queries from './lib/queries';
|
|
23
|
-
|
|
24
|
-
import StartEmailAnalyticsJobEvent from './events/start-email-analytics-job-event';
|
|
23
|
+
import {StartEmailAnalyticsJobEvent} from './events/start-email-analytics-job-event';
|
|
25
24
|
import {StartAutomationEmailAnalyticsJobEvent} from './events/start-automation-email-analytics-job-event';
|
|
26
25
|
import {AUTOMATION_EMAIL_TAG} from '../member-welcome-emails/constants';
|
|
27
26
|
import * as automationsApi from '../automations/automations-api';
|