ghost 6.53.0 → 6.54.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/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.1.1.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-CSaHoSVD.js +3 -0
- package/core/built/admin/assets/Newsletters-C5cs6FGo.js +1 -0
- package/core/built/admin/assets/Overview-j4NaeUNm.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-_fD935OX.js +2 -0
- package/core/built/admin/assets/account-migration-DLvVA5yq.js +1 -0
- package/core/built/admin/assets/activitypub/{account-migration-BPZG37DJ.js → account-migration-DHbZcxGM.js} +13 -13
- package/core/built/admin/assets/activitypub/activitypub.js +7 -7
- 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-zfxUey_L.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-B5ira32t.js → dist-Ba_QxHHl.js} +5 -5
- package/core/built/admin/assets/activitypub/{domain-iqE4YXwD.js → domain-CmwSZLHK.js} +33 -33
- package/core/built/admin/assets/activitypub/{edit-profile-B8MFYh28.js → edit-profile-CXdwNmVG.js} +46 -45
- package/core/built/admin/assets/activitypub/{explore-BbdKodp3.js → explore-DfbjzGM1.js} +20 -20
- package/core/built/admin/assets/activitypub/{feed-Cl3A5owG.js → feed-DSEBJOqf.js} +15 -15
- package/core/built/admin/assets/activitypub/{field-DL6WyR-c.js → field-CY7XVcx6.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-DtQ0kytT.js +1221 -0
- package/core/built/admin/assets/activitypub/{label-DGbLjDvE.js → label-Dw96GQ7u.js} +6 -6
- package/core/built/admin/assets/activitypub/layout-IdVq3lRy.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-qnBtk1zS.js → moderation-Dg_-I-8C.js} +32 -31
- package/core/built/admin/assets/activitypub/{note-C7ZRoSJv.js → note-Cy1-uKMY.js} +21 -21
- package/core/built/admin/assets/activitypub/{notifications-DiEA4b1o.js → notifications-B_fvoLIM.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-ByJseZp6.js} +1607 -1606
- package/core/built/admin/assets/activitypub/{profile-D8ZJfYXB.js → profile-BFtbnIjz.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-Dh3xXfce.js} +1311 -1295
- package/core/built/admin/assets/activitypub/{separator-1gNokN5S.js → separator-BI1FLsYM.js} +4 -4
- package/core/built/admin/assets/activitypub/{settings--9Sb0nbl.js → settings-DTgqJPxM.js} +14 -14
- package/core/built/admin/assets/activitypub/{site-fkMmqv0V.js → site-CdL9ZLqm.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-ogqwoBlb.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-CxonteFD.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-BKRdsFmy.js} +1 -1
- package/core/built/admin/assets/{automated-emails-UWM02CMr.js → automated-emails-Cn87L5Md.js} +1 -1
- package/core/built/admin/assets/automations-B7-y3dXt.js +1 -0
- package/core/built/admin/assets/automations-BP_aHamJ.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-Bh36XPh4.js +1 -0
- package/core/built/admin/assets/box-BWbhXh21.js +1 -0
- package/core/built/admin/assets/breadcrumb-D34YWnaw.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-DbklaJw9.js +1 -0
- package/core/built/admin/assets/checkbox-DA4-1UiI.js +1 -0
- package/core/built/admin/assets/chunk.524.45e0875f41b71e46e849.js +25 -0
- package/core/built/admin/assets/chunk.582.51defd4b009f0de8d4d5.js +27 -0
- package/core/built/admin/assets/{chunk.831.0703a12e49f51cec3f3a.js → chunk.589.096f4d0bb775e5229aa9.js} +78 -85
- package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js → chunk.962.b73442b07be930bb5d85.js} +2216 -3188
- package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js.LICENSE.txt → chunk.962.b73442b07be930bb5d85.js.LICENSE.txt} +0 -63
- package/core/built/admin/assets/code-editor-view-BKBrkffZ.js +1 -0
- package/core/built/admin/assets/comments-CzVNIT8b.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-B5vSsrpx.js +1 -0
- package/core/built/admin/assets/disabled-sources-indicator-NkOIoMue.js +1 -0
- package/core/built/admin/assets/{dist-CsekE4FL.js → dist-CQJY6SVY.js} +1 -1
- package/core/built/admin/assets/dist-DGzPJ_bO.js +4 -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-B7_n5nfx.js +1 -0
- package/core/built/admin/assets/dropzone-DcuJEEUf.js +5 -0
- package/core/built/admin/assets/edit-profile-rvDGrS8J.js +1 -0
- package/core/built/admin/assets/editor-BCiIyFjm.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-BZAZOg5X.js +1 -0
- package/core/built/admin/assets/feed-CFV8xDw9.js +1 -0
- package/core/built/admin/assets/field-BW-M2Zwp.js +1 -0
- package/core/built/admin/assets/{filter-sources-v39ihhhV.js → filter-sources-Fx8wiYYw.js} +1 -1
- package/core/built/admin/assets/filters-CGX_pf2N.js +1 -0
- package/core/built/admin/assets/filters-DtcXMZDU.js +1 -0
- package/core/built/admin/assets/framework-provider-CmtnPXIT.js +4 -0
- package/core/built/admin/assets/{ghost-b57f077997b739a8ae9a70772dc016cb.js → ghost-b1dce91ad3232cc259ee5fbbf9526243.js} +294 -290
- package/core/built/admin/assets/ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css +1 -0
- package/core/built/admin/assets/gift-link-modal-Bk8qpnMw.js +1 -0
- package/core/built/admin/assets/{gift-links-CY3GwiVi.js → gift-links-nBxJjZiQ.js} +1 -1
- package/core/built/admin/assets/growth-Ck2s3JjR.js +1 -0
- package/core/built/admin/assets/hooks-BApwwBE0.js +2 -0
- package/core/built/admin/assets/{inbox-TEISAmth.js → inbox-BRp1_aaC.js} +35 -35
- package/core/built/admin/assets/index-BBf502Wg.js +69 -0
- package/core/built/admin/assets/index-BCCZKxP2.css +1 -0
- package/core/built/admin/assets/inline-EMAm3okk.js +1 -0
- package/core/built/admin/assets/input-group-DjuYnNCd.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-CM7UFNdL.js} +2 -2
- package/core/built/admin/assets/kpi-card-BrGH6FsT.js +1 -0
- package/core/built/admin/assets/kpi-card-CIGyijjx.js +1 -0
- package/core/built/admin/assets/kpi-helpers-_HRRsklE.js +1 -0
- package/core/built/admin/assets/kpi-tabs-BSvh9eoq.js +1 -0
- package/core/built/admin/assets/label-BOR9XdKl.js +1 -0
- package/core/built/admin/assets/label-picker-BdNAWuUX.js +1 -0
- package/core/built/admin/assets/{labels-GbxlXWtf.js → labels-Cyayfd-e.js} +1 -1
- package/core/built/admin/assets/layout-Bw4GnxXp.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-DvFyamLu.js +1 -0
- package/core/built/admin/assets/member-detail-Cg2vTqvJ.js +1 -0
- package/core/built/admin/assets/members-DsPxYAVm.js +10 -0
- package/core/built/admin/assets/modals-Bf_fyvHZ.js +31 -0
- package/core/built/admin/assets/moderation-Dlp7M5sa.js +1 -0
- package/core/built/admin/assets/multi-select-combobox-CH1o8XXQ.js +1 -0
- package/core/built/admin/assets/newsletter-CQ5CAYUI.js +1 -0
- package/core/built/admin/assets/{newsletters-DZm3yLj8.js → newsletters-D1jbtV-h.js} +1 -1
- package/core/built/admin/assets/note-BrAZ7Z0o.js +1 -0
- package/core/built/admin/assets/notifications-BnbHLOPC.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-eU146kuA.js +1 -0
- package/core/built/admin/assets/overview-BpbaK-xu.js +1 -0
- package/core/built/admin/assets/page-header-C0jVxtS8.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-Iw7dk1mT.js +1 -0
- package/core/built/admin/assets/post-analytics-header-D9pJ4iNm.js +1 -0
- package/core/built/admin/assets/{post-analytics-provider-DSfBCtnj.js → post-analytics-provider-BDqcfBor.js} +1 -1
- package/core/built/admin/assets/post-share-modal-DBfKl2GZ.js +1 -0
- package/core/built/admin/assets/{posts-CwH8VJvB.js → posts-EWpZIjkr.js} +1 -1
- package/core/built/admin/assets/preferences-D4EANGoc.js +5 -0
- package/core/built/admin/assets/profile-dJ44Bn_W.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--2uVN9_-.js +1 -0
- package/core/built/admin/assets/settings-Bz3RZRmE.js +1 -0
- package/core/built/admin/assets/settings-SD9bxIpt.js +4 -0
- package/core/built/admin/assets/share-modal-CkdTTMJd.js +1 -0
- package/core/built/admin/assets/social-urls-BvFZwYcE.js +8 -0
- package/core/built/admin/assets/sort-button-DZp9Y2r1.js +1 -0
- package/core/built/admin/assets/source-icon-CHr9qJ2Y.js +1 -0
- package/core/built/admin/assets/stack-xiN0eQ6Z.js +1 -0
- package/core/built/admin/assets/stats-DGoXZxWE.js +1 -0
- package/core/built/admin/assets/stats-view-D2-1L0ms.js +1 -0
- package/core/built/admin/assets/step-1-RdahbwyG.js +1 -0
- package/core/built/admin/assets/step-2-D83PeRwd.js +1 -0
- package/core/built/admin/assets/step-3-p_Op4wv4.js +2 -0
- package/core/built/admin/assets/switch-qp518gFQ.js +1 -0
- package/core/built/admin/assets/table-B8LgTQJZ.js +1 -0
- package/core/built/admin/assets/tabs-D3ZOYkM7.js +1 -0
- package/core/built/admin/assets/tags-B4l891z2.js +1 -0
- package/core/built/admin/assets/text-DwtjwGkh.js +1 -0
- package/core/built/admin/assets/textarea-CTlb3Uu6.js +1 -0
- package/core/built/admin/assets/{tiers-EghDzCKc.js → tiers-BgYLWRJv.js} +1 -1
- package/core/built/admin/assets/toggle-group-DNXDkAwf.js +1 -0
- package/core/built/admin/assets/topic-filter-DZGjEcz3.js +1 -0
- package/core/built/admin/assets/{use-analytics-data-0l_OHtnR.js → use-analytics-data-CaT8RirX.js} +1 -1
- package/core/built/admin/assets/use-filter-params-DeQ8sX4N.js +1 -0
- package/core/built/admin/assets/use-growth-stats-9Db2CuJe.js +1 -0
- package/core/built/admin/assets/{use-post-referrers-DwI31Ril.js → use-post-referrers-BV54YcQS.js} +1 -1
- package/core/built/admin/assets/use-reply-chain-data-DuYZGDan.js +1 -0
- package/core/built/admin/assets/use-simple-pagination-8fTua9Nt.js +1 -0
- package/core/built/admin/assets/{use-tinybird-query-DvZBBMG7.js → use-tinybird-query-Dz156HvZ.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-CQtebkvU.js → use-tinybird-token-C9RUdL_n.js} +1 -1
- package/core/built/admin/assets/{users-Pc8IRjk9.js → users-CcSCQFcQ.js} +1 -1
- package/core/built/admin/assets/virtual-list-BCvP0YF-.js +1 -0
- package/core/built/admin/assets/web-DTZnnUGr.js +1 -0
- package/core/built/admin/index.html +18 -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 +31 -2
- 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 +1 -1
- package/core/server/adapters/storage/LocalImagesStorage.js +1 -1
- package/core/server/adapters/storage/LocalMediaStorage.js +1 -1
- package/core/server/adapters/storage/LocalStorageBase.js +3 -3
- 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 +1 -1
- package/core/server/api/endpoints/authentication.js +1 -1
- 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/posts.js +17 -1
- 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/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 +16 -26
- 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/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/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 +5 -7
- package/core/server/lib/image/image-utils.js +2 -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/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 +1 -1
- 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 +1 -1
- package/core/server/services/automations/automations-api.js +2 -19
- package/core/server/services/automations/automations-api.ts +2 -31
- package/core/server/services/automations/automations-repository.ts +15 -0
- package/core/server/services/automations/database-automations-repository.js +30 -2
- package/core/server/services/automations/database-automations-repository.ts +33 -2
- 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/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/csv/index.js +10 -0
- package/core/server/services/members/csv/index.ts +3 -0
- package/core/server/services/members/csv/parse.js +94 -0
- package/core/server/services/members/csv/parse.ts +111 -0
- package/core/server/services/members/csv/types.js +2 -0
- package/core/server/services/members/csv/types.ts +39 -0
- package/core/server/services/members/csv/unparse.js +69 -0
- package/core/server/services/members/csv/unparse.ts +79 -0
- package/core/server/services/members/exporter/query.js +35 -8
- package/core/server/services/members/importer/config.js +35 -0
- package/core/server/services/members/importer/config.ts +39 -0
- package/core/server/services/members/importer/members-csv-importer.js +31 -13
- 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 +15 -2
- 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-service-instance.js +1 -1
- package/core/server/services/posts/posts-service.js +2 -2
- 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/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 +8 -1
- package/core/shared/config/overrides.json +4 -0
- package/core/shared/url-utils.js +19 -15
- package/core/shared/url-utils.ts +20 -0
- package/ghost.js +0 -1
- package/package.json +26 -31
- 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-DJ6c4_De.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
|
@@ -6,7 +6,7 @@ import type {InternalApiKey, InternalKeys} from '../internal-keys';
|
|
|
6
6
|
// CJS-only modules — typed loosely below. models is the Bookshelf registry
|
|
7
7
|
// without TS declarations; the rest are JS modules without types.
|
|
8
8
|
const models = require('../../models');
|
|
9
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
9
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
10
10
|
const {getSignedAdminToken} = require('../../adapters/scheduling/utils');
|
|
11
11
|
const events = require('../../lib/common/events');
|
|
12
12
|
|
|
@@ -22,13 +22,13 @@ class PostEmailHandler {
|
|
|
22
22
|
* Validates email can be sent before saving the post (if an email will be sent)
|
|
23
23
|
*
|
|
24
24
|
* @param {import('@tryghost/api-framework').Frame} frame
|
|
25
|
-
* @returns {Promise<
|
|
25
|
+
* @returns {Promise<{newsletter: Object, emailRecipientFilter: string, emailCount: number}|null>}
|
|
26
26
|
*/
|
|
27
27
|
async validateBeforeSave(frame) {
|
|
28
28
|
const newStatus = frame.data.posts[0].status;
|
|
29
29
|
|
|
30
30
|
if (!EMAIL_SENDING_STATUSES.includes(newStatus)) {
|
|
31
|
-
return;
|
|
31
|
+
return null;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const existingPost = await this.models.Post.findOne(
|
|
@@ -41,7 +41,7 @@ class PostEmailHandler {
|
|
|
41
41
|
const sendingEmail = hasNewsletter && this.shouldSendEmail(newStatus, previousStatus);
|
|
42
42
|
|
|
43
43
|
if (!sendingEmail) {
|
|
44
|
-
return;
|
|
44
|
+
return null;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const emailRecipientFilter = frame.options.email_segment || existingPost?.get('email_recipient_filter') || 'all';
|
|
@@ -50,7 +50,9 @@ class PostEmailHandler {
|
|
|
50
50
|
|
|
51
51
|
const newsletter = await this.getNewsletter(frame, existingPost);
|
|
52
52
|
|
|
53
|
-
await this.emailService.checkCanSendEmail(newsletter, emailRecipientFilter);
|
|
53
|
+
const {emailCount} = await this.emailService.checkCanSendEmail(newsletter, emailRecipientFilter);
|
|
54
|
+
|
|
55
|
+
return {newsletter, emailRecipientFilter, emailCount};
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
/**
|
|
@@ -97,9 +99,14 @@ class PostEmailHandler {
|
|
|
97
99
|
* Handles creating or retrying the newsletter email after post is saved
|
|
98
100
|
*
|
|
99
101
|
* @param {Object} model - The post model
|
|
102
|
+
* @param {Object} [options]
|
|
103
|
+
* @param {Object} [options.preflight] - Validation result from validateBeforeSave, passed through to createEmail
|
|
104
|
+
* @param {Object} [options.preflight.newsletter]
|
|
105
|
+
* @param {string} [options.preflight.emailRecipientFilter]
|
|
106
|
+
* @param {number} [options.preflight.emailCount]
|
|
100
107
|
* @returns {Promise<void>}
|
|
101
108
|
*/
|
|
102
|
-
async createOrRetryEmail(model) {
|
|
109
|
+
async createOrRetryEmail(model, {preflight} = {}) {
|
|
103
110
|
if (!model.get('newsletter_id')) {
|
|
104
111
|
return;
|
|
105
112
|
}
|
|
@@ -114,7 +121,7 @@ class PostEmailHandler {
|
|
|
114
121
|
let email;
|
|
115
122
|
|
|
116
123
|
if (!postEmail) {
|
|
117
|
-
email = await this.emailService.createEmail(model);
|
|
124
|
+
email = await this.emailService.createEmail(model, {preflight});
|
|
118
125
|
} else if (postEmail.get('status') === 'failed') {
|
|
119
126
|
email = await this.emailService.retryEmail(postEmail);
|
|
120
127
|
}
|
|
@@ -2,7 +2,7 @@ const _ = require('lodash');
|
|
|
2
2
|
const errors = require('@tryghost/errors');
|
|
3
3
|
const moment = require('moment');
|
|
4
4
|
const config = require('../../../shared/config');
|
|
5
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
5
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
6
6
|
const api = require('../../api').endpoints;
|
|
7
7
|
|
|
8
8
|
const messages = {
|
|
@@ -6,7 +6,7 @@ const url = require('../../../server/api/endpoints/utils/serializers/output/util
|
|
|
6
6
|
* @returns {InstanceType<PostsService>} instance of the PostsService
|
|
7
7
|
*/
|
|
8
8
|
const getPostServiceInstance = () => {
|
|
9
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
9
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
10
10
|
const labs = require('../../../shared/labs');
|
|
11
11
|
const models = require('../../models');
|
|
12
12
|
const PostStats = require('./stats/post-stats');
|
|
@@ -61,11 +61,11 @@ class PostsService {
|
|
|
61
61
|
* @returns
|
|
62
62
|
*/
|
|
63
63
|
async editPost(frame, options) {
|
|
64
|
-
await this.postEmailHandler.validateBeforeSave(frame);
|
|
64
|
+
const preflight = await this.postEmailHandler.validateBeforeSave(frame);
|
|
65
65
|
|
|
66
66
|
const model = await this.models.Post.edit(frame.data.posts[0], frame.options);
|
|
67
67
|
|
|
68
|
-
await this.postEmailHandler.createOrRetryEmail(model);
|
|
68
|
+
await this.postEmailHandler.createOrRetryEmail(model, {preflight});
|
|
69
69
|
|
|
70
70
|
const dto = model.toJSON(frame.options);
|
|
71
71
|
|
|
@@ -6,7 +6,7 @@ class PostsPublicServiceWrapper {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
// Wire up all the dependencies
|
|
9
|
-
const adapterManager = require('../adapter-manager');
|
|
9
|
+
const adapterManager = require('../adapter-manager').default;
|
|
10
10
|
const config = require('../../../shared/config');
|
|
11
11
|
const EventRegistry = require('../../lib/common/events');
|
|
12
12
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const ghostVersion = require('@tryghost/version');
|
|
2
2
|
const settingsCache = require('../../../shared/settings-cache');
|
|
3
3
|
const config = require('../../../shared/config');
|
|
4
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
4
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
5
5
|
|
|
6
6
|
module.exports = function getSiteProperties() {
|
|
7
7
|
const siteProperties = {
|
|
@@ -49,7 +49,7 @@ class RecommendationServiceWrapper {
|
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
52
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
53
53
|
const models = require('../../models');
|
|
54
54
|
const sentry = require('../../../shared/sentry');
|
|
55
55
|
const settings = require('../settings');
|
|
@@ -112,7 +112,7 @@ class DynamicRoutingService {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
async upload(
|
|
115
|
+
async upload(yamlContent) {
|
|
116
116
|
const parseYaml = require('./yaml-parser');
|
|
117
117
|
const {parseRouteSettings} = require('./route-settings-parser');
|
|
118
118
|
const urlService = require('../url');
|
|
@@ -120,8 +120,7 @@ class DynamicRoutingService {
|
|
|
120
120
|
|
|
121
121
|
// Parse and validate before anything is persisted — an invalid
|
|
122
122
|
// upload is rejected here and never reaches the store.
|
|
123
|
-
const
|
|
124
|
-
const next = parseRouteSettings(parseYaml(content), content);
|
|
123
|
+
const next = parseRouteSettings(parseYaml(yamlContent), yamlContent);
|
|
125
124
|
let previous = null;
|
|
126
125
|
try {
|
|
127
126
|
previous = await this.store.get();
|
|
@@ -6,7 +6,7 @@ const service = new DynamicRoutingService();
|
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
init: async () => {
|
|
9
|
-
const adapterManager = require('../adapter-manager');
|
|
9
|
+
const adapterManager = require('../adapter-manager').default;
|
|
10
10
|
const SettingsLoader = require('./settings-loader');
|
|
11
11
|
const SettingsPathManager = require('./settings-path-manager');
|
|
12
12
|
|
|
@@ -7,37 +7,46 @@ exports.parseRouteSettings = parseRouteSettings;
|
|
|
7
7
|
exports.serializeRouteSettings = serializeRouteSettings;
|
|
8
8
|
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
9
9
|
const zod_1 = require("zod");
|
|
10
|
-
const errors_1 = __importDefault(require("@tryghost/errors"));
|
|
11
10
|
const tpl_1 = __importDefault(require("@tryghost/tpl"));
|
|
11
|
+
const validation_errors_1 = require("./validation-errors");
|
|
12
12
|
const messages = {
|
|
13
|
-
|
|
14
|
-
badDataError: 'Please wrap the data definition into a custom name.',
|
|
13
|
+
badDataError: '"{key}" is a reserved key. Please wrap the data definition into a custom name.',
|
|
15
14
|
badDataHelp: 'Example:\n data:\n my-tag:\n resource: tags\n ...\n',
|
|
16
|
-
authorDeprecatedError: 'Please choose a different name. We recommend not using author.'
|
|
15
|
+
authorDeprecatedError: '"author" is reserved. Please choose a different name. We recommend not using author.'
|
|
17
16
|
};
|
|
18
|
-
function validationError(at, reason, help) {
|
|
19
|
-
return new errors_1.default.ValidationError({
|
|
20
|
-
message: (0, tpl_1.default)(messages.validationError, { at, reason }),
|
|
21
|
-
...(help ? { help } : {})
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
17
|
const VALID_SHORTFORM_RESOURCES = ['tag', 'page', 'post', 'author'];
|
|
25
18
|
const VALID_LONGFORM_RESOURCES = ['tags', 'posts', 'pages', 'authors'];
|
|
26
19
|
const RESERVED_DATA_KEYS = ['resource', 'type', 'limit', 'order', 'include', 'filter', 'status', 'visibility', 'slug', 'redirect'];
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
// YAML parses a bare `filter:` as null and authors commonly quote numeric scalars
|
|
21
|
+
// (`limit: "100"`); the legacy validator accepted both, so treat an explicitly empty
|
|
22
|
+
// value as unset and coerce digit-only limit strings to numbers.
|
|
23
|
+
const OptionalStringField = zod_1.z.string().nullish().transform(v => v ?? undefined);
|
|
24
|
+
const OptionalBooleanField = zod_1.z.boolean().nullish().transform(v => v ?? undefined);
|
|
25
|
+
const LimitField = zod_1.z.union([zod_1.z.number(), zod_1.z.literal('all'), zod_1.z.string().regex(/^\d+$/).transform(Number)])
|
|
26
|
+
.nullish().transform(v => v ?? undefined);
|
|
27
|
+
const SHORTFORM_HELP = 'e.g. data: tag.recipes';
|
|
28
|
+
/**
|
|
29
|
+
* Shorthand data definitions look like `tag.recipes` — resource, dot, slug.
|
|
30
|
+
*
|
|
31
|
+
* `%s` stands in for the slug: on channel routes and collections, fetch-data
|
|
32
|
+
* substitutes it with the request's `slug` param at query time, which is how a
|
|
33
|
+
* wildcard route such as `/author/:slug/` serves a different author per request.
|
|
34
|
+
* There is no static slug that could replace it, so rejecting it would break
|
|
35
|
+
* those routes.
|
|
36
|
+
*/
|
|
37
|
+
function validateDataShortForm(value, path) {
|
|
38
|
+
if (!/^[a-zA-Z0-9_]+\.(?:%s|[a-zA-Z0-9_-]+)$/.test(value)) {
|
|
39
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(path), `"${value}" is not a valid data shorthand. Please use resource.slug, e.g. tag.recipes.`, SHORTFORM_HELP);
|
|
31
40
|
}
|
|
32
|
-
const resource =
|
|
41
|
+
const resource = value.split('.')[0];
|
|
33
42
|
if (!VALID_SHORTFORM_RESOURCES.includes(resource)) {
|
|
34
|
-
|
|
43
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(path), `resource "${resource}" is not supported. Please use ${(0, validation_errors_1.humanList)(VALID_SHORTFORM_RESOURCES)}.`, SHORTFORM_HELP);
|
|
35
44
|
}
|
|
36
|
-
}
|
|
45
|
+
}
|
|
37
46
|
const DataReadEntrySchema = zod_1.z.object({
|
|
38
47
|
type: zod_1.z.literal('read'),
|
|
39
48
|
resource: zod_1.z.enum(VALID_LONGFORM_RESOURCES),
|
|
40
|
-
slug: zod_1.z.string(
|
|
49
|
+
slug: zod_1.z.string().min(1),
|
|
41
50
|
redirect: zod_1.z.boolean().optional(),
|
|
42
51
|
include: zod_1.z.string().optional(),
|
|
43
52
|
visibility: zod_1.z.string().optional(),
|
|
@@ -46,98 +55,104 @@ const DataReadEntrySchema = zod_1.z.object({
|
|
|
46
55
|
const DataBrowseEntrySchema = zod_1.z.object({
|
|
47
56
|
type: zod_1.z.literal('browse'),
|
|
48
57
|
resource: zod_1.z.enum(VALID_LONGFORM_RESOURCES),
|
|
49
|
-
filter:
|
|
50
|
-
limit:
|
|
51
|
-
order:
|
|
52
|
-
include:
|
|
53
|
-
fields:
|
|
54
|
-
visibility:
|
|
55
|
-
status:
|
|
58
|
+
filter: OptionalStringField,
|
|
59
|
+
limit: LimitField,
|
|
60
|
+
order: OptionalStringField,
|
|
61
|
+
include: OptionalStringField,
|
|
62
|
+
fields: OptionalStringField,
|
|
63
|
+
visibility: OptionalStringField,
|
|
64
|
+
status: OptionalStringField,
|
|
56
65
|
page: zod_1.z.number().optional()
|
|
57
66
|
});
|
|
58
67
|
const DataLongFormEntrySchema = zod_1.z.discriminatedUnion('type', [DataReadEntrySchema, DataBrowseEntrySchema]);
|
|
59
|
-
|
|
68
|
+
const DATA_ENTRY_HELP = 'e.g.\n data:\n my-tag:\n resource: tags\n type: read\n slug: recipes\n';
|
|
69
|
+
function parseDataEntry(value, path) {
|
|
60
70
|
if (typeof value === 'string') {
|
|
61
|
-
|
|
62
|
-
if (!result.success) {
|
|
63
|
-
throw toValidationError(result.error);
|
|
64
|
-
}
|
|
71
|
+
validateDataShortForm(value, path);
|
|
65
72
|
return value;
|
|
66
73
|
}
|
|
67
|
-
if (typeof value === 'object' && value !== null) {
|
|
74
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
68
75
|
const result = DataLongFormEntrySchema.safeParse(value);
|
|
69
76
|
if (!result.success) {
|
|
70
77
|
const issue = result.error.issues[0];
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
const at = (0, validation_errors_1.formatLocation)(path);
|
|
79
|
+
const record = value;
|
|
80
|
+
// A failed `type` discriminator surfaces as a union issue on that
|
|
81
|
+
// key — matched on the code rather than the wording, which zod
|
|
82
|
+
// is free to change.
|
|
83
|
+
if (issue.code === 'invalid_union' && issue.path[0] === 'type') {
|
|
84
|
+
if (record.type === undefined) {
|
|
85
|
+
throw (0, validation_errors_1.validationError)(at, 'type is required. Please use read or browse.', DATA_ENTRY_HELP);
|
|
75
86
|
}
|
|
76
|
-
throw
|
|
87
|
+
throw (0, validation_errors_1.validationError)(at, `type "${record.type}" is not supported. Please use read or browse.`, DATA_ENTRY_HELP);
|
|
77
88
|
}
|
|
78
|
-
if (issue.path
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
throw validationError(JSON.stringify(value), 'resource is required.');
|
|
89
|
+
if (issue.path.includes('resource')) {
|
|
90
|
+
if (record.resource === undefined) {
|
|
91
|
+
throw (0, validation_errors_1.validationError)(at, `resource is required. Please use ${(0, validation_errors_1.humanList)(VALID_LONGFORM_RESOURCES)}.`, DATA_ENTRY_HELP);
|
|
82
92
|
}
|
|
83
|
-
throw
|
|
93
|
+
throw (0, validation_errors_1.validationError)(at, `resource "${record.resource}" is not supported. Please use ${(0, validation_errors_1.humanList)(VALID_LONGFORM_RESOURCES)}.`, DATA_ENTRY_HELP);
|
|
94
|
+
}
|
|
95
|
+
if (issue.path.includes('slug') && !record.slug) {
|
|
96
|
+
throw (0, validation_errors_1.validationError)(at, 'slug is required for read data entries.', DATA_ENTRY_HELP);
|
|
97
|
+
}
|
|
98
|
+
throw (0, validation_errors_1.toValidationError)(result.error, path, value);
|
|
99
|
+
}
|
|
100
|
+
// Fields set to an explicitly empty value parse to undefined — drop the
|
|
101
|
+
// keys so "unset" means absent in the domain model and serialized output.
|
|
102
|
+
const entry = result.data;
|
|
103
|
+
for (const entryKey of Object.keys(entry)) {
|
|
104
|
+
if (entry[entryKey] === undefined) {
|
|
105
|
+
delete entry[entryKey];
|
|
84
106
|
}
|
|
85
|
-
throw toValidationError(result.error);
|
|
86
107
|
}
|
|
87
108
|
return result.data;
|
|
88
109
|
}
|
|
89
|
-
throw validationError(
|
|
110
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(path), `a data entry must be a shorthand like tag.recipes, or a map with type and resource, but ${(0, validation_errors_1.describeValue)(value)} was provided.`, DATA_ENTRY_HELP);
|
|
90
111
|
}
|
|
91
|
-
function parseRouteData(data) {
|
|
112
|
+
function parseRouteData(data, path) {
|
|
92
113
|
if (typeof data === 'string') {
|
|
93
|
-
|
|
94
|
-
if (!result.success) {
|
|
95
|
-
throw toValidationError(result.error);
|
|
96
|
-
}
|
|
114
|
+
validateDataShortForm(data, path);
|
|
97
115
|
return data;
|
|
98
116
|
}
|
|
99
|
-
if (typeof data !== 'object' || data === null) {
|
|
100
|
-
throw validationError(
|
|
117
|
+
if (typeof data !== 'object' || data === null || Array.isArray(data)) {
|
|
118
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(path), `data must be a shorthand like tag.recipes, or a map of named data entries, but ${(0, validation_errors_1.describeValue)(data)} was provided.`, DATA_ENTRY_HELP);
|
|
101
119
|
}
|
|
102
120
|
const record = data;
|
|
103
121
|
for (const key of Object.keys(record)) {
|
|
104
122
|
if (RESERVED_DATA_KEYS.includes(key)) {
|
|
105
|
-
throw
|
|
106
|
-
message: (0, tpl_1.default)(messages.badDataError),
|
|
107
|
-
help: messages.badDataHelp
|
|
108
|
-
});
|
|
123
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)([...path, key]), (0, tpl_1.default)(messages.badDataError, { key }), messages.badDataHelp);
|
|
109
124
|
}
|
|
110
125
|
if (key === 'author') {
|
|
111
|
-
throw
|
|
112
|
-
message: (0, tpl_1.default)(messages.authorDeprecatedError)
|
|
113
|
-
});
|
|
126
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)([...path, key]), messages.authorDeprecatedError);
|
|
114
127
|
}
|
|
115
128
|
}
|
|
116
129
|
const parsed = {};
|
|
117
130
|
for (const [key, value] of Object.entries(record)) {
|
|
118
|
-
parsed[key] = parseDataEntry(
|
|
131
|
+
parsed[key] = parseDataEntry(value, [...path, key]);
|
|
119
132
|
}
|
|
120
133
|
return parsed;
|
|
121
134
|
}
|
|
122
|
-
const TemplateField = zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]).
|
|
135
|
+
const TemplateField = zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]).nullish().default([])
|
|
123
136
|
.transform(v => {
|
|
124
137
|
if (!v || (Array.isArray(v) && v.length === 0)) {
|
|
125
138
|
return [];
|
|
126
139
|
}
|
|
127
140
|
return Array.isArray(v) ? v : [v];
|
|
128
141
|
});
|
|
129
|
-
|
|
142
|
+
// The schemas are built per route/collection so that errors raised while
|
|
143
|
+
// parsing nested `data` can name the exact path they came from.
|
|
144
|
+
const routeObjectSchema = (path) => zod_1.z.object({
|
|
130
145
|
controller: zod_1.z.literal('channel').optional(),
|
|
131
146
|
template: TemplateField,
|
|
132
147
|
data: zod_1.z.unknown().optional(),
|
|
133
|
-
content_type:
|
|
134
|
-
filter:
|
|
135
|
-
order:
|
|
136
|
-
limit:
|
|
137
|
-
rss:
|
|
148
|
+
content_type: OptionalStringField,
|
|
149
|
+
filter: OptionalStringField,
|
|
150
|
+
order: OptionalStringField,
|
|
151
|
+
limit: LimitField,
|
|
152
|
+
rss: OptionalBooleanField
|
|
138
153
|
}).transform((val) => {
|
|
139
154
|
const templates = val.template;
|
|
140
|
-
const data = val.data !== undefined ? parseRouteData(val.data) : undefined;
|
|
155
|
+
const data = val.data !== undefined ? parseRouteData(val.data, [...path, 'data']) : undefined;
|
|
141
156
|
if (val.controller === 'channel') {
|
|
142
157
|
const route = {
|
|
143
158
|
type: 'channel',
|
|
@@ -175,16 +190,16 @@ const RouteObjectSchema = zod_1.z.object({
|
|
|
175
190
|
}
|
|
176
191
|
return route;
|
|
177
192
|
});
|
|
178
|
-
const
|
|
179
|
-
permalink: zod_1.z.string(
|
|
193
|
+
const collectionValueSchema = (path) => zod_1.z.object({
|
|
194
|
+
permalink: zod_1.z.string().optional(),
|
|
180
195
|
template: TemplateField,
|
|
181
196
|
data: zod_1.z.unknown().optional(),
|
|
182
|
-
filter:
|
|
183
|
-
order:
|
|
184
|
-
limit:
|
|
185
|
-
rss:
|
|
197
|
+
filter: OptionalStringField,
|
|
198
|
+
order: OptionalStringField,
|
|
199
|
+
limit: LimitField,
|
|
200
|
+
rss: OptionalBooleanField
|
|
186
201
|
}).transform((val) => {
|
|
187
|
-
const data = val.data !== undefined ? parseRouteData(val.data) : undefined;
|
|
202
|
+
const data = val.data !== undefined ? parseRouteData(val.data, [...path, 'data']) : undefined;
|
|
188
203
|
const collection = {
|
|
189
204
|
permalink: val.permalink ?? '',
|
|
190
205
|
templates: val.template
|
|
@@ -208,48 +223,60 @@ const RawCollectionValueSchema = zod_1.z.object({
|
|
|
208
223
|
});
|
|
209
224
|
const RouteSettingsSchema = zod_1.z.object({
|
|
210
225
|
routes: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).nullable().optional().default({}),
|
|
211
|
-
collections: zod_1.z.record(zod_1.z.string(),
|
|
226
|
+
collections: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).nullable().optional().default({}),
|
|
212
227
|
taxonomies: zod_1.z.record(zod_1.z.string(), zod_1.z.string()).nullable().optional().default({})
|
|
213
228
|
});
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Every path in routes.yaml — route paths, collection paths, permalinks and
|
|
231
|
+
* taxonomy permalinks — follows the same rules, so they share one message set.
|
|
232
|
+
*
|
|
233
|
+
* `allowParamNotation` is set for route and collection keys, which are mounted on
|
|
234
|
+
* Express verbatim: nothing rewrites `{param}` to `:param` for them the way it
|
|
235
|
+
* does for permalinks and taxonomies. So `/author/:slug/` is a working wildcard
|
|
236
|
+
* route on live sites and `/author/{slug}/` would be a dead literal path —
|
|
237
|
+
* rejecting :param there would break the former, and the suggested rewrite would
|
|
238
|
+
* silently produce the latter.
|
|
239
|
+
*/
|
|
240
|
+
function validatePath(value, path, example, { allowParamNotation = false } = {}) {
|
|
241
|
+
const at = (0, validation_errors_1.formatLocation)(path);
|
|
242
|
+
if (!value.startsWith('/')) {
|
|
243
|
+
throw (0, validation_errors_1.validationError)(at, `"${value}" is missing a leading slash. Please use e.g. ${example}.`);
|
|
244
|
+
}
|
|
245
|
+
if (!value.endsWith('/')) {
|
|
246
|
+
throw (0, validation_errors_1.validationError)(at, `"${value}" is missing a trailing slash. Please use e.g. ${example}.`);
|
|
247
|
+
}
|
|
248
|
+
if (!allowParamNotation && /\/:\w+/.test(value)) {
|
|
249
|
+
// Suggest the same path in the notation Ghost expects, rather than a
|
|
250
|
+
// generic example the author then has to translate.
|
|
251
|
+
throw (0, validation_errors_1.validationError)(at, `"${value}" uses the :param notation. Please use "${value.replace(/\/:(\w+)/g, '/{$1}')}".`);
|
|
252
|
+
}
|
|
219
253
|
}
|
|
220
254
|
function parseRouteSettings(raw, yamlSource) {
|
|
221
255
|
const obj = raw ?? {};
|
|
222
256
|
const parsed = RouteSettingsSchema.safeParse(obj);
|
|
223
257
|
if (!parsed.success) {
|
|
224
|
-
throw toValidationError(parsed.error);
|
|
258
|
+
throw (0, validation_errors_1.toValidationError)(parsed.error, [], obj);
|
|
225
259
|
}
|
|
226
260
|
const { routes: rawRoutes, collections: rawCollections, taxonomies: rawTaxonomies } = parsed.data;
|
|
227
261
|
const routes = [];
|
|
228
262
|
if (rawRoutes) {
|
|
229
263
|
for (const [path, value] of Object.entries(rawRoutes)) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
if (!path.endsWith('/')) {
|
|
234
|
-
throw validationError(path, 'A trailing slash is required.');
|
|
235
|
-
}
|
|
236
|
-
if (/\/:\w+/.test(path)) {
|
|
237
|
-
throw validationError(path, 'Please use the following notation e.g. /{slug}/.');
|
|
238
|
-
}
|
|
264
|
+
const routeLocation = ['routes', path];
|
|
265
|
+
validatePath(path, routeLocation, '/about/', { allowParamNotation: true });
|
|
239
266
|
if (value === null || value === undefined) {
|
|
240
|
-
throw validationError(
|
|
267
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(routeLocation), 'Please define a template, e.g. /about/: about.');
|
|
241
268
|
}
|
|
242
269
|
if (typeof value === 'string') {
|
|
243
270
|
routes.push({ type: 'template', path, templates: [value] });
|
|
244
271
|
continue;
|
|
245
272
|
}
|
|
246
|
-
const routeResult =
|
|
273
|
+
const routeResult = routeObjectSchema(routeLocation).safeParse(value);
|
|
247
274
|
if (!routeResult.success) {
|
|
248
|
-
throw toValidationError(routeResult.error);
|
|
275
|
+
throw (0, validation_errors_1.toValidationError)(routeResult.error, routeLocation, value);
|
|
249
276
|
}
|
|
250
277
|
const route = routeResult.data;
|
|
251
278
|
if (route.type === 'template' && (!route.templates || route.templates.length === 0) && !route.data && !route.contentType) {
|
|
252
|
-
throw validationError(
|
|
279
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(routeLocation), 'Please define a template, e.g. /about/: about.');
|
|
253
280
|
}
|
|
254
281
|
routes.push({ ...route, path });
|
|
255
282
|
}
|
|
@@ -257,48 +284,31 @@ function parseRouteSettings(raw, yamlSource) {
|
|
|
257
284
|
const collections = [];
|
|
258
285
|
if (rawCollections) {
|
|
259
286
|
for (const [path, value] of Object.entries(rawCollections)) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (!
|
|
264
|
-
throw
|
|
265
|
-
}
|
|
266
|
-
if (/\/:\w+/.test(path)) {
|
|
267
|
-
throw validationError(path, 'Please use the following notation e.g. /{slug}/.');
|
|
287
|
+
const collectionLocation = ['collections', path];
|
|
288
|
+
validatePath(path, collectionLocation, '/blog/', { allowParamNotation: true });
|
|
289
|
+
const collectionResult = collectionValueSchema(collectionLocation).safeParse(value);
|
|
290
|
+
if (!collectionResult.success) {
|
|
291
|
+
throw (0, validation_errors_1.toValidationError)(collectionResult.error, collectionLocation, value);
|
|
268
292
|
}
|
|
269
|
-
|
|
270
|
-
|
|
293
|
+
const collection = collectionResult.data;
|
|
294
|
+
if (!collection.permalink) {
|
|
295
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(collectionLocation), 'Please define a permalink route, e.g. permalink: /{slug}/.');
|
|
271
296
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
if (!value.permalink.endsWith('/')) {
|
|
276
|
-
throw validationError(value.permalink, 'A trailing slash is required.');
|
|
277
|
-
}
|
|
278
|
-
if (/\/:\w+/.test(value.permalink)) {
|
|
279
|
-
throw validationError(value.permalink, 'Please use the following notation e.g. /{slug}/.');
|
|
280
|
-
}
|
|
281
|
-
collections.push({ ...value, path });
|
|
297
|
+
validatePath(collection.permalink, [...collectionLocation, 'permalink'], '/{slug}/');
|
|
298
|
+
collections.push({ ...collection, path });
|
|
282
299
|
}
|
|
283
300
|
}
|
|
284
301
|
const taxonomies = {};
|
|
285
302
|
if (rawTaxonomies) {
|
|
286
303
|
for (const [key, value] of Object.entries(rawTaxonomies)) {
|
|
304
|
+
const taxonomyLocation = ['taxonomies', key];
|
|
287
305
|
if (!['tag', 'author'].includes(key)) {
|
|
288
|
-
throw validationError(
|
|
306
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(taxonomyLocation), 'Unknown taxonomy. Please use tag or author.');
|
|
289
307
|
}
|
|
290
308
|
if (!value) {
|
|
291
|
-
throw validationError(
|
|
292
|
-
}
|
|
293
|
-
if (!value.startsWith('/')) {
|
|
294
|
-
throw validationError(value, 'A leading slash is required.');
|
|
295
|
-
}
|
|
296
|
-
if (!value.endsWith('/')) {
|
|
297
|
-
throw validationError(value, 'A trailing slash is required.');
|
|
298
|
-
}
|
|
299
|
-
if (/\/:\w+/.test(value)) {
|
|
300
|
-
throw validationError(value, 'Please use the following notation e.g. /{slug}/.');
|
|
309
|
+
throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(taxonomyLocation), `Please define a taxonomy permalink route, e.g. ${key}: /${key}/{slug}/.`);
|
|
301
310
|
}
|
|
311
|
+
validatePath(value, taxonomyLocation, `/${key}/{slug}/`);
|
|
302
312
|
if (key === 'tag') {
|
|
303
313
|
taxonomies.tag = value;
|
|
304
314
|
}
|