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
|
@@ -14,10 +14,13 @@ const queries_1 = require("./queries");
|
|
|
14
14
|
const storage_1 = require("./storage");
|
|
15
15
|
const FIELDS_TABLE = 'members_custom_fields';
|
|
16
16
|
const VALUES_TABLE = 'members_custom_field_values';
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
// Matches the `members_custom_fields.key` column (schema.js), so no key a site
|
|
18
|
+
// could actually have minted is ever refused by it.
|
|
19
|
+
const MAX_KEY_LENGTH = 191;
|
|
20
|
+
// Values arrive keyed by field key. Each value stays `unknown` here: it is
|
|
21
|
+
// validated by its own field type's schema, which isn't known until the key is
|
|
22
|
+
// resolved to a definition.
|
|
23
|
+
const ValuesInput = zod_1.z.record(zod_1.z.string().max(MAX_KEY_LENGTH), zod_1.z.unknown());
|
|
21
24
|
/**
|
|
22
25
|
* The value half of member custom fields: reading and writing what a member holds
|
|
23
26
|
* for each defined field. It belongs to the member aggregate — a value is data
|
|
@@ -31,8 +34,15 @@ const ValuesInput = zod_1.z.record(zod_1.z.string(), zod_1.z.unknown());
|
|
|
31
34
|
*/
|
|
32
35
|
class CustomFieldValuesService {
|
|
33
36
|
knex;
|
|
34
|
-
|
|
37
|
+
/**
|
|
38
|
+
* @private
|
|
39
|
+
* A getter rather than a number: the ceiling is an operator setting that can
|
|
40
|
+
* change between requests.
|
|
41
|
+
*/
|
|
42
|
+
getMaxDefinitions;
|
|
43
|
+
constructor({ knex, getMaxDefinitions }) {
|
|
35
44
|
this.knex = knex;
|
|
45
|
+
this.getMaxDefinitions = getMaxDefinitions;
|
|
36
46
|
}
|
|
37
47
|
/**
|
|
38
48
|
* The active fields for a set of keys, keyed by key, for resolving a write.
|
|
@@ -97,6 +107,33 @@ class CustomFieldValuesService {
|
|
|
97
107
|
}
|
|
98
108
|
return byMember;
|
|
99
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* @private
|
|
112
|
+
* Input as the values object it claims to be, rejecting anything that isn't
|
|
113
|
+
* one. Shared by every caller so they cannot disagree on what a values object
|
|
114
|
+
* is, or on the error when it isn't one.
|
|
115
|
+
*/
|
|
116
|
+
parseValues(input) {
|
|
117
|
+
const parsed = ValuesInput.safeParse(input);
|
|
118
|
+
if (!parsed.success) {
|
|
119
|
+
throw new errors_1.default.ValidationError({ message: 'Custom field values must be an object keyed by field key.', property: 'custom_fields' });
|
|
120
|
+
}
|
|
121
|
+
return parsed.data;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Whether input names any values. An absent key names none; anything present
|
|
125
|
+
* that isn't a values object throws, with the same error resolving it would
|
|
126
|
+
* have raised.
|
|
127
|
+
*
|
|
128
|
+
* Answers the shape question alone, with no catalog lookup, so it can be asked
|
|
129
|
+
* before a write is known to be permitted.
|
|
130
|
+
*/
|
|
131
|
+
namesValues(input) {
|
|
132
|
+
if (input === undefined) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return Object.keys(this.parseValues(input)).length > 0;
|
|
136
|
+
}
|
|
100
137
|
/**
|
|
101
138
|
* Resolve input into the writes it implies, rejecting anything invalid, and
|
|
102
139
|
* writing nothing. Returned so a caller can validate before it commits to a
|
|
@@ -104,13 +141,22 @@ class CustomFieldValuesService {
|
|
|
104
141
|
* apply the same plan without re-resolving or re-validating.
|
|
105
142
|
*/
|
|
106
143
|
async planWrite(input) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
144
|
+
const values = this.parseValues(input);
|
|
145
|
+
const keys = Object.keys(values);
|
|
146
|
+
// A write cannot name more fields than the site may define, so the
|
|
147
|
+
// definitions ceiling bounds it. This also holds the lookup below within the
|
|
148
|
+
// database driver's bound-parameter limit, which one key per parameter would
|
|
149
|
+
// otherwise exceed.
|
|
150
|
+
const maxKeys = this.getMaxDefinitions();
|
|
151
|
+
if (keys.length > maxKeys) {
|
|
152
|
+
throw new errors_1.default.ValidationError({
|
|
153
|
+
message: `Custom field values are limited to ${maxKeys} fields per request.`,
|
|
154
|
+
property: 'custom_fields'
|
|
155
|
+
});
|
|
110
156
|
}
|
|
111
|
-
const byKey = await this.activeFieldsByKey(
|
|
157
|
+
const byKey = await this.activeFieldsByKey(keys);
|
|
112
158
|
const writes = [];
|
|
113
|
-
for (const [key, raw] of Object.entries(
|
|
159
|
+
for (const [key, raw] of Object.entries(values)) {
|
|
114
160
|
const field = byKey.get(key);
|
|
115
161
|
if (!field) {
|
|
116
162
|
// Unknown (or archived) key. Rejected rather than ignored: a typo
|
|
@@ -11,10 +11,14 @@ import {storageCodecFor, storageColumnsFor} from './storage';
|
|
|
11
11
|
const FIELDS_TABLE = 'members_custom_fields';
|
|
12
12
|
const VALUES_TABLE = 'members_custom_field_values';
|
|
13
13
|
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
// Matches the `members_custom_fields.key` column (schema.js), so no key a site
|
|
15
|
+
// could actually have minted is ever refused by it.
|
|
16
|
+
const MAX_KEY_LENGTH = 191;
|
|
17
|
+
|
|
18
|
+
// Values arrive keyed by field key. Each value stays `unknown` here: it is
|
|
19
|
+
// validated by its own field type's schema, which isn't known until the key is
|
|
20
|
+
// resolved to a definition.
|
|
21
|
+
const ValuesInput = z.record(z.string().max(MAX_KEY_LENGTH), z.unknown());
|
|
18
22
|
|
|
19
23
|
// The field facts the value path needs: the id to write the FK, the key to match
|
|
20
24
|
// input against, the name for error messages, and the type to pick the validator
|
|
@@ -47,9 +51,16 @@ interface PlannedWrite {
|
|
|
47
51
|
*/
|
|
48
52
|
export class CustomFieldValuesService {
|
|
49
53
|
private knex: Knex;
|
|
54
|
+
/**
|
|
55
|
+
* @private
|
|
56
|
+
* A getter rather than a number: the ceiling is an operator setting that can
|
|
57
|
+
* change between requests.
|
|
58
|
+
*/
|
|
59
|
+
private getMaxDefinitions: () => number;
|
|
50
60
|
|
|
51
|
-
constructor({knex}: {knex: Knex}) {
|
|
61
|
+
constructor({knex, getMaxDefinitions}: {knex: Knex, getMaxDefinitions: () => number}) {
|
|
52
62
|
this.knex = knex;
|
|
63
|
+
this.getMaxDefinitions = getMaxDefinitions;
|
|
53
64
|
}
|
|
54
65
|
|
|
55
66
|
/**
|
|
@@ -119,6 +130,37 @@ export class CustomFieldValuesService {
|
|
|
119
130
|
return byMember;
|
|
120
131
|
}
|
|
121
132
|
|
|
133
|
+
/**
|
|
134
|
+
* @private
|
|
135
|
+
* Input as the values object it claims to be, rejecting anything that isn't
|
|
136
|
+
* one. Shared by every caller so they cannot disagree on what a values object
|
|
137
|
+
* is, or on the error when it isn't one.
|
|
138
|
+
*/
|
|
139
|
+
private parseValues(input: unknown): Record<string, unknown> {
|
|
140
|
+
const parsed = ValuesInput.safeParse(input);
|
|
141
|
+
if (!parsed.success) {
|
|
142
|
+
throw new errors.ValidationError({message: 'Custom field values must be an object keyed by field key.', property: 'custom_fields'});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return parsed.data;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Whether input names any values. An absent key names none; anything present
|
|
150
|
+
* that isn't a values object throws, with the same error resolving it would
|
|
151
|
+
* have raised.
|
|
152
|
+
*
|
|
153
|
+
* Answers the shape question alone, with no catalog lookup, so it can be asked
|
|
154
|
+
* before a write is known to be permitted.
|
|
155
|
+
*/
|
|
156
|
+
namesValues(input: unknown): boolean {
|
|
157
|
+
if (input === undefined) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return Object.keys(this.parseValues(input)).length > 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
122
164
|
/**
|
|
123
165
|
* Resolve input into the writes it implies, rejecting anything invalid, and
|
|
124
166
|
* writing nothing. Returned so a caller can validate before it commits to a
|
|
@@ -126,15 +168,25 @@ export class CustomFieldValuesService {
|
|
|
126
168
|
* apply the same plan without re-resolving or re-validating.
|
|
127
169
|
*/
|
|
128
170
|
async planWrite(input: unknown): Promise<PlannedWrite[]> {
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
171
|
+
const values = this.parseValues(input);
|
|
172
|
+
const keys = Object.keys(values);
|
|
173
|
+
|
|
174
|
+
// A write cannot name more fields than the site may define, so the
|
|
175
|
+
// definitions ceiling bounds it. This also holds the lookup below within the
|
|
176
|
+
// database driver's bound-parameter limit, which one key per parameter would
|
|
177
|
+
// otherwise exceed.
|
|
178
|
+
const maxKeys = this.getMaxDefinitions();
|
|
179
|
+
if (keys.length > maxKeys) {
|
|
180
|
+
throw new errors.ValidationError({
|
|
181
|
+
message: `Custom field values are limited to ${maxKeys} fields per request.`,
|
|
182
|
+
property: 'custom_fields'
|
|
183
|
+
});
|
|
132
184
|
}
|
|
133
185
|
|
|
134
|
-
const byKey = await this.activeFieldsByKey(
|
|
186
|
+
const byKey = await this.activeFieldsByKey(keys);
|
|
135
187
|
const writes: PlannedWrite[] = [];
|
|
136
188
|
|
|
137
|
-
for (const [key, raw] of Object.entries(
|
|
189
|
+
for (const [key, raw] of Object.entries(values)) {
|
|
138
190
|
const field = byKey.get(key);
|
|
139
191
|
if (!field) {
|
|
140
192
|
// Unknown (or archived) key. Rejected rather than ignored: a typo
|
|
@@ -5,14 +5,16 @@ module.exports = class MentionSendingService {
|
|
|
5
5
|
#discoveryService;
|
|
6
6
|
#externalRequest;
|
|
7
7
|
#getSiteUrl;
|
|
8
|
+
#getPostData;
|
|
8
9
|
#getPostUrl;
|
|
9
10
|
#isEnabled;
|
|
10
11
|
#jobService;
|
|
11
12
|
|
|
12
|
-
constructor({discoveryService, externalRequest, getSiteUrl, getPostUrl, isEnabled, jobService}) {
|
|
13
|
+
constructor({discoveryService, externalRequest, getSiteUrl, getPostData, getPostUrl, isEnabled, jobService}) {
|
|
13
14
|
this.#discoveryService = discoveryService;
|
|
14
15
|
this.#externalRequest = externalRequest;
|
|
15
16
|
this.#getSiteUrl = getSiteUrl;
|
|
17
|
+
this.#getPostData = getPostData;
|
|
16
18
|
this.#getPostUrl = getPostUrl;
|
|
17
19
|
this.#isEnabled = isEnabled;
|
|
18
20
|
this.#jobService = jobService;
|
|
@@ -66,9 +68,12 @@ module.exports = class MentionSendingService {
|
|
|
66
68
|
let html = post.get('status') === 'published' ? post.get('html') : null;
|
|
67
69
|
let previousHtml = post.previous('status') === 'published' ? post.previous('html') : null;
|
|
68
70
|
if (html || previousHtml) {
|
|
71
|
+
// Capture the source URL now, from the event's data, rather than
|
|
72
|
+
// deferring the model into the job.
|
|
73
|
+
const url = new URL(await this.#resolvePostUrl(post));
|
|
69
74
|
await this.#jobService.addJob('sendWebmentions', async () => {
|
|
70
75
|
await this.sendForHTMLResource({
|
|
71
|
-
url
|
|
76
|
+
url,
|
|
72
77
|
html: html,
|
|
73
78
|
previousHtml: previousHtml
|
|
74
79
|
});
|
|
@@ -80,6 +85,21 @@ module.exports = class MentionSendingService {
|
|
|
80
85
|
}
|
|
81
86
|
}
|
|
82
87
|
|
|
88
|
+
// Deleting a published post fires `unpublished` from onDestroyed with the
|
|
89
|
+
// model already destroyed: its own attributes are cleared, but its previous
|
|
90
|
+
// state and loaded relations remain. Resolve the URL from that previous
|
|
91
|
+
// data, the same way we read previous('html') above; live models resolve
|
|
92
|
+
// straight from the model.
|
|
93
|
+
async #resolvePostUrl(post) {
|
|
94
|
+
// A deleted post arrives destroyed: its own attributes are cleared, so
|
|
95
|
+
// its data lives in the previous attributes (its relations remain).
|
|
96
|
+
// A live post loads whatever the URL service still needs.
|
|
97
|
+
if (post.attributes && Object.keys(post.attributes).length === 0) {
|
|
98
|
+
return this.#getPostUrl(post.previous('id'), {...post.toJSON(), ...post.previousAttributes()});
|
|
99
|
+
}
|
|
100
|
+
return this.#getPostUrl(post.id, await this.#getPostData(post));
|
|
101
|
+
}
|
|
102
|
+
|
|
83
103
|
/**
|
|
84
104
|
* @param {{source: URL, target: URL, endpoint: URL}} options
|
|
85
105
|
* @returns
|
|
@@ -9,16 +9,27 @@ const RoutingService = require('./routing-service');
|
|
|
9
9
|
const models = require('../../models');
|
|
10
10
|
const events = require('../../lib/common/events');
|
|
11
11
|
const externalRequest = require('../../../server/lib/request-external.js');
|
|
12
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
12
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
13
13
|
const outputSerializerUrlUtil = require('../../../server/api/endpoints/utils/serializers/output/utils/url');
|
|
14
14
|
const urlService = require('../url');
|
|
15
15
|
const settingsCache = require('../../../shared/settings-cache');
|
|
16
16
|
const DomainEvents = require('@tryghost/domain-events');
|
|
17
17
|
const jobsService = require('../mentions-jobs');
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
// Serializes a post model to the data the URL service needs, loading the
|
|
20
|
+
// relations it reads for filtered collections (event-emitted models don't
|
|
21
|
+
// reliably carry them).
|
|
22
|
+
async function getPostData(post) {
|
|
23
|
+
const missing = urlService.facade.getRequiredRelations().filter(relation => !post.relations[relation]);
|
|
24
|
+
if (missing.length) {
|
|
25
|
+
await post.load(missing);
|
|
26
|
+
}
|
|
27
|
+
return post.toJSON();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getPostUrl(id, postData) {
|
|
31
|
+
const jsonModel = {...postData};
|
|
32
|
+
outputSerializerUrlUtil.forPost(id, jsonModel, {options: {}});
|
|
22
33
|
return jsonModel.url;
|
|
23
34
|
}
|
|
24
35
|
|
|
@@ -99,7 +110,8 @@ module.exports = {
|
|
|
99
110
|
discoveryService,
|
|
100
111
|
externalRequest,
|
|
101
112
|
getSiteUrl: () => urlUtils.urlFor('home', true),
|
|
102
|
-
|
|
113
|
+
getPostData: post => getPostData(post),
|
|
114
|
+
getPostUrl: (id, data) => getPostUrl(id, data),
|
|
103
115
|
isEnabled: () => !settingsCache.get('is_private'),
|
|
104
116
|
jobService: {
|
|
105
117
|
async addJob(name, fn) {
|
|
@@ -116,3 +128,7 @@ module.exports = {
|
|
|
116
128
|
this.sendingService = sendingService;
|
|
117
129
|
}
|
|
118
130
|
};
|
|
131
|
+
|
|
132
|
+
// exposed for testing
|
|
133
|
+
module.exports.getPostData = getPostData;
|
|
134
|
+
module.exports.getPostUrl = getPostUrl;
|
|
@@ -2,7 +2,7 @@ const NewslettersService = require('./newsletters-service.js');
|
|
|
2
2
|
const SingleUseTokenProvider = require('../members/single-use-token-provider');
|
|
3
3
|
const mail = require('../mail');
|
|
4
4
|
const models = require('../../models');
|
|
5
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
5
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
6
6
|
const limitService = require('../limits');
|
|
7
7
|
const labs = require('../../../shared/labs');
|
|
8
8
|
const emailAddressService = require('../email-address');
|
|
@@ -13,6 +13,8 @@ const crypto = require('crypto');
|
|
|
13
13
|
// Some sites block non-standard user agents so we need to mimic a typical browser
|
|
14
14
|
// Note: the Ghost/5.0 string _may_ be in use by 3rd parties so use caution when updating across majors
|
|
15
15
|
const USER_AGENT = 'Mozilla/5.0 (compatible; Ghost/5.0; +https://ghost.org/)';
|
|
16
|
+
const DEFAULT_BOOKMARK_ICON = 'https://static.ghost.org/v5.0.0/images/link-icon.svg';
|
|
17
|
+
const DEFAULT_REQUEST_TIMEOUT = 5000;
|
|
16
18
|
|
|
17
19
|
// metascraper-amazon's built-in URL test is a substring regex that misfires on
|
|
18
20
|
// any host ending in a letter followed by `.co/` (e.g. `rangemedia.co`), causing
|
|
@@ -77,9 +79,8 @@ const findUrlWithProvider = (url) => {
|
|
|
77
79
|
*/
|
|
78
80
|
|
|
79
81
|
/**
|
|
80
|
-
* @typedef {
|
|
81
|
-
*
|
|
82
|
-
*/
|
|
82
|
+
* @typedef {import('ghost-storage-base').StorageBase} IImageStore
|
|
83
|
+
*
|
|
83
84
|
|
|
84
85
|
/**
|
|
85
86
|
* @typedef {import('got').GotRequestFunction} IExternalRequest
|
|
@@ -96,12 +97,12 @@ class OEmbedService {
|
|
|
96
97
|
*
|
|
97
98
|
* @param {Object} dependencies
|
|
98
99
|
* @param {IConfig} dependencies.config
|
|
99
|
-
* @param {
|
|
100
|
+
* @param {IImageStore} dependencies.imageStore
|
|
100
101
|
* @param {IExternalRequest} dependencies.externalRequest
|
|
101
102
|
*/
|
|
102
|
-
constructor({config, externalRequest,
|
|
103
|
+
constructor({config, externalRequest, imageStore}) {
|
|
103
104
|
this.config = config;
|
|
104
|
-
this.
|
|
105
|
+
this.imageStore = imageStore;
|
|
105
106
|
|
|
106
107
|
/** @type {IExternalRequest} */
|
|
107
108
|
this.externalRequest = externalRequest;
|
|
@@ -130,12 +131,13 @@ class OEmbedService {
|
|
|
130
131
|
|
|
131
132
|
/**
|
|
132
133
|
* @param {string} url
|
|
134
|
+
* @param {Object} [options]
|
|
133
135
|
*/
|
|
134
|
-
async knownProvider(url) {
|
|
136
|
+
async knownProvider(url, options = {}) {
|
|
135
137
|
const {extract} = require('@extractus/oembed-extractor');
|
|
136
138
|
|
|
137
139
|
try {
|
|
138
|
-
return await extract(url);
|
|
140
|
+
return await extract(url, {}, options);
|
|
139
141
|
} catch (err) {
|
|
140
142
|
if (err.message === 'Request failed with error code 401' || err.message === 'Request failed with error code 403') {
|
|
141
143
|
throw new errors.ValidationError({
|
|
@@ -163,25 +165,66 @@ class OEmbedService {
|
|
|
163
165
|
|
|
164
166
|
/**
|
|
165
167
|
* Process and store image from a URL
|
|
166
|
-
* @param {string} imageUrl - URL of the image to process
|
|
168
|
+
* @param {string|null|undefined} imageUrl - URL of the image to process
|
|
167
169
|
* @param {string} imageType - What is the image used for. Example - icon, thumbnail
|
|
168
|
-
* @returns {Promise<String>} - URL where the image is stored
|
|
170
|
+
* @returns {Promise<String|null>} - URL where the image is stored
|
|
169
171
|
*/
|
|
170
172
|
async processImageFromUrl(imageUrl, imageType) {
|
|
173
|
+
if (!imageUrl) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
171
177
|
// Fetch image buffer from the URL
|
|
172
178
|
const imageBuffer = await this.fetchImageBuffer(imageUrl);
|
|
173
|
-
const store = this.storage.getStorage('images');
|
|
174
179
|
|
|
175
180
|
// Extract file name from URL
|
|
176
181
|
const fileName = path.basename(new URL(imageUrl).pathname);
|
|
177
182
|
const ext = path.extname(fileName);
|
|
178
183
|
const baseName = ext ? path.basename(fileName, ext) : fileName;
|
|
179
|
-
const name =
|
|
184
|
+
const name = this.imageStore.getSanitizedFileName(baseName);
|
|
180
185
|
|
|
181
186
|
const uniqueFileName = `${name}-${crypto.randomUUID()}${ext}`;
|
|
182
187
|
const targetPath = path.join(imageType, uniqueFileName);
|
|
183
188
|
|
|
184
|
-
return
|
|
189
|
+
return this.imageStore.saveRaw(imageBuffer, targetPath);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Fetch bookmark enrichment from an allowlisted oEmbed provider without
|
|
194
|
+
* exposing provider-supplied HTML.
|
|
195
|
+
*
|
|
196
|
+
* @param {string} url
|
|
197
|
+
* @param {Object} [options]
|
|
198
|
+
* @returns {Promise<Object|undefined>}
|
|
199
|
+
*/
|
|
200
|
+
async fetchBookmarkEnrichment(url, options = {}) {
|
|
201
|
+
const {url: providerUrl, provider} = findUrlWithProvider(url);
|
|
202
|
+
if (!provider) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const timeout = options.timeout?.request ?? DEFAULT_REQUEST_TIMEOUT;
|
|
207
|
+
const signal = AbortSignal.timeout(timeout);
|
|
208
|
+
|
|
209
|
+
let oembed;
|
|
210
|
+
try {
|
|
211
|
+
oembed = await this.knownProvider(providerUrl, {signal});
|
|
212
|
+
} catch {
|
|
213
|
+
// oEmbed metadata is a best-effort enhancement. If it fails, keep
|
|
214
|
+
// the bookmark metadata scraped from the page.
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!oembed) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return _.pickBy({
|
|
223
|
+
title: oembed.title,
|
|
224
|
+
author: oembed.author_name,
|
|
225
|
+
publisher: oembed.provider_name,
|
|
226
|
+
thumbnail: oembed.thumbnail_url || (oembed.type === 'photo' ? oembed.url : undefined)
|
|
227
|
+
}, value => value !== null && value !== undefined && value !== '');
|
|
185
228
|
}
|
|
186
229
|
|
|
187
230
|
/**
|
|
@@ -198,7 +241,7 @@ class OEmbedService {
|
|
|
198
241
|
'user-agent': USER_AGENT
|
|
199
242
|
},
|
|
200
243
|
timeout: {
|
|
201
|
-
request:
|
|
244
|
+
request: DEFAULT_REQUEST_TIMEOUT
|
|
202
245
|
},
|
|
203
246
|
followRedirect: true,
|
|
204
247
|
...options
|
|
@@ -274,6 +317,8 @@ class OEmbedService {
|
|
|
274
317
|
/**
|
|
275
318
|
* @param {string} url
|
|
276
319
|
* @param {string} html
|
|
320
|
+
* @param {string} type
|
|
321
|
+
* @param {Object} [enrichment]
|
|
277
322
|
*
|
|
278
323
|
* @returns {Promise<{
|
|
279
324
|
* version: '1.0',
|
|
@@ -285,7 +330,7 @@ class OEmbedService {
|
|
|
285
330
|
* }
|
|
286
331
|
* }>}
|
|
287
332
|
*/
|
|
288
|
-
async fetchBookmarkData(url, html, type) {
|
|
333
|
+
async fetchBookmarkData(url, html, type, enrichment = {}) {
|
|
289
334
|
const requestOptions = this.externalRequest.defaults?.options || {};
|
|
290
335
|
const gotOpts = {
|
|
291
336
|
hooks: requestOptions.hooks,
|
|
@@ -374,11 +419,24 @@ class OEmbedService {
|
|
|
374
419
|
const metadata = Object.assign({}, scraperResponse, {
|
|
375
420
|
thumbnail: scraperResponse.image,
|
|
376
421
|
icon: scraperResponse.logo
|
|
377
|
-
});
|
|
422
|
+
}, enrichment);
|
|
378
423
|
// We want to use standard naming for image and logo
|
|
379
424
|
delete metadata.image;
|
|
380
425
|
delete metadata.logo;
|
|
381
426
|
|
|
427
|
+
return this.buildBookmarkData(url, metadata, type);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Validate and process bookmark metadata after it has been scraped,
|
|
432
|
+
* enriched, or assembled from enrichment alone.
|
|
433
|
+
*
|
|
434
|
+
* @param {string} url
|
|
435
|
+
* @param {Object} metadata
|
|
436
|
+
* @param {string} type
|
|
437
|
+
* @returns {Promise<Object>}
|
|
438
|
+
*/
|
|
439
|
+
async buildBookmarkData(url, metadata, type) {
|
|
382
440
|
if (!metadata.title) {
|
|
383
441
|
throw new errors.ValidationError({
|
|
384
442
|
message: tpl(messages.insufficientMetadata),
|
|
@@ -391,24 +449,31 @@ class OEmbedService {
|
|
|
391
449
|
try {
|
|
392
450
|
await this.externalRequest.head(metadata.icon);
|
|
393
451
|
} catch (err) {
|
|
394
|
-
metadata.icon =
|
|
452
|
+
metadata.icon = DEFAULT_BOOKMARK_ICON;
|
|
395
453
|
logging.error(err);
|
|
396
454
|
}
|
|
397
455
|
}
|
|
398
456
|
} else {
|
|
399
|
-
|
|
400
|
-
.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
457
|
+
if (metadata.icon) {
|
|
458
|
+
await this.processImageFromUrl(metadata.icon, 'icon')
|
|
459
|
+
.then((processedImageUrl) => {
|
|
460
|
+
metadata.icon = processedImageUrl;
|
|
461
|
+
}).catch((err) => {
|
|
462
|
+
metadata.icon = DEFAULT_BOOKMARK_ICON;
|
|
463
|
+
logging.error(err);
|
|
464
|
+
});
|
|
465
|
+
} else {
|
|
466
|
+
metadata.icon = DEFAULT_BOOKMARK_ICON;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (metadata.thumbnail) {
|
|
470
|
+
await this.processImageFromUrl(metadata.thumbnail, 'thumbnail')
|
|
471
|
+
.then((processedImageUrl) => {
|
|
472
|
+
metadata.thumbnail = processedImageUrl;
|
|
473
|
+
}).catch((err) => {
|
|
474
|
+
logging.error(err);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
412
477
|
}
|
|
413
478
|
|
|
414
479
|
return {
|
|
@@ -508,7 +573,7 @@ class OEmbedService {
|
|
|
508
573
|
* @param {string} url - oembed URL
|
|
509
574
|
* @param {string} type - card type
|
|
510
575
|
* @param {Object} [options] Specific fetch options
|
|
511
|
-
* @param {
|
|
576
|
+
* @param {Object} [options.timeout] Change the default request timeout, got-style ({request: ms})
|
|
512
577
|
*
|
|
513
578
|
* @returns {Promise<Object>}
|
|
514
579
|
*/
|
|
@@ -553,11 +618,35 @@ class OEmbedService {
|
|
|
553
618
|
}
|
|
554
619
|
|
|
555
620
|
// Not in the list, we need to fetch the content
|
|
556
|
-
const
|
|
621
|
+
const bookmarkEnrichmentPromise = type === 'bookmark' ? this.fetchBookmarkEnrichment(url, fetchOptions) : undefined;
|
|
622
|
+
const [pageResult, enrichmentResult] = await Promise.allSettled([
|
|
623
|
+
this.fetchPageHtml(url, fetchOptions),
|
|
624
|
+
bookmarkEnrichmentPromise
|
|
625
|
+
]);
|
|
626
|
+
const bookmarkEnrichment = enrichmentResult.status === 'fulfilled' ? enrichmentResult.value : undefined;
|
|
627
|
+
|
|
628
|
+
if (pageResult.status === 'rejected') {
|
|
629
|
+
if (type === 'bookmark' && bookmarkEnrichment?.title) {
|
|
630
|
+
return this.buildBookmarkData(url, {
|
|
631
|
+
url,
|
|
632
|
+
title: null,
|
|
633
|
+
description: null,
|
|
634
|
+
author: null,
|
|
635
|
+
publisher: null,
|
|
636
|
+
thumbnail: null,
|
|
637
|
+
icon: null,
|
|
638
|
+
...bookmarkEnrichment
|
|
639
|
+
}, type);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
throw pageResult.reason;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const {url: pageUrl, body, contentType} = pageResult.value;
|
|
557
646
|
|
|
558
647
|
// fetch only bookmark when explicitly requested
|
|
559
648
|
if (type === 'bookmark') {
|
|
560
|
-
return this.fetchBookmarkData(url, body, type);
|
|
649
|
+
return this.fetchBookmarkData(url, body, type, bookmarkEnrichment);
|
|
561
650
|
}
|
|
562
651
|
|
|
563
652
|
// mentions need to return bookmark data (metadata) and body (html) for link verification
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
const config = require('../../../shared/config');
|
|
2
|
-
const
|
|
2
|
+
const adapterManager = require('../../services/adapter-manager').default;
|
|
3
3
|
const externalRequest = require('../../lib/request-external');
|
|
4
4
|
|
|
5
5
|
const OEmbedService = require('./oembed-service');
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
const imageStore = adapterManager.getAdapter('storage:images');
|
|
8
|
+
const oembed = new OEmbedService({config, externalRequest, imageStore});
|
|
7
9
|
|
|
8
10
|
const NFT = require('./nft-oembed-provider');
|
|
9
11
|
const nft = new NFT({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const DynamicRedirectManager = require('../lib/dynamic-redirect-manager');
|
|
2
2
|
const config = require('../../../shared/config');
|
|
3
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
3
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
4
4
|
const models = require('../../models');
|
|
5
5
|
const OfferBookshelfRepository = require('./offer-bookshelf-repository');
|
|
6
6
|
const OffersModule = require('./offers-module');
|
|
@@ -5,11 +5,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const post_scheduling_1 = __importDefault(require("./post-scheduling"));
|
|
7
7
|
const internal_keys_1 = __importDefault(require("../internal-keys"));
|
|
8
|
+
const adapter_manager_1 = __importDefault(require("../adapter-manager"));
|
|
9
|
+
const error_capture_1 = require("../../adapters/scheduling/error-capture");
|
|
8
10
|
// CJS modules without TS declarations — typed loosely at the boundary.
|
|
9
|
-
const
|
|
10
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
11
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
11
12
|
exports.default = new post_scheduling_1.default({
|
|
12
13
|
apiUrl: urlUtils.urlFor('api', { type: 'admin' }, true),
|
|
13
|
-
adapter:
|
|
14
|
+
adapter: (0, error_capture_1.withErrorCapture)(adapter_manager_1.default.getAdapter('scheduling')),
|
|
14
15
|
internalKeys: internal_keys_1.default
|
|
15
16
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import PostScheduling from './post-scheduling';
|
|
2
2
|
import internalKeys from '../internal-keys';
|
|
3
|
+
import adapterManager from '../adapter-manager';
|
|
4
|
+
import {withErrorCapture} from '../../adapters/scheduling/error-capture';
|
|
3
5
|
|
|
4
6
|
// CJS modules without TS declarations — typed loosely at the boundary.
|
|
5
|
-
const
|
|
6
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
7
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
7
8
|
|
|
8
9
|
export default new PostScheduling({
|
|
9
10
|
apiUrl: urlUtils.urlFor('api', {type: 'admin'}, true),
|
|
10
|
-
adapter: adapterManager.getAdapter('scheduling'),
|
|
11
|
+
adapter: withErrorCapture(adapterManager.getAdapter('scheduling')),
|
|
11
12
|
internalKeys
|
|
12
13
|
});
|
|
@@ -8,7 +8,7 @@ const logging_1 = __importDefault(require("@tryghost/logging"));
|
|
|
8
8
|
// CJS-only modules — typed loosely below. models is the Bookshelf registry
|
|
9
9
|
// without TS declarations; the rest are JS modules without types.
|
|
10
10
|
const models = require('../../models');
|
|
11
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
11
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
12
12
|
const { getSignedAdminToken } = require('../../adapters/scheduling/utils');
|
|
13
13
|
const events = require('../../lib/common/events');
|
|
14
14
|
// Pages live in the posts table with type:'page', so both types are
|