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
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const messages = {
|
|
2
|
+
requestFailedError: 'The {service} service was unable to send a ping request, your site will continue to function.',
|
|
3
|
+
requestFailedHelp: 'If you get this error repeatedly, please seek help on {url}.'
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export const INDEXNOW_LOG_KEY = '[indexnow]';
|
|
7
|
+
|
|
8
|
+
// IndexNow endpoint - this routes to all participating search engines
|
|
9
|
+
export const INDEXNOW_ENDPOINT = 'https://api.indexnow.org/indexnow';
|
|
10
|
+
|
|
11
|
+
export const defaultPostSlugs = [
|
|
12
|
+
'welcome',
|
|
13
|
+
'the-editor',
|
|
14
|
+
'using-tags',
|
|
15
|
+
'managing-users',
|
|
16
|
+
'private-sites',
|
|
17
|
+
'advanced-markdown',
|
|
18
|
+
'themes',
|
|
19
|
+
'coming-soon'
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
// Fields that affect how the post appears in search engine results
|
|
23
|
+
export const seoFields = [
|
|
24
|
+
'html', // Post content
|
|
25
|
+
'title', // Post title (appears in SERP)
|
|
26
|
+
'slug', // URL path
|
|
27
|
+
'meta_title', // Custom meta title
|
|
28
|
+
'meta_description', // Meta description (appears in SERP)
|
|
29
|
+
'canonical_url', // Canonical URL
|
|
30
|
+
'status' // Published status change
|
|
31
|
+
];
|
|
32
|
+
|
|
@@ -1,257 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* Protocol: https://www.indexnow.org/documentation
|
|
10
|
-
*
|
|
11
|
-
* How it works:
|
|
12
|
-
* 1. Ghost generates a unique API key (32-char hex string)
|
|
13
|
-
* 2. The key is stored in settings and served at /{key}.txt for verification
|
|
14
|
-
* 3. When a post is published/updated, we send a GET request to IndexNow:
|
|
15
|
-
* GET https://api.indexnow.org/indexnow?url={post-url}&key={key}&keyLocation={key-file-url}
|
|
16
|
-
* 4. IndexNow distributes the notification to participating search engines
|
|
17
|
-
* (Bing, Yandex, Seznam.cz, Naver, and others)
|
|
18
|
-
*
|
|
19
|
-
* The API key file is served by the middleware in:
|
|
20
|
-
* ghost/core/core/frontend/web/middleware/serve-indexnow-key.js
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
const urlService = require('../url');
|
|
24
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
25
|
-
const errors = require('@tryghost/errors');
|
|
26
|
-
const tpl = require('@tryghost/tpl');
|
|
27
|
-
const logging = require('@tryghost/logging');
|
|
28
|
-
const request = require('@tryghost/request');
|
|
29
|
-
const settingsCache = require('../../../shared/settings-cache');
|
|
30
|
-
const config = require('../../../shared/config');
|
|
31
|
-
const labs = require('../../../shared/labs');
|
|
32
|
-
const events = require('../../lib/common/events');
|
|
33
|
-
|
|
34
|
-
const messages = {
|
|
35
|
-
requestFailedError: 'The {service} service was unable to send a ping request, your site will continue to function.',
|
|
36
|
-
requestFailedHelp: 'If you get this error repeatedly, please seek help on {url}.'
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const INDEXNOW_LOG_KEY = '[indexnow]';
|
|
40
|
-
|
|
41
|
-
const defaultPostSlugs = [
|
|
42
|
-
'welcome',
|
|
43
|
-
'the-editor',
|
|
44
|
-
'using-tags',
|
|
45
|
-
'managing-users',
|
|
46
|
-
'private-sites',
|
|
47
|
-
'advanced-markdown',
|
|
48
|
-
'themes',
|
|
49
|
-
'coming-soon'
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
// IndexNow endpoint - this routes to all participating search engines
|
|
53
|
-
const INDEXNOW_ENDPOINT = 'https://api.indexnow.org/indexnow';
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Get existing API key from settings
|
|
57
|
-
* The key is auto-generated on boot by the settings service
|
|
58
|
-
* @returns {string|null} The API key or null if not set
|
|
59
|
-
*/
|
|
60
|
-
function getApiKey() {
|
|
61
|
-
return settingsCache.get('indexnow_api_key') || null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Ping IndexNow with a URL
|
|
66
|
-
* @param {Object} post - The post object
|
|
67
|
-
*/
|
|
68
|
-
async function ping(post) {
|
|
69
|
-
// Skip pages - only ping for posts
|
|
70
|
-
if (post.type === 'page') {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Skip if site is private
|
|
75
|
-
if (settingsCache.get('is_private')) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Skip if IndexNow pings are disabled via privacy config
|
|
80
|
-
if (config.isPrivacyDisabled('useIndexNow')) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Skip if IndexNow is not enabled in labs
|
|
85
|
-
if (!labs.isSet('indexnow')) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Don't ping for the default posts
|
|
90
|
-
if (defaultPostSlugs.indexOf(post.slug) > -1) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
let url = null;
|
|
95
|
-
try {
|
|
96
|
-
url = urlService.facade.getUrlForResource({...post, type: 'posts'}, {absolute: true});
|
|
97
|
-
|
|
98
|
-
if (!url || url.endsWith('/404/')) {
|
|
99
|
-
logging.warn({
|
|
100
|
-
event: {name: 'indexnow.unresolved_url'},
|
|
101
|
-
post: {id: post.id, slug: post.slug, url}
|
|
102
|
-
}, `${INDEXNOW_LOG_KEY} Skipped ping - post has no resolvable URL`);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Get the API key (auto-generated on boot by settings service)
|
|
107
|
-
const key = getApiKey();
|
|
108
|
-
if (!key) {
|
|
109
|
-
logging.warn({
|
|
110
|
-
event: {name: 'indexnow.api_key_missing'},
|
|
111
|
-
post: {id: post.id, slug: post.slug}
|
|
112
|
-
}, `${INDEXNOW_LOG_KEY} API key not available`);
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const indexnow_ping_service_1 = require("./indexnow-ping-service");
|
|
4
|
+
class IndexNowPingServiceWrapper {
|
|
5
|
+
service;
|
|
6
|
+
init() {
|
|
7
|
+
if (this.service) {
|
|
8
|
+
// Already done
|
|
113
9
|
return;
|
|
114
10
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
message: `IndexNow returned unexpected status: ${response.statusCode}`,
|
|
136
|
-
statusCode: response.statusCode
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
logging.info({
|
|
141
|
-
event: {name: 'indexnow.pinged'},
|
|
142
|
-
post: {id: post.id, slug: post.slug, url},
|
|
143
|
-
http: {response: {status_code: response.statusCode}}
|
|
144
|
-
}, `${INDEXNOW_LOG_KEY} Successfully pinged ${url}`);
|
|
145
|
-
} catch (err) {
|
|
146
|
-
// Log errors but don't throw - IndexNow failures shouldn't disrupt publishing
|
|
147
|
-
const statusCode = err.statusCode ?? err.response?.statusCode ?? null;
|
|
148
|
-
|
|
149
|
-
let eventName;
|
|
150
|
-
let error;
|
|
151
|
-
if (statusCode === 429) {
|
|
152
|
-
// Rate limited by IndexNow - we have no retry/backoff, so the ping is dropped
|
|
153
|
-
eventName = 'indexnow.rate_limited';
|
|
154
|
-
error = new errors.TooManyRequestsError({
|
|
155
|
-
err,
|
|
156
|
-
message: err.message,
|
|
157
|
-
context: tpl(messages.requestFailedError, {service: 'IndexNow'}),
|
|
158
|
-
help: tpl(messages.requestFailedHelp, {url: 'https://ghost.org/docs/'})
|
|
159
|
-
});
|
|
160
|
-
} else if (statusCode === 422 || statusCode === 403) {
|
|
161
|
-
eventName = 'indexnow.key_validation_failed';
|
|
162
|
-
error = new errors.ValidationError({
|
|
163
|
-
err,
|
|
164
|
-
message: 'IndexNow key validation failed',
|
|
165
|
-
context: tpl(messages.requestFailedError, {service: 'IndexNow'}),
|
|
166
|
-
help: 'Ensure your IndexNow API key file is accessible at the correct URL'
|
|
167
|
-
});
|
|
168
|
-
} else {
|
|
169
|
-
eventName = 'indexnow.ping_failed';
|
|
170
|
-
error = new errors.InternalServerError({
|
|
171
|
-
err: err,
|
|
172
|
-
message: err.message,
|
|
173
|
-
context: tpl(messages.requestFailedError, {service: 'IndexNow'}),
|
|
174
|
-
help: tpl(messages.requestFailedHelp, {url: 'https://ghost.org/docs/'})
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
logging.warn({
|
|
179
|
-
event: {name: eventName},
|
|
180
|
-
post: {id: post.id, slug: post.slug, url},
|
|
181
|
-
http: {response: {status_code: statusCode}},
|
|
182
|
-
err: error
|
|
183
|
-
}, `${INDEXNOW_LOG_KEY} ${error.message}`);
|
|
11
|
+
// Wire up all the dependencies
|
|
12
|
+
const settingsCache = require('../../../shared/settings-cache');
|
|
13
|
+
const config = require('../../../shared/config');
|
|
14
|
+
const labs = require('../../../shared/labs');
|
|
15
|
+
const urlService = require('../url');
|
|
16
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
17
|
+
const request = require('@tryghost/request');
|
|
18
|
+
const logging = require('@tryghost/logging');
|
|
19
|
+
const events = require('../../lib/common/events');
|
|
20
|
+
this.service = new indexnow_ping_service_1.IndexNowPingService({
|
|
21
|
+
settingsCache,
|
|
22
|
+
config,
|
|
23
|
+
labs,
|
|
24
|
+
urlService,
|
|
25
|
+
urlUtils,
|
|
26
|
+
request,
|
|
27
|
+
logging,
|
|
28
|
+
events
|
|
29
|
+
});
|
|
30
|
+
this.service.subscribeEvents();
|
|
184
31
|
}
|
|
185
32
|
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Check if any SEO-relevant fields have changed
|
|
189
|
-
* These are fields that affect how the post appears in search results
|
|
190
|
-
* @param {Object} model - The model instance
|
|
191
|
-
* @returns {boolean} True if SEO-relevant content has changed
|
|
192
|
-
*/
|
|
193
|
-
function hasSeoRelevantChanges(model) {
|
|
194
|
-
// Fields that affect how the post appears in search engine results
|
|
195
|
-
const seoFields = [
|
|
196
|
-
'html', // Post content
|
|
197
|
-
'title', // Post title (appears in SERP)
|
|
198
|
-
'slug', // URL path
|
|
199
|
-
'meta_title', // Custom meta title
|
|
200
|
-
'meta_description', // Meta description (appears in SERP)
|
|
201
|
-
'canonical_url', // Canonical URL
|
|
202
|
-
'status' // Published status change
|
|
203
|
-
];
|
|
204
|
-
|
|
205
|
-
return seoFields.some(field => model.get(field) !== model.previous(field));
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Event listener for post.published events
|
|
210
|
-
* @param {Object} model - The model instance
|
|
211
|
-
* @param {Object} options - Event options
|
|
212
|
-
*/
|
|
213
|
-
function indexnowListener(model, options) {
|
|
214
|
-
// CASE: do not ping if we import a database
|
|
215
|
-
if (options && options.importing) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Content-based deduplication: skip if no SEO-relevant fields changed
|
|
220
|
-
// This avoids spamming IndexNow when minor non-content edits are made
|
|
221
|
-
if (!hasSeoRelevantChanges(model)) {
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
ping({
|
|
226
|
-
...model.toJSON(),
|
|
227
|
-
// tags and authors are needed so the lazy URL service can evaluate
|
|
228
|
-
// collection filters (e.g. `tag:foo`) when resolving the post URL;
|
|
229
|
-
// without them a tag/author-filtered post resolves to /404/
|
|
230
|
-
authors: model.related('authors').toJSON(),
|
|
231
|
-
tags: model.related('tags').toJSON()
|
|
232
|
-
}).catch(() => {
|
|
233
|
-
// Errors are already logged inside ping()
|
|
234
|
-
// This catch is just to prevent unhandled rejection warnings
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Register event listeners for IndexNow
|
|
240
|
-
*/
|
|
241
|
-
function init() {
|
|
242
|
-
// Listen for new posts being published
|
|
243
|
-
events
|
|
244
|
-
.removeListener('post.published', indexnowListener)
|
|
245
|
-
.on('post.published', indexnowListener);
|
|
246
|
-
|
|
247
|
-
// Also listen for published posts being edited
|
|
248
|
-
events
|
|
249
|
-
.removeListener('post.published.edited', indexnowListener)
|
|
250
|
-
.on('post.published.edited', indexnowListener);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
module.exports = {
|
|
254
|
-
init: init,
|
|
255
|
-
ping: ping,
|
|
256
|
-
getApiKey: getApiKey
|
|
257
|
-
};
|
|
33
|
+
exports.default = new IndexNowPingServiceWrapper();
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {IndexNowPingService} from './indexnow-ping-service';
|
|
2
|
+
|
|
3
|
+
class IndexNowPingServiceWrapper {
|
|
4
|
+
service?: IndexNowPingService;
|
|
5
|
+
|
|
6
|
+
init(): void {
|
|
7
|
+
if (this.service) {
|
|
8
|
+
// Already done
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Wire up all the dependencies
|
|
13
|
+
const settingsCache = require('../../../shared/settings-cache');
|
|
14
|
+
const config = require('../../../shared/config');
|
|
15
|
+
const labs = require('../../../shared/labs');
|
|
16
|
+
const urlService = require('../url');
|
|
17
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
18
|
+
const request = require('@tryghost/request');
|
|
19
|
+
const logging = require('@tryghost/logging');
|
|
20
|
+
const events = require('../../lib/common/events');
|
|
21
|
+
|
|
22
|
+
this.service = new IndexNowPingService({
|
|
23
|
+
settingsCache,
|
|
24
|
+
config,
|
|
25
|
+
labs,
|
|
26
|
+
urlService,
|
|
27
|
+
urlUtils,
|
|
28
|
+
request,
|
|
29
|
+
logging,
|
|
30
|
+
events
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
this.service.subscribeEvents();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default new IndexNowPingServiceWrapper();
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* IndexNow Integration Service
|
|
4
|
+
*
|
|
5
|
+
* IndexNow is a protocol that allows websites to notify search engines about
|
|
6
|
+
* content changes for faster indexing. Instead of waiting for crawlers to
|
|
7
|
+
* discover updates, we proactively ping the IndexNow API when posts are
|
|
8
|
+
* published or updated.
|
|
9
|
+
*
|
|
10
|
+
* Protocol: https://www.indexnow.org/documentation
|
|
11
|
+
*
|
|
12
|
+
* How it works:
|
|
13
|
+
* 1. Ghost generates a unique API key (32-char hex string)
|
|
14
|
+
* 2. The key is stored in settings and served at /{key}.txt for verification
|
|
15
|
+
* 3. When a post is published/updated, we send a GET request to IndexNow:
|
|
16
|
+
* GET https://api.indexnow.org/indexnow?url={post-url}&key={key}&keyLocation={key-file-url}
|
|
17
|
+
* 4. IndexNow distributes the notification to participating search engines
|
|
18
|
+
* (Bing, Yandex, Seznam.cz, Naver, and others)
|
|
19
|
+
*
|
|
20
|
+
* The API key file is served by the middleware in:
|
|
21
|
+
* ghost/core/core/frontend/web/middleware/serve-indexnow-key.js
|
|
22
|
+
*/
|
|
23
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
24
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
25
|
+
};
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.IndexNowPingService = void 0;
|
|
28
|
+
const errors_1 = __importDefault(require("@tryghost/errors"));
|
|
29
|
+
const tpl_1 = __importDefault(require("@tryghost/tpl"));
|
|
30
|
+
const constants_1 = require("./constants");
|
|
31
|
+
class IndexNowPingService {
|
|
32
|
+
settingsCache;
|
|
33
|
+
config;
|
|
34
|
+
labs;
|
|
35
|
+
urlService;
|
|
36
|
+
urlUtils;
|
|
37
|
+
request;
|
|
38
|
+
logging;
|
|
39
|
+
events;
|
|
40
|
+
listener;
|
|
41
|
+
constructor({ settingsCache, config, labs, urlService, urlUtils, request, logging, events }) {
|
|
42
|
+
this.settingsCache = settingsCache;
|
|
43
|
+
this.config = config;
|
|
44
|
+
this.labs = labs;
|
|
45
|
+
this.urlService = urlService;
|
|
46
|
+
this.urlUtils = urlUtils;
|
|
47
|
+
this.request = request;
|
|
48
|
+
this.logging = logging;
|
|
49
|
+
this.events = events;
|
|
50
|
+
// Stable reference so removeListener() can de-register it across reboots.
|
|
51
|
+
this.listener = this.handlePostEvent.bind(this);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get existing API key from settings.
|
|
55
|
+
* The key is auto-generated on boot by the settings service.
|
|
56
|
+
*/
|
|
57
|
+
getApiKey() {
|
|
58
|
+
return this.settingsCache.get('indexnow_api_key') || null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if any SEO-relevant fields have changed.
|
|
62
|
+
* These are fields that affect how the post appears in search results.
|
|
63
|
+
*/
|
|
64
|
+
hasSeoRelevantChanges(model) {
|
|
65
|
+
return constants_1.seoFields.some(field => model.get(field) !== model.previous(field));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Ping IndexNow with a URL.
|
|
69
|
+
*/
|
|
70
|
+
async ping(post) {
|
|
71
|
+
// Skip pages - only ping for posts
|
|
72
|
+
if (post.type === 'page') {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Skip if site is private
|
|
76
|
+
if (this.settingsCache.get('is_private')) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Skip if IndexNow pings are disabled via privacy config
|
|
80
|
+
if (this.config.isPrivacyDisabled('useIndexNow')) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Skip if IndexNow is not enabled in labs
|
|
84
|
+
if (!this.labs.isSet('indexnow')) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Don't ping for the default posts
|
|
88
|
+
if (post.slug && constants_1.defaultPostSlugs.indexOf(post.slug) > -1) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Everything from URL resolution onwards sits inside the swallow-and-log
|
|
92
|
+
// envelope: the lazy URL service evaluates collection filters during
|
|
93
|
+
// resolution and can throw, and IndexNow failures must never disrupt
|
|
94
|
+
// publishing.
|
|
95
|
+
let url = null;
|
|
96
|
+
try {
|
|
97
|
+
url = this.urlService.facade.getUrlForResource({ ...post, type: 'posts' }, { absolute: true });
|
|
98
|
+
if (!url || url.endsWith('/404/')) {
|
|
99
|
+
this.logging.warn({
|
|
100
|
+
event: { name: 'indexnow.unresolved_url' },
|
|
101
|
+
post: { id: post.id, slug: post.slug, url }
|
|
102
|
+
}, `${constants_1.INDEXNOW_LOG_KEY} Skipped ping - post has no resolvable URL`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// Get the API key (auto-generated on boot by settings service)
|
|
106
|
+
const key = this.getApiKey();
|
|
107
|
+
if (!key) {
|
|
108
|
+
this.logging.warn({
|
|
109
|
+
event: { name: 'indexnow.api_key_missing' },
|
|
110
|
+
post: { id: post.id, slug: post.slug }
|
|
111
|
+
}, `${constants_1.INDEXNOW_LOG_KEY} API key not available`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Get the site URL for the keyLocation parameter
|
|
115
|
+
const siteUrl = this.urlUtils.urlFor('home', true);
|
|
116
|
+
// Build the IndexNow request URL
|
|
117
|
+
const indexNowUrl = new URL(constants_1.INDEXNOW_ENDPOINT);
|
|
118
|
+
indexNowUrl.searchParams.set('url', url);
|
|
119
|
+
indexNowUrl.searchParams.set('key', key);
|
|
120
|
+
indexNowUrl.searchParams.set('keyLocation', this.urlUtils.urlJoin(siteUrl, `${key}.txt`));
|
|
121
|
+
const response = await this.request(indexNowUrl.toString(), {
|
|
122
|
+
timeout: {
|
|
123
|
+
request: 5 * 1000 // 5 second timeout
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
if (response.statusCode !== 200 && response.statusCode !== 202) {
|
|
127
|
+
throw new errors_1.default.InternalServerError({
|
|
128
|
+
message: `IndexNow returned unexpected status: ${response.statusCode}`,
|
|
129
|
+
statusCode: response.statusCode
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
this.logging.info({
|
|
133
|
+
event: { name: 'indexnow.pinged' },
|
|
134
|
+
post: { id: post.id, slug: post.slug, url },
|
|
135
|
+
http: { response: { status_code: response.statusCode } }
|
|
136
|
+
}, `${constants_1.INDEXNOW_LOG_KEY} Successfully pinged ${url}`);
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
// Log errors but don't throw - IndexNow failures shouldn't disrupt publishing
|
|
140
|
+
const errorLike = err;
|
|
141
|
+
const statusCode = errorLike.statusCode ?? errorLike.response?.statusCode ?? null;
|
|
142
|
+
const { eventName, error } = this.#classifyError(statusCode, err);
|
|
143
|
+
this.logging.warn({
|
|
144
|
+
event: { name: eventName },
|
|
145
|
+
post: { id: post.id, slug: post.slug, url },
|
|
146
|
+
http: { response: { status_code: statusCode } },
|
|
147
|
+
err: error
|
|
148
|
+
}, `${constants_1.INDEXNOW_LOG_KEY} ${error.message}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Map an IndexNow response status to a log event name and a structured error.
|
|
153
|
+
* IndexNow-protocol-specific interpretation; when this logic is lifted into a
|
|
154
|
+
* shared ping primitive, this becomes the injected `interpret(status)` hook.
|
|
155
|
+
*/
|
|
156
|
+
#classifyError(statusCode, err) {
|
|
157
|
+
if (statusCode === 429) {
|
|
158
|
+
// Rate limited by IndexNow - we have no retry/backoff, so the ping is dropped
|
|
159
|
+
return {
|
|
160
|
+
eventName: 'indexnow.rate_limited',
|
|
161
|
+
error: new errors_1.default.TooManyRequestsError({
|
|
162
|
+
err,
|
|
163
|
+
message: err.message,
|
|
164
|
+
context: (0, tpl_1.default)(constants_1.messages.requestFailedError, { service: 'IndexNow' }),
|
|
165
|
+
help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://ghost.org/docs/' })
|
|
166
|
+
})
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if (statusCode === 422 || statusCode === 403) {
|
|
170
|
+
return {
|
|
171
|
+
eventName: 'indexnow.key_validation_failed',
|
|
172
|
+
error: new errors_1.default.ValidationError({
|
|
173
|
+
err,
|
|
174
|
+
message: 'IndexNow key validation failed',
|
|
175
|
+
context: (0, tpl_1.default)(constants_1.messages.requestFailedError, { service: 'IndexNow' }),
|
|
176
|
+
help: 'Ensure your IndexNow API key file is accessible at the correct URL'
|
|
177
|
+
})
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
eventName: 'indexnow.ping_failed',
|
|
182
|
+
error: new errors_1.default.InternalServerError({
|
|
183
|
+
err,
|
|
184
|
+
message: err.message,
|
|
185
|
+
context: (0, tpl_1.default)(constants_1.messages.requestFailedError, { service: 'IndexNow' }),
|
|
186
|
+
help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://ghost.org/docs/' })
|
|
187
|
+
})
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Event listener for post.published / post.published.edited.
|
|
192
|
+
*/
|
|
193
|
+
handlePostEvent(model, options) {
|
|
194
|
+
// CASE: do not ping if we import a database
|
|
195
|
+
if (options && options.importing) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// Content-based deduplication: skip if no SEO-relevant fields changed
|
|
199
|
+
// This avoids spamming IndexNow when minor non-content edits are made
|
|
200
|
+
if (!this.hasSeoRelevantChanges(model)) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
this.ping({
|
|
204
|
+
...model.toJSON(),
|
|
205
|
+
// tags and authors are needed so the lazy URL service can evaluate
|
|
206
|
+
// collection filters (e.g. `tag:foo`) when resolving the post URL;
|
|
207
|
+
// without them a tag/author-filtered post resolves to /404/
|
|
208
|
+
authors: model.related('authors').toJSON(),
|
|
209
|
+
tags: model.related('tags').toJSON()
|
|
210
|
+
}).catch(() => {
|
|
211
|
+
// Errors are already logged inside ping()
|
|
212
|
+
// This catch is just to prevent unhandled rejection warnings
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Register event listeners for IndexNow.
|
|
217
|
+
*/
|
|
218
|
+
subscribeEvents() {
|
|
219
|
+
// Listen for new posts being published
|
|
220
|
+
this.events
|
|
221
|
+
.removeListener('post.published', this.listener)
|
|
222
|
+
.on('post.published', this.listener);
|
|
223
|
+
// Also listen for published posts being edited
|
|
224
|
+
this.events
|
|
225
|
+
.removeListener('post.published.edited', this.listener)
|
|
226
|
+
.on('post.published.edited', this.listener);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
exports.IndexNowPingService = IndexNowPingService;
|