ghost 6.56.0 → 6.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/validate-adapters.js +74 -0
- package/bin/validate-adapters.ts +87 -0
- package/bin/warm-compile-cache.sh +60 -0
- package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
- package/components/tryghost-kg-html-to-lexical-1.3.3.tgz +0 -0
- package/components/tryghost-kg-lexical-html-renderer-1.4.3.tgz +0 -0
- package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
- package/core/app.js +1 -1
- package/core/boot.js +21 -25
- package/core/bridge.js +10 -12
- package/core/built/admin/assets/Combination-BDvCdg1t.js +41 -0
- package/core/built/admin/assets/about-C7O-AgRZ.js +1 -0
- package/core/built/admin/assets/{account-migration-D3O_yVck.js → account-migration-Cv_ol1ko.js} +1 -1
- package/core/built/admin/assets/action-list-lGzZLHc8.js +1 -0
- package/core/built/admin/assets/activitypub/{account-migration-D8FbP-Z-.js → account-migration-DHFbePl6.js} +7 -7
- package/core/built/admin/assets/activitypub/activitypub.js +3 -3
- package/core/built/admin/assets/activitypub/{avatar-11EA1VSs.js → avatar-CT4tS2_S.js} +2 -2
- package/core/built/admin/assets/activitypub/{avatar-flipboard-jfbLG-xe.js → avatar-flipboard-ByYWKipo.js} +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-f1jTQe2P.js → bluesky-sharing-srVnSHDz.js} +8 -8
- package/core/built/admin/assets/activitypub/{content-formatters-nmTOPY9M.js → content-formatters-C2sos5Ht.js} +3 -3
- package/core/built/admin/assets/activitypub/{copy-BCwo9ep3.js → copy-B1UBTOoZ.js} +2 -2
- package/core/built/admin/assets/activitypub/{dist-BEfX-0aW.js → dist-MPsb2WZ1.js} +4 -4
- package/core/built/admin/assets/activitypub/{domain-AaDlZlrA.js → domain-DzcM9Dzo.js} +9 -9
- package/core/built/admin/assets/activitypub/{edit-profile-DPi8Tl5M.js → edit-profile-CsQ_4xAk.js} +5 -5
- package/core/built/admin/assets/activitypub/{explore-CxTzjILQ.js → explore-CJe0DZBK.js} +8 -8
- package/core/built/admin/assets/activitypub/{feed-DPv5x2MX.js → feed-CKV3qWON.js} +9 -9
- package/core/built/admin/assets/activitypub/{field-DbgA8lat.js → field-DckHfDJf.js} +3 -3
- package/core/built/admin/assets/activitypub/{hash-BWuZoYkA.js → hash-Dlp8RM55.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-35VDQ2K2.js → inbox-CsPy4R0M.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-DSrF_i1O.js → inbox-DAsjzUUe.js} +10 -10
- package/core/built/admin/assets/activitypub/{label-CPjFBbo7.js → label-DWyo9E5T.js} +3 -3
- package/core/built/admin/assets/activitypub/layout-DM_3pqsU.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-BkDC1XVZ.js → moderation-B0Inc03M.js} +7 -7
- package/core/built/admin/assets/activitypub/{note-xEyH4xT-.js → note-CSE54lER.js} +7 -7
- package/core/built/admin/assets/activitypub/{notifications-DClaL3ui.js → notifications-RSwbKqdh.js} +9 -9
- package/core/built/admin/assets/activitypub/{preferences-DpnOa-4Z.js → preferences-CE231n2_.js} +11 -11
- package/core/built/admin/assets/activitypub/{profile-Dvi9mz-6.js → profile-aaQ1j1Eo.js} +13 -13
- package/core/built/admin/assets/activitypub/{reply-Cs9ySd6Z.js → reply-Cjb0Vs3m.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-DFBeTnfn.js → routes-Djb0mc9k.js} +26 -26
- package/core/built/admin/assets/activitypub/{separator-C5u_VjzY.js → separator-D8pROI5n.js} +3 -3
- package/core/built/admin/assets/activitypub/{settings-CV2fFu6D.js → settings-DMc32IQl.js} +5 -5
- package/core/built/admin/assets/activitypub/{site-_TgDd_EM.js → site-DVIcsohX.js} +4 -4
- package/core/built/admin/assets/activitypub/{step-1-BfnNL2oF.js → step-1-9Yey9usF.js} +5 -5
- package/core/built/admin/assets/activitypub/{step-2-DLndZkO-.js → step-2-DdYmKRXV.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-3-A-PZTtRE.js → step-3-hdSkcjZU.js} +10 -10
- package/core/built/admin/assets/activitypub/{tabs-BUbz7tea.js → tabs-CUqseYzQ.js} +6 -6
- package/core/built/admin/assets/activitypub/{topic-filter-BdX_xYYT.js → topic-filter-Coni6OXM.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-EwuRemHh.js → use-activity-pub-queries-MeHTPMQv.js} +2 -2
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-cy4ACBc4.js → use-navigate-with-base-path-B046AM38.js} +24 -7
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-CyFcGfan.js → use-reply-chain-data-1AO-Xob6.js} +5 -5
- package/core/built/admin/assets/activitypub/{x-7zk8mV2p.js → x-BRfRYd16.js} +2 -2
- package/core/built/admin/assets/add-integration-modal-m9Dv6f77.js +1 -0
- package/core/built/admin/assets/add-newsletter-modal-CPSVZL2H.js +1 -0
- package/core/built/admin/assets/add-recommendation-modal-Ci9Z5yat.js +1 -0
- package/core/built/admin/assets/analytics-DqSCVV8U.js +1 -0
- package/core/built/admin/assets/announcement-bar-modal-DU3avV7d.js +1 -0
- package/core/built/admin/assets/api-keys-BK0LylyK.js +1 -0
- package/core/built/admin/assets/api-keys-_iCT4dxr.js +1 -0
- package/core/built/admin/assets/{audience-CkBb2LlO.js → audience-DTJtXXWY.js} +1 -1
- package/core/built/admin/assets/automated-emails-PayPCT8L.js +1 -0
- package/core/built/admin/assets/{automations-DhKeS_U5.js → automations-162q5HjL.js} +1 -1
- package/core/built/admin/assets/{automations-cMllU545.js → automations-dtQ_MRZ7.js} +1 -1
- package/core/built/admin/assets/{bluesky-sharing-DPGpyD-G.js → bluesky-sharing-B8Es3AuV.js} +1 -1
- package/core/built/admin/assets/brand-icon-09YqFZjV.js +1 -0
- package/core/built/admin/assets/{breadcrumb-DIfcF5ow.js → breadcrumb-tg5zL--z.js} +1 -1
- package/core/built/admin/assets/{chart-helpers-DV0FkdcD.js → chart-helpers-CZElTGYL.js} +1 -1
- package/core/built/admin/assets/checkbox-Cyo-x7mC.js +1 -0
- package/core/built/admin/assets/{chunk.524.87b52f4fada529df2c4c.js → chunk.524.cd5498dd4e195f679266.js} +4 -4
- package/core/built/admin/assets/{chunk.582.340bcca873e806cbd4bb.js → chunk.582.6f92ec1f03734bf2ea3f.js} +6 -6
- package/core/built/admin/assets/{chunk.332.05991a101d67f732dec3.js → chunk.873.b8fc05a8ab877fb819ed.js} +28 -27
- package/core/built/admin/assets/code-editor-view-Dq1rQ4tS.js +1 -0
- package/core/built/admin/assets/color-picker-field-BonBgxhU.js +1 -0
- package/core/built/admin/assets/color-utils-BsrwXuDz.js +1 -0
- package/core/built/admin/assets/combobox-uX5r_paI.js +1 -0
- package/core/built/admin/assets/command-DxwBO2pF.js +1 -0
- package/core/built/admin/assets/comments-Dn-RO-nU.js +1 -0
- package/core/built/admin/assets/components-CwL6a6As-B0E0-NBJ.js +1 -0
- package/core/built/admin/assets/confirmation-modal-B6D6mk6R.js +1 -0
- package/core/built/admin/assets/content-api-modal-BxQ-7T6u.js +1 -0
- package/core/built/admin/assets/copy-field-BAxL4Zqn.js +1 -0
- package/core/built/admin/assets/currency-Dy4Tc2R2.js +1 -0
- package/core/built/admin/assets/custom-integration-modal---d_l7lc.js +1 -0
- package/core/built/admin/assets/{date-range-select-dXc-GsVe.js → date-range-select-PB2n1HZf.js} +1 -1
- package/core/built/admin/assets/debounce-Dg2fW5Rg.js +3 -0
- package/core/built/admin/assets/design-and-theme-modal-DYRT207a.js +23 -0
- package/core/built/admin/assets/dirty-confirm-dialog-BnDJ39ao.js +1 -0
- package/core/built/admin/assets/disabled-sources-indicator-iMHrkyV3.js +1 -0
- package/core/built/admin/assets/dist-B2PvRwLn.js +1 -0
- package/core/built/admin/assets/{dist-pHiOxyxa.js → dist-D5vhMdXf.js} +1 -1
- package/core/built/admin/assets/dist-DlCyLrOC.js +1 -0
- package/core/built/admin/assets/dist-WeOIvSYM.js +23 -0
- package/core/built/admin/assets/{dist-DyViJwIy.js → dist-cFzKLG7y.js} +3 -3
- package/core/built/admin/assets/dist-j1xxxnY8.js +1 -0
- package/core/built/admin/assets/dist-myQaY0ka.js +1 -0
- package/core/built/admin/assets/{domain-B5ogXUBa.js → domain-BR8FIdjD.js} +1 -1
- package/core/built/admin/assets/{dropzone-BnFG7dDP.js → dropzone-hNxmUvwD.js} +1 -1
- package/core/built/admin/assets/{edit-profile-B07jCZy9.js → edit-profile-CENrkY0l.js} +1 -1
- package/core/built/admin/assets/editor-B18D0lm8.js +8 -0
- package/core/built/admin/assets/embed-signup-form-modal-BsCYUMvQ.js +9 -0
- package/core/built/admin/assets/{explore-Ca1y8HW_.js → explore-BmrnljWw.js} +1 -1
- package/core/built/admin/assets/{feed-x4iFMBP4.js → feed-Dy4li6i8.js} +1 -1
- package/core/built/admin/assets/{field-ChCAabZg.js → field-Dh_lwk13.js} +1 -1
- package/core/built/admin/assets/{filter-sources-LdtH1e-T.js → filter-sources-D2zDuJH5.js} +1 -1
- package/core/built/admin/assets/filters-3JBQcNtJ.js +1 -0
- package/core/built/admin/assets/{filters-CjVKRP8U.js → filters-CFt_BDe4.js} +1 -1
- package/core/built/admin/assets/first-promoter-modal-D6Rjxugw.js +1 -0
- package/core/built/admin/assets/format-url-C-t8G6Qd.js +1 -0
- package/core/built/admin/assets/{ghost-7f01131115186d1af84ead76e79646dd.js → ghost-d683fbeb945b13155ea669caa5d8db41.js} +300 -298
- package/core/built/admin/assets/{gift-link-modal-Buqh2vXh.js → gift-link-modal-zMtlJhLQ.js} +1 -1
- package/core/built/admin/assets/{gift-links-CsUhefWG.js → gift-links-CVuqLhsZ.js} +1 -1
- package/core/built/admin/assets/global-data-provider-B949LDXJ.js +1 -0
- package/core/built/admin/assets/grid-CUciBfjf.js +1 -0
- package/core/built/admin/assets/{growth-Dy2UOSay.js → growth-C38Xtp8D.js} +2 -2
- package/core/built/admin/assets/{growth-DajOBdN0.js → growth-CFws67_i.js} +1 -1
- package/core/built/admin/assets/history-modal-ILAOkbxH.js +1 -0
- package/core/built/admin/assets/{hooks-CixO01lL.js → hooks-D6EE7BIt.js} +2 -2
- package/core/built/admin/assets/html-field-9a9Id_2q.js +1 -0
- package/core/built/admin/assets/iframe-buffering-e8vH4-Qn.js +1 -0
- package/core/built/admin/assets/images-CrQKVc9Q.js +1 -0
- package/core/built/admin/assets/{inbox-BUOLDoji.js → inbox-BrSRzyvz.js} +13 -13
- package/core/built/admin/assets/index-BHy2DZX-.js +67 -0
- package/core/built/admin/assets/index-Ds2iUoF6.css +1 -0
- package/core/built/admin/assets/index.es-B9tvf-t4.js +1 -0
- package/core/built/admin/assets/{input-group-uSK3XT7b.js → input-group-6vEPvX9S.js} +1 -1
- package/core/built/admin/assets/integration-header-B4DyXV06.js +1 -0
- package/core/built/admin/assets/integrations-BT6_iJvu.js +1 -0
- package/core/built/admin/assets/invite-user-modal-5xDCEw90.js +1 -0
- package/core/built/admin/assets/isEmail-BOfC647y.js +1 -0
- package/core/built/admin/assets/koenig-editor-base-BWLEB9Vf.js +1 -0
- package/core/built/admin/assets/{koenig-lexical-BFc4yFed.js → koenig-lexical-Cj62r_y9.js} +1 -1
- package/core/built/admin/assets/{kpi-card-BN-E6WYX.js → kpi-card-DOUnkZcN.js} +1 -1
- package/core/built/admin/assets/{kpi-card-CCt-qeWD.js → kpi-card-IHDo8Q56.js} +1 -1
- package/core/built/admin/assets/{kpi-helpers-DlxTbTs4.js → kpi-helpers-CjUdECAK.js} +1 -1
- package/core/built/admin/assets/{kpi-tabs-BlcUttpn.js → kpi-tabs-X3DkOYbI.js} +1 -1
- package/core/built/admin/assets/{label-AVrxwmsz.js → label-Dq6QaOuS.js} +1 -1
- package/core/built/admin/assets/label-picker-8YlhS2U3.js +1 -0
- package/core/built/admin/assets/{labels-DAIqKed7.js → labels-DAPjKPy2.js} +1 -1
- package/core/built/admin/assets/layout-TMj4P-vv.js +1 -0
- package/core/built/admin/assets/limit-modal-BRPsit_B.js +1 -0
- package/core/built/admin/assets/{link-helpers-D9LsDOkG.js → link-helpers-Bzkk68GD.js} +1 -1
- package/core/built/admin/assets/member-custom-fields-CmvsuuV_.js +1 -0
- package/core/built/admin/assets/member-detail-DCvRrkmJ.js +1 -0
- package/core/built/admin/assets/members-DxbSKngD.js +11 -0
- package/core/built/admin/assets/modal-page-BMTzFHVO.js +1 -0
- package/core/built/admin/assets/{moderation-CQ3urTFE.js → moderation-Da5lhhWh.js} +1 -1
- package/core/built/admin/assets/multi-select-combobox-CYdkH7KQ.js +1 -0
- package/core/built/admin/assets/navigation-modal-BIoTwtMy.js +1 -0
- package/core/built/admin/assets/newsletter-BptlVoJm.js +1 -0
- package/core/built/admin/assets/newsletter-detail-modal-BIvxqE0N.js +1 -0
- package/core/built/admin/assets/newsletter-emails-Bf8IZLsP.js +1 -0
- package/core/built/admin/assets/{newsletters-vt3Ni1Ov.js → newsletters-BgrIZk0V.js} +1 -1
- package/core/built/admin/assets/{newsletters-BXJbJgA-.js → newsletters-Du0lzskS.js} +1 -1
- package/core/built/admin/assets/{note-Dk877BTv.js → note-DYcLOmDb.js} +1 -1
- package/core/built/admin/assets/{notifications-CPlLjPxO.js → notifications-B2SPFIV9.js} +1 -1
- package/core/built/admin/assets/{offers-DEniVRD5.js → offers-Um6ab71O.js} +1 -1
- package/core/built/admin/assets/offers-container-modal-BZnZITMw.js +1 -0
- package/core/built/admin/assets/{onboarding-route-DdStOtjy.js → onboarding-route-DgdfxkQh.js} +1 -1
- package/core/built/admin/assets/overview-BYQJXSog.js +1 -0
- package/core/built/admin/assets/overview-Dt2_mR6U.js +1 -0
- package/core/built/admin/assets/{page-header-pp4dWmOS.js → page-header-CpmxJj5B.js} +1 -1
- package/core/built/admin/assets/{pages-B4goRPUn.js → pages-BVMnpI2O.js} +1 -1
- package/core/built/admin/assets/pintura-modal-B4MuBuuO.js +1 -0
- package/core/built/admin/assets/portal-frame-BF0NBIji.js +1 -0
- package/core/built/admin/assets/portal-modal-DMVbm0oy.js +1 -0
- package/core/built/admin/assets/{post-analytics-BMJrI81R.js → post-analytics-CXWBOGyP.js} +1 -1
- package/core/built/admin/assets/post-analytics-header-ChzjXVPt.js +1 -0
- package/core/built/admin/assets/{post-analytics-provider-Btml5vJI.js → post-analytics-provider-Cgw4U_fw.js} +1 -1
- package/core/built/admin/assets/{post-share-modal-AcUZkbfL.js → post-share-modal-B9Vmk_XM.js} +1 -1
- package/core/built/admin/assets/{posts-DhXE7b6r.js → posts-CxG7v0-M.js} +1 -1
- package/core/built/admin/assets/preferences-BfzJmnsd.js +5 -0
- package/core/built/admin/assets/preview-chrome-BOVO6_PE.js +1 -0
- package/core/built/admin/assets/preview-modal-Dw_HtD6S.js +1 -0
- package/core/built/admin/assets/profile-BT5vtv9b.js +1 -0
- package/core/built/admin/assets/radio-group-I7ou7PoJ.js +1 -0
- package/core/built/admin/assets/{referrers-pmJT4k3-.js → referrers-B9QDAfYm.js} +1 -1
- package/core/built/admin/assets/{router-provider-BmEZf6c6.js → router-provider-DSQfprxH.js} +1 -1
- package/core/built/admin/assets/select-D9oU1IoM.js +1 -0
- package/core/built/admin/assets/settings-CfZFbyu_.js +4 -0
- package/core/built/admin/assets/{settings-BGgk7oCI.js → settings-CpvHWix7.js} +1 -1
- package/core/built/admin/assets/settings-breadcrumbs-K0USP2nw.js +1 -0
- package/core/built/admin/assets/{share-modal-BeuydaBf.js → share-modal-ClIyPzc5.js} +1 -1
- package/core/built/admin/assets/slack-modal-1XXqOfiw.js +1 -0
- package/core/built/admin/assets/social-urls-CHQ9cTAK.js +1 -0
- package/core/built/admin/assets/{sort-button-Df4t2AL8.js → sort-button-CdBsm40v.js} +1 -1
- package/core/built/admin/assets/{source-icon-ajoaKb41.js → source-icon-CEYmVLXR.js} +1 -1
- package/core/built/admin/assets/{stats-C_lfxZAw.js → stats-D8nZCTy5.js} +1 -1
- package/core/built/admin/assets/{stats-view-Cxot1iD8.js → stats-view-CugFVf0g.js} +1 -1
- package/core/built/admin/assets/{step-1-ogAA4lDr.js → step-1-DOYjrORn.js} +1 -1
- package/core/built/admin/assets/{step-2-C5Xini-7.js → step-2-vA6RsarH.js} +1 -1
- package/core/built/admin/assets/{step-3-CZv1FV81.js → step-3-BtIBxMId.js} +2 -2
- package/core/built/admin/assets/stripe-button-UFP4QRXd.js +1 -0
- package/core/built/admin/assets/stripe-connect-modal-C_L3uM6n.js +1 -0
- package/core/built/admin/assets/switch-CE2NuMn-.js +1 -0
- package/core/built/admin/assets/{table-DFj1wiYv.js → table-TMCgCQK7.js} +1 -1
- package/core/built/admin/assets/tabs-Dd6oOKbv.js +1 -0
- package/core/built/admin/assets/tag-detail-D3l-UJPR.js +1 -0
- package/core/built/admin/assets/tags-BwCgmr5v.js +1 -0
- package/core/built/admin/assets/tags-WdKQGWR8.js +1 -0
- package/core/built/admin/assets/testimonials-modal-CqWp-xXJ.js +1 -0
- package/core/built/admin/assets/tier-detail-modal-BkcR2u0A.js +1 -0
- package/core/built/admin/assets/{tiers-DYsa4DCo.js → tiers-Da6kxHQP.js} +1 -1
- package/core/built/admin/assets/toggle-group-Guorw93z.js +1 -0
- package/core/built/admin/assets/{topic-filter-DGDxDalo.js → topic-filter-CbgoWIHn.js} +1 -1
- package/core/built/admin/assets/transistor-modal-DuNnnpal.js +1 -0
- package/core/built/admin/assets/unsplash-modal-y2bVwTHH.js +1 -0
- package/core/built/admin/assets/{use-analytics-data-C76v4LIp.js → use-analytics-data-B-b4wNSC.js} +1 -1
- package/core/built/admin/assets/use-check-theme-limit-error-m09J38Mq.js +2 -0
- package/core/built/admin/assets/use-feature-flag-ud0Qz8vt.js +1 -0
- package/core/built/admin/assets/use-filter-params-BnbBDc7T.js +1 -0
- package/core/built/admin/assets/use-filterable-api-iMpDZBxD.js +1 -0
- package/core/built/admin/assets/use-form-vRjI0Kwk.js +1 -0
- package/core/built/admin/assets/{use-growth-stats-aNXJOmQr.js → use-growth-stats-DPU5rt3W.js} +1 -1
- package/core/built/admin/assets/use-hash-link-navigation-guard-B9j6HIrV.js +1 -0
- package/core/built/admin/assets/use-limiter-BkN3E4gw.js +2 -0
- package/core/built/admin/assets/use-pintura-config-C_z8HTG2.js +1 -0
- package/core/built/admin/assets/use-pintura-editor-DNgbkhGp.js +1 -0
- package/core/built/admin/assets/{use-post-referrers-CG0SZioj.js → use-post-referrers-C2mXyrp-.js} +1 -1
- package/core/built/admin/assets/use-query-params-DHhhu8wi.js +1 -0
- package/core/built/admin/assets/{use-reply-chain-data-RLdPKRmS.js → use-reply-chain-data-DaK8q2qQ.js} +1 -1
- package/core/built/admin/assets/use-setting-group-YlYcoNyP.js +1 -0
- package/core/built/admin/assets/use-settings-navigation-Bf1g1rEh.js +1 -0
- package/core/built/admin/assets/{use-simple-pagination-DgcF69KI.js → use-simple-pagination-D9ckKo5-.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-query-C1R_Kbmy.js → use-tinybird-query-GSa32hVw.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-C9fPjVM_.js → use-tinybird-token-CKLOZFsw.js} +1 -1
- package/core/built/admin/assets/use-url-input-z-p0Kewm.js +5 -0
- package/core/built/admin/assets/user-detail-modal-BMxOA4Sv.js +1 -0
- package/core/built/admin/assets/{users-Dkv8NQZe.js → users-B6hIds6n.js} +1 -1
- package/core/built/admin/assets/validator-Cr0sMKuW.js +7 -0
- package/core/built/admin/assets/{virtual-list-BmTUzeoF.js → virtual-list-RHeEL05L.js} +1 -1
- package/core/built/admin/assets/web-Bw2QMO5u.js +2 -0
- package/core/built/admin/assets/web-xJtcwMy4.js +1 -0
- package/core/built/admin/assets/zapier-modal-BP2f4-vY.js +1 -0
- package/core/built/admin/index.html +15 -13
- package/core/frontend/helpers/authors.js +1 -1
- package/core/frontend/helpers/link.js +3 -8
- package/core/frontend/helpers/tags.js +1 -1
- package/core/frontend/meta/author-url.js +2 -2
- package/core/frontend/meta/url.js +4 -4
- package/core/frontend/services/proxy.js +1 -1
- package/core/frontend/services/routing/events.js +20 -6
- package/core/frontend/services/routing/permalink-adapter.js +0 -13
- package/core/frontend/services/routing/permalink-adapter.ts +0 -13
- package/core/frontend/services/routing/router-manager.js +15 -9
- package/core/frontend/services/sitemap/base-site-map-generator.js +1 -28
- package/core/frontend/services/sitemap/site-map-manager.js +22 -57
- package/core/server/adapters/route-settings/utils.js +10 -2
- package/core/server/adapters/route-settings/utils.ts +12 -2
- package/core/server/api/endpoints/email-post.js +1 -1
- package/core/server/api/endpoints/previews.js +1 -1
- package/core/server/api/endpoints/search-index-public.js +3 -3
- package/core/server/api/endpoints/search-index.js +4 -4
- package/core/server/api/endpoints/utils/serializers/input/authors.js +2 -2
- package/core/server/api/endpoints/utils/serializers/input/comments.js +1 -1
- package/core/server/api/endpoints/utils/serializers/input/pages.js +3 -3
- package/core/server/api/endpoints/utils/serializers/input/posts.js +3 -3
- package/core/server/api/endpoints/utils/serializers/input/tags.js +1 -1
- package/core/server/api/endpoints/utils/serializers/input/users.js +2 -2
- package/core/server/api/endpoints/utils/serializers/input/utils/url.js +31 -13
- package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +2 -2
- package/core/server/api/endpoints/utils/serializers/output/mappers/tags.js +2 -2
- package/core/server/api/endpoints/utils/serializers/output/mappers/users.js +8 -0
- package/core/server/api/endpoints/utils/serializers/output/utils/url.js +18 -11
- package/core/server/data/migrations/versions/6.57/2026-08-04-18-00-00-store-custom-field-values-as-leaf-rows.js +74 -0
- package/core/server/data/migrations/versions/6.57/2026-08-04-18-54-14-reset-automation-email-analytics.js +25 -0
- package/core/server/data/schema/commands.js +21 -5
- package/core/server/data/schema/schema.js +24 -5
- package/core/server/lib/common/to-plain.ts +1 -1
- package/core/server/models/post.js +2 -2
- package/core/server/services/adapter-manager/adapter-manager.js +1 -45
- package/core/server/services/adapter-manager/adapter-manager.ts +2 -48
- package/core/server/services/adapter-manager/adapter-paths.js +24 -0
- package/core/server/services/adapter-manager/adapter-paths.ts +21 -0
- package/core/server/services/adapter-manager/base-classes.js +22 -0
- package/core/server/services/adapter-manager/base-classes.ts +22 -0
- package/core/server/services/adapter-manager/index.js +4 -27
- package/core/server/services/adapter-manager/index.ts +4 -31
- package/core/server/services/adapter-manager/utils.js +50 -0
- package/core/server/services/adapter-manager/utils.ts +57 -0
- package/core/server/services/audience-feedback/audience-feedback-controller.js +1 -1
- package/core/server/services/audience-feedback/audience-feedback-service.js +2 -2
- package/core/server/services/automations/service.js +2 -2
- package/core/server/services/automations/service.ts +2 -2
- package/core/server/services/comments/comments-service-emails.js +1 -1
- package/core/server/services/comments/comments-service.js +1 -1
- package/core/server/services/email-analytics/email-analytics-service-wrapper.js +11 -2
- package/core/server/services/email-analytics/email-analytics-service.js +1 -1
- package/core/server/services/email-service/email-service-wrapper.js +2 -1
- package/core/server/services/email-service/mailgun-email-provider.js +15 -0
- package/core/server/services/indexnow-ping/indexnow-ping-service.js +1 -1
- package/core/server/services/indexnow-ping/indexnow-ping-service.ts +2 -4
- package/core/server/services/lib/mailgun-client.js +3 -3
- package/core/server/services/media-inliner/external-media-inliner.js +12 -8
- package/core/server/services/member-attribution/url-translator.js +5 -7
- package/core/server/services/member-welcome-emails/service.js +72 -12
- package/core/server/services/members/api.js +1 -1
- package/core/server/services/members/import-export/import/completion-email.js +8 -4
- package/core/server/services/members/import-export/import/completion-email.ts +9 -4
- package/core/server/services/members/import-export/import/importer.js +25 -4
- package/core/server/services/members/import-export/import/importer.ts +26 -6
- package/core/server/services/members/import-export/import/row.ts +5 -1
- package/core/server/services/members/import-export/index.js +1 -5
- package/core/server/services/members/import-export/index.ts +2 -6
- package/core/server/services/members-custom-fields/queries.js +4 -13
- package/core/server/services/members-custom-fields/queries.ts +4 -13
- package/core/server/services/members-custom-fields/schema.js +18 -27
- package/core/server/services/members-custom-fields/schema.ts +17 -27
- package/core/server/services/members-custom-fields/storage.js +94 -27
- package/core/server/services/members-custom-fields/storage.ts +114 -39
- package/core/server/services/members-custom-fields/values-service.js +98 -219
- package/core/server/services/members-custom-fields/values-service.ts +110 -238
- package/core/server/services/mentions/resource-service.js +1 -1
- package/core/server/services/mentions/service.js +2 -2
- package/core/server/services/route-settings/dynamic-routing-service.js +9 -59
- package/core/server/services/slack-ping/slack-ping-service.js +2 -2
- package/core/server/services/slack-ping/slack-ping-service.ts +3 -5
- package/core/server/services/stats/content-stats-service.js +3 -3
- package/core/server/services/stats/posts-stats-service.js +2 -2
- package/core/server/services/url/config.js +90 -135
- package/core/server/services/url/index.js +6 -49
- package/core/server/services/url/lazy-find-resource.js +14 -11
- package/core/server/services/url/lazy-find-resource.ts +14 -11
- package/core/server/services/url/lazy-url-service.js +174 -94
- package/core/server/services/url/lazy-url-service.ts +233 -97
- package/core/server/services/url/routable-resources.js +62 -71
- package/core/server/services/url/router-filter.js +12 -4
- package/core/server/services/url/router-filter.ts +12 -4
- package/core/server/services/webhooks/index.js +1 -1
- package/core/server/services/webhooks/serialize.js +2 -1
- package/core/shared/config/env/config.testing-mysql.json +1 -2
- package/core/shared/config/env/config.testing.json +1 -2
- package/core/shared/events/index.js +1 -2
- package/core/shared/labs.js +3 -3
- package/package.json +5 -6
- package/pnpm-lock.yaml +6 -9
- package/pnpm-workspace.yaml +2 -2
- package/tsconfig.json +1 -0
- package/core/built/admin/assets/Combination-BCm9FL4o.js +0 -41
- package/core/built/admin/assets/activitypub/layout-CTgrezN7.js +0 -1
- package/core/built/admin/assets/automated-emails-6t2bIRWf.js +0 -7
- package/core/built/admin/assets/checkbox-BIl077a0.js +0 -1
- package/core/built/admin/assets/code-editor-view-C0aWNwdl.js +0 -1
- package/core/built/admin/assets/comments-qwhIjH3c.js +0 -1
- package/core/built/admin/assets/disabled-sources-indicator-DYAXW-6V.js +0 -1
- package/core/built/admin/assets/dist-BUKmD51u.js +0 -1
- package/core/built/admin/assets/dist-CNlMj7ML.js +0 -1
- package/core/built/admin/assets/dist-DDY6GRVz.js +0 -1
- package/core/built/admin/assets/dist-DG78yroX.js +0 -23
- package/core/built/admin/assets/editor-DDYSOXGN.js +0 -8
- package/core/built/admin/assets/esm-CFX93H5M.js +0 -2
- package/core/built/admin/assets/filters-CLehPo_D.js +0 -1
- package/core/built/admin/assets/index-08n05-rc.js +0 -67
- package/core/built/admin/assets/index-DgUzgFvS.css +0 -1
- package/core/built/admin/assets/label-picker-DVnpu_IF.js +0 -1
- package/core/built/admin/assets/layout-B0YLh7R9.js +0 -1
- package/core/built/admin/assets/member-custom-fields-C8NpZYza.js +0 -1
- package/core/built/admin/assets/member-detail-CIVAdKXf.js +0 -1
- package/core/built/admin/assets/members-oLPiSkXD.js +0 -10
- package/core/built/admin/assets/modals-CB7v-k3T.js +0 -31
- package/core/built/admin/assets/newsletter-rbeDX9Wk.js +0 -1
- package/core/built/admin/assets/overview--4V-kx9c.js +0 -1
- package/core/built/admin/assets/overview-DSLv30oz.js +0 -1
- package/core/built/admin/assets/post-analytics-header-pU2m9ZuV.js +0 -1
- package/core/built/admin/assets/preferences-Ru4CRPHC.js +0 -5
- package/core/built/admin/assets/profile-BNb1oj7D.js +0 -1
- package/core/built/admin/assets/select-B0HteHrp.js +0 -1
- package/core/built/admin/assets/settings-B1C9Q3wo.js +0 -4
- package/core/built/admin/assets/social-urls-DA2lXrhW.js +0 -8
- package/core/built/admin/assets/switch-CyQcwMAv.js +0 -1
- package/core/built/admin/assets/tabs-D4y1gqUd.js +0 -1
- package/core/built/admin/assets/tags-Dmft-Y4O.js +0 -1
- package/core/built/admin/assets/toggle-group-R2QMFvXW.js +0 -1
- package/core/built/admin/assets/use-filter-params-WrdhAISv.js +0 -1
- package/core/built/admin/assets/web-BqW0b0_C.js +0 -1
- package/core/built/admin/assets/web-Cy5GKMWM.js +0 -2
- package/core/server/services/url/local-file-cache.js +0 -75
- package/core/server/services/url/queue.js +0 -260
- package/core/server/services/url/resource.js +0 -102
- package/core/server/services/url/resources.js +0 -480
- package/core/server/services/url/url-generator.js +0 -276
- package/core/server/services/url/url-service-facade.js +0 -366
- package/core/server/services/url/url-service-facade.ts +0 -519
- package/core/server/services/url/url-service.js +0 -387
- package/core/server/services/url/urls.js +0 -140
- package/core/shared/events/url-resource-updated-event.js +0 -33
- /package/core/built/admin/assets/{dist-CqO2lWS0.js → dist-CqO2lWS02.js} +0 -0
|
@@ -1,480 +0,0 @@
|
|
|
1
|
-
const _ = require('lodash');
|
|
2
|
-
const debug = require('@tryghost/debug')('services:url:resources');
|
|
3
|
-
const DomainEvents = require('@tryghost/domain-events');
|
|
4
|
-
const {URLResourceUpdatedEvent} = require('../../../shared/events');
|
|
5
|
-
const Resource = require('./resource');
|
|
6
|
-
const models = require('../../models');
|
|
7
|
-
const DatabaseInfo = require('@tryghost/database-info');
|
|
8
|
-
|
|
9
|
-
// This listens to all manner of model events to find new content that needs a URL...
|
|
10
|
-
const events = require('../../lib/common/events');
|
|
11
|
-
|
|
12
|
-
/** @typedef {'posts' | 'pages' | 'tags' | 'authors'} ResourceType */
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @description At the moment the resources class is directly responsible for data population
|
|
16
|
-
* for URLs...but because it's actually a storage cache of all published
|
|
17
|
-
* resources in the system, could also be used as a cache for Content API in
|
|
18
|
-
* the future.
|
|
19
|
-
*
|
|
20
|
-
* Each entry in the database will be represented by a "Resource" (see /Resource.js).
|
|
21
|
-
*/
|
|
22
|
-
class Resources {
|
|
23
|
-
/**
|
|
24
|
-
*
|
|
25
|
-
* @param {Object} options
|
|
26
|
-
* @param {Object} [options.resources] - resources to initialize with instead of fetching them from the database
|
|
27
|
-
* @param {Object} [options.queue] - instance of the Queue class
|
|
28
|
-
* @param {Object[]} [options.resourcesConfig] - resource config used when handling resource events and fetching
|
|
29
|
-
*/
|
|
30
|
-
constructor({resources = {}, queue, resourcesConfig = []} = {}) {
|
|
31
|
-
this.queue = queue;
|
|
32
|
-
this.resourcesConfig = resourcesConfig;
|
|
33
|
-
this.data = resources;
|
|
34
|
-
|
|
35
|
-
this.listeners = [];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @description Little helper to register on Ghost events and remember the listener functions to be able
|
|
40
|
-
* to unsubscribe.
|
|
41
|
-
*
|
|
42
|
-
* @param {string} eventName
|
|
43
|
-
* @param {Function} listener
|
|
44
|
-
* @private
|
|
45
|
-
*/
|
|
46
|
-
_listenOn(eventName, listener) {
|
|
47
|
-
this.listeners.push({
|
|
48
|
-
eventName: eventName,
|
|
49
|
-
listener: listener
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
events.on(eventName, listener);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* @description Helper function to initialize data fetching.
|
|
57
|
-
*/
|
|
58
|
-
async fetchResources() {
|
|
59
|
-
const ops = [];
|
|
60
|
-
debug('fetchResources');
|
|
61
|
-
|
|
62
|
-
// NOTE: Iterate over all resource types (posts, users etc..) and call `_fetch`.
|
|
63
|
-
_.each(this.resourcesConfig, (resourceConfig) => {
|
|
64
|
-
this.data[resourceConfig.type] = [];
|
|
65
|
-
|
|
66
|
-
// NOTE: We are querying knex directly, because the Bookshelf ORM overhead is too slow.
|
|
67
|
-
ops.push(this._fetch(resourceConfig));
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
await Promise.all(ops);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* @description Each resource type needs to register resource/model events to get notified
|
|
75
|
-
* about updates/deletions/inserts.
|
|
76
|
-
*
|
|
77
|
-
* For example for a "tag" resource type with following configuration:
|
|
78
|
-
* events: {
|
|
79
|
-
* add: 'tag.added',
|
|
80
|
-
* update: ['tag.edited', 'tag.attached', 'tag.detached'],
|
|
81
|
-
* remove: 'tag.deleted'
|
|
82
|
-
* }
|
|
83
|
-
* there would be:
|
|
84
|
-
* 1 event listener connected to "_onResourceAdded" handler and it's 'tag.added' event
|
|
85
|
-
* 3 event listeners connected to "_onResourceUpdated" handler and it's 'tag.edited', 'tag.attached', 'tag.detached' events
|
|
86
|
-
* 1 event listener connected to "_onResourceRemoved" handler and it's 'tag.deleted' event
|
|
87
|
-
*/
|
|
88
|
-
initEventListeners() {
|
|
89
|
-
_.each(this.resourcesConfig, (resourceConfig) => {
|
|
90
|
-
this.data[resourceConfig.type] = [];
|
|
91
|
-
|
|
92
|
-
this._listenOn(resourceConfig.events.add, async (model) => {
|
|
93
|
-
await this._onResourceAdded(resourceConfig.type, model);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
if (_.isArray(resourceConfig.events.update)) {
|
|
97
|
-
resourceConfig.events.update.forEach((event) => {
|
|
98
|
-
this._listenOn(event, async (model) => {
|
|
99
|
-
await this._onResourceUpdated(resourceConfig.type, model);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
} else {
|
|
103
|
-
this._listenOn(resourceConfig.events.update, async (model) => {
|
|
104
|
-
await this._onResourceUpdated(resourceConfig.type, model);
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this._listenOn(resourceConfig.events.remove, (model) => {
|
|
109
|
-
this._onResourceRemoved(resourceConfig.type, model);
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* @description The actual call to the model layer, which will execute raw knex queries to ensure performance.
|
|
116
|
-
* @param {Object} resourceConfig
|
|
117
|
-
* @param {Object} options
|
|
118
|
-
* @returns {Promise}
|
|
119
|
-
* @private
|
|
120
|
-
*/
|
|
121
|
-
async _fetch(resourceConfig, options = {offset: 0, limit: 999}) {
|
|
122
|
-
debug('_fetch', resourceConfig.type, resourceConfig.modelOptions);
|
|
123
|
-
|
|
124
|
-
let modelOptions = _.cloneDeep(resourceConfig.modelOptions);
|
|
125
|
-
const isSQLite = DatabaseInfo.isSQLite(models.Base.knex);
|
|
126
|
-
|
|
127
|
-
// CASE: prevent "too many SQL variables" error on SQLite3 (https://github.com/TryGhost/Ghost/issues/5810)
|
|
128
|
-
if (isSQLite) {
|
|
129
|
-
modelOptions.offset = options.offset;
|
|
130
|
-
modelOptions.limit = options.limit;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const now = Date.now();
|
|
134
|
-
const objects = await models.Base.Model.raw_knex.fetchAll(modelOptions);
|
|
135
|
-
debug('_fetch.fetched', resourceConfig.type, objects.length, `${Date.now() - now}ms`);
|
|
136
|
-
|
|
137
|
-
for (const object of objects) {
|
|
138
|
-
this.data[resourceConfig.type].push(new Resource(resourceConfig.type, object));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (objects.length && isSQLite) {
|
|
142
|
-
options.offset = options.offset + options.limit;
|
|
143
|
-
return this._fetch(resourceConfig, {offset: options.offset, limit: options.limit});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return objects;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* @description Call the model layer to fetch a single resource via raw knex queries.
|
|
151
|
-
*
|
|
152
|
-
* This function was invented, because the model event is a generic event, which is independent of any
|
|
153
|
-
* api version behavior. We have to ensure that a model matches the conditions of the configured api version
|
|
154
|
-
* in the theme.
|
|
155
|
-
*
|
|
156
|
-
* See https://github.com/TryGhost/Ghost/issues/10124.
|
|
157
|
-
*
|
|
158
|
-
* @param {Object} resourceConfig
|
|
159
|
-
* @param {string} id
|
|
160
|
-
* @returns {Promise}
|
|
161
|
-
* @private
|
|
162
|
-
*/
|
|
163
|
-
_fetchSingle(resourceConfig, id) {
|
|
164
|
-
let modelOptions = _.cloneDeep(resourceConfig.modelOptions);
|
|
165
|
-
modelOptions.id = id;
|
|
166
|
-
|
|
167
|
-
return models.Base.Model.raw_knex.fetchAll(modelOptions);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* @description Helper function to prepare the received model's relations.
|
|
172
|
-
*
|
|
173
|
-
* This helper was added to reduce the number of fields we keep in cache for relations.
|
|
174
|
-
*
|
|
175
|
-
* If we resolve (https://github.com/TryGhost/Ghost/issues/10360) and talk to the Content API,
|
|
176
|
-
* we could pass on e.g. `?include=authors&fields=authors.id,authors.slug`, but the API has to support it.
|
|
177
|
-
*
|
|
178
|
-
* @param {import('bookshelf').Model} model
|
|
179
|
-
* @param {Object} resourceConfig
|
|
180
|
-
* @private
|
|
181
|
-
*/
|
|
182
|
-
_prepareModelSync(model, resourceConfig) {
|
|
183
|
-
const exclude = resourceConfig.modelOptions.exclude;
|
|
184
|
-
const withRelatedFields = resourceConfig.modelOptions.withRelatedFields;
|
|
185
|
-
const obj = _.omit(model.toJSON(), exclude);
|
|
186
|
-
|
|
187
|
-
if (withRelatedFields) {
|
|
188
|
-
_.each(withRelatedFields, (fields, key) => {
|
|
189
|
-
if (!obj[key]) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
obj[key] = _.map(obj[key], (relation) => {
|
|
194
|
-
const relationToReturn = {};
|
|
195
|
-
|
|
196
|
-
_.each(fields, (field) => {
|
|
197
|
-
const fieldSanitized = field.replace(/^\w+./, '');
|
|
198
|
-
relationToReturn[fieldSanitized] = relation[fieldSanitized];
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
return relationToReturn;
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
const withRelatedPrimary = resourceConfig.modelOptions.withRelatedPrimary;
|
|
206
|
-
|
|
207
|
-
if (withRelatedPrimary) {
|
|
208
|
-
_.each(withRelatedPrimary, (relation, primaryKey) => {
|
|
209
|
-
if (!obj[primaryKey] || !obj[relation]) {
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const targetTagKeys = Object.keys(obj[relation].find((item) => {
|
|
214
|
-
return item.id === obj[primaryKey].id;
|
|
215
|
-
}));
|
|
216
|
-
obj[primaryKey] = _.pick(obj[primaryKey], targetTagKeys);
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return obj;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* @description Listener for "model added" event.
|
|
226
|
-
*
|
|
227
|
-
* If we receive an event from the model layer, we push the new resource into the queue.
|
|
228
|
-
* The subscribers (the url generators) have registered for this event and the queue will call
|
|
229
|
-
* all subscribers sequentially. The first generator, where the conditions match the resource, will
|
|
230
|
-
* own the resource and it's url.
|
|
231
|
-
*
|
|
232
|
-
* @param {ResourceType} type
|
|
233
|
-
* @param {import('bookshelf').Model} model
|
|
234
|
-
* @private
|
|
235
|
-
*/
|
|
236
|
-
async _onResourceAdded(type, model) {
|
|
237
|
-
debug('_onResourceAdded', type);
|
|
238
|
-
|
|
239
|
-
const resourceConfig = _.find(this.resourcesConfig, {type: type});
|
|
240
|
-
|
|
241
|
-
// NOTE: synchronous handling for post and pages so that their URL is available without a delay
|
|
242
|
-
// for more context and future improvements check https://github.com/TryGhost/Ghost/issues/10360
|
|
243
|
-
if (['posts', 'pages'].includes(type)) {
|
|
244
|
-
const obj = this._prepareModelSync(model, resourceConfig);
|
|
245
|
-
|
|
246
|
-
const resource = new Resource(type, obj);
|
|
247
|
-
|
|
248
|
-
debug('_onResourceAdded', type);
|
|
249
|
-
this.data[type].push(resource);
|
|
250
|
-
|
|
251
|
-
this.queue.start({
|
|
252
|
-
event: 'added',
|
|
253
|
-
action: 'added:' + model.id,
|
|
254
|
-
eventData: {
|
|
255
|
-
id: model.id,
|
|
256
|
-
type: type
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
} else {
|
|
260
|
-
const [dbResource] = await this._fetchSingle(resourceConfig, model.id);
|
|
261
|
-
|
|
262
|
-
if (dbResource) {
|
|
263
|
-
const resource = new Resource(type, dbResource);
|
|
264
|
-
|
|
265
|
-
debug('_onResourceAdded', type);
|
|
266
|
-
this.data[type].push(resource);
|
|
267
|
-
|
|
268
|
-
this.queue.start({
|
|
269
|
-
event: 'added',
|
|
270
|
-
action: 'added:' + model.id,
|
|
271
|
-
eventData: {
|
|
272
|
-
id: model.id,
|
|
273
|
-
type: type
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
*
|
|
282
|
-
* @param {Object} model resource model
|
|
283
|
-
* @returns
|
|
284
|
-
*/
|
|
285
|
-
_containsRoutingAffectingChanges(model, ignoredProperties) {
|
|
286
|
-
if (model._changed && Object.keys(model._changed).length) {
|
|
287
|
-
return _.difference(Object.keys(model._changed), ignoredProperties).length !== 0;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// NOTE: returning true here as "_changed" property might not be available on attached/detached events
|
|
291
|
-
// assuming there were route affecting changes by default
|
|
292
|
-
return true;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* @description Listener for "model updated" event.
|
|
297
|
-
*
|
|
298
|
-
* CASE:
|
|
299
|
-
* - post was fetched on bootstrap
|
|
300
|
-
* - that means, the post is already published
|
|
301
|
-
* - resource exists, but nobody owns it
|
|
302
|
-
* - if the model changes, it can be that somebody will then own the post
|
|
303
|
-
*
|
|
304
|
-
* CASE:
|
|
305
|
-
* - post was fetched on bootstrap
|
|
306
|
-
* - that means, the post is already published
|
|
307
|
-
* - resource exists and is owned by somebody
|
|
308
|
-
* - but the data changed and is maybe no longer owned?
|
|
309
|
-
* - e.g. featured:false changes and your filter requires featured posts
|
|
310
|
-
*
|
|
311
|
-
* @param {ResourceType} type
|
|
312
|
-
* @param {import('bookshelf').Model} model
|
|
313
|
-
* @private
|
|
314
|
-
*/
|
|
315
|
-
async _onResourceUpdated(type, model) {
|
|
316
|
-
debug('_onResourceUpdated', type);
|
|
317
|
-
|
|
318
|
-
const resourceConfig = _.find(this.resourcesConfig, {type: type});
|
|
319
|
-
|
|
320
|
-
// NOTE: check if any of the route-related fields were changed and only proceed if so
|
|
321
|
-
const ignoredProperties = [...resourceConfig.modelOptions.exclude, 'updated_at'];
|
|
322
|
-
if (!this._containsRoutingAffectingChanges(model, ignoredProperties)) {
|
|
323
|
-
const cachedResource = this.getByIdAndType(type, model.id);
|
|
324
|
-
|
|
325
|
-
if (cachedResource && model._changed && Object.keys(model._changed).includes('updated_at')) {
|
|
326
|
-
DomainEvents.dispatch(URLResourceUpdatedEvent.create(Object.assign(cachedResource.data, {
|
|
327
|
-
resourceType: cachedResource.config.type,
|
|
328
|
-
updated_at: model._changed.updated_at
|
|
329
|
-
})));
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
debug('skipping _onResourceUpdated because only non-route-related properties changed');
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// NOTE: synchronous handling for post and pages so that their URL is available without a delay
|
|
337
|
-
// for more context and future improvements check https://github.com/TryGhost/Ghost/issues/10360
|
|
338
|
-
if (['posts', 'pages'].includes(type)) {
|
|
339
|
-
// CASE: search for the target resource in the cache
|
|
340
|
-
this.data[type].every((resource) => {
|
|
341
|
-
if (resource.data.id === model.id) {
|
|
342
|
-
const obj = this._prepareModelSync(model, resourceConfig);
|
|
343
|
-
|
|
344
|
-
resource.update(obj);
|
|
345
|
-
|
|
346
|
-
// CASE: Resource is not owned, try to add it again (data has changed, it could be that somebody will own it now)
|
|
347
|
-
if (!resource.isReserved()) {
|
|
348
|
-
this.queue.start({
|
|
349
|
-
event: 'added',
|
|
350
|
-
action: 'added:' + model.id,
|
|
351
|
-
eventData: {
|
|
352
|
-
id: model.id,
|
|
353
|
-
type: type
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// break!
|
|
359
|
-
return false;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return true;
|
|
363
|
-
});
|
|
364
|
-
} else {
|
|
365
|
-
const [dbResource] = await this._fetchSingle(resourceConfig, model.id);
|
|
366
|
-
|
|
367
|
-
const resource = this.data[type].find(r => (r.data.id === model.id));
|
|
368
|
-
|
|
369
|
-
// CASE: cached resource exists, API conditions matched with the data in the db
|
|
370
|
-
if (resource && dbResource) {
|
|
371
|
-
resource.update(dbResource);
|
|
372
|
-
|
|
373
|
-
// CASE: pretend it was added
|
|
374
|
-
if (!resource.isReserved()) {
|
|
375
|
-
this.queue.start({
|
|
376
|
-
event: 'added',
|
|
377
|
-
action: 'added:' + dbResource.id,
|
|
378
|
-
eventData: {
|
|
379
|
-
id: dbResource.id,
|
|
380
|
-
type: type
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
} else if (!resource && dbResource) {
|
|
385
|
-
await this._onResourceAdded(type, model);
|
|
386
|
-
} else if (resource && !dbResource) {
|
|
387
|
-
await this._onResourceRemoved(type, model);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* @description Listener for "model removed" event.
|
|
394
|
-
* @param {ResourceType} type
|
|
395
|
-
* @param {import('bookshelf').Model} model
|
|
396
|
-
* @private
|
|
397
|
-
*/
|
|
398
|
-
_onResourceRemoved(type, model) {
|
|
399
|
-
debug('_onResourceRemoved', type);
|
|
400
|
-
|
|
401
|
-
const resourceId = model._previousAttributes.id;
|
|
402
|
-
const index = this.data[type].findIndex(resource => resource.data.id === resourceId);
|
|
403
|
-
|
|
404
|
-
// Resource might not be in cache if e.g. visibility was internal
|
|
405
|
-
if (index === -1) {
|
|
406
|
-
debug('Resource not found in cache', resourceId);
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// remove the resource from cache
|
|
411
|
-
const [removedResource] = this.data[type].splice(index, 1);
|
|
412
|
-
removedResource.remove();
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* @description Get all cached resources.
|
|
417
|
-
* @returns {Object}
|
|
418
|
-
*/
|
|
419
|
-
getAll() {
|
|
420
|
-
return this.data;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* @description Get all cached resourced by type.
|
|
425
|
-
* @param {ResourceType} type
|
|
426
|
-
* @returns {Object}
|
|
427
|
-
*/
|
|
428
|
-
getAllByType(type) {
|
|
429
|
-
return this.data[type];
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* @description Get all cached resourced by resource id and type.
|
|
434
|
-
* @param {ResourceType} type
|
|
435
|
-
* @param {string} id
|
|
436
|
-
* @returns {Object}
|
|
437
|
-
*/
|
|
438
|
-
getByIdAndType(type, id) {
|
|
439
|
-
return this.data[type]?.find(r => r.data.id === id);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* @description Reset this class instance.
|
|
444
|
-
*
|
|
445
|
-
* Is triggered if you switch API versions.
|
|
446
|
-
*/
|
|
447
|
-
reset() {
|
|
448
|
-
_.each(this.listeners, (obj) => {
|
|
449
|
-
events.removeListener(obj.eventName, obj.listener);
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
this.listeners = [];
|
|
453
|
-
this.data = {};
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* @description Soft reset this class instance. Only used for test env.
|
|
458
|
-
* It will only clear the cache.
|
|
459
|
-
*/
|
|
460
|
-
softReset() {
|
|
461
|
-
this.data = {};
|
|
462
|
-
|
|
463
|
-
_.each(this.resourcesConfig, (resourceConfig) => {
|
|
464
|
-
this.data[resourceConfig.type] = [];
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* @description Release all resources. Get's called during "reset".
|
|
470
|
-
*/
|
|
471
|
-
releaseAll() {
|
|
472
|
-
_.each(this.data, (resources, type) => {
|
|
473
|
-
_.each(this.data[type], (resource) => {
|
|
474
|
-
resource.release();
|
|
475
|
-
});
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
module.exports = Resources;
|