ghost 6.54.1 → 6.56.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/tryghost-adapter-base-scheduling-0.2.0.tgz +0 -0
- package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
- package/components/tryghost-kg-default-nodes-2.1.4.tgz +0 -0
- package/components/tryghost-kg-default-transforms-1.3.3.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-nql-string-0.0.0.tgz +0 -0
- package/core/boot.js +3 -6
- package/core/built/admin/assets/{Combination-CJG7Flp-.js → Combination-BCm9FL4o.js} +1 -1
- package/core/built/admin/assets/{PolarAngleAxis-BGjf7sBu.js → PolarAngleAxis-C4qtHy1B.js} +1 -1
- package/core/built/admin/assets/{RadialBarChart-zeFf9mBz.js → RadialBarChart-Bh09Stsj.js} +1 -1
- package/core/built/admin/assets/{account-migration-BklF2I_I.js → account-migration-D3O_yVck.js} +1 -1
- package/core/built/admin/assets/activitypub/{account-migration-CNovr6W-.js → account-migration-D8FbP-Z-.js} +7 -7
- package/core/built/admin/assets/activitypub/activitypub.js +6 -6
- package/core/built/admin/assets/activitypub/{avatar-B3DEDB1l.js → avatar-11EA1VSs.js} +2 -2
- package/core/built/admin/assets/activitypub/{avatar-flipboard-Cqrg0XMx.js → avatar-flipboard-jfbLG-xe.js} +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-Ceslb1_M.js → bluesky-sharing-f1jTQe2P.js} +16 -16
- package/core/built/admin/assets/activitypub/{content-formatters-BpQARh28.js → content-formatters-nmTOPY9M.js} +3 -3
- package/core/built/admin/assets/activitypub/{copy-D9UWIAan.js → copy-BCwo9ep3.js} +2 -2
- package/core/built/admin/assets/activitypub/{dist-DHAjBcV3.js → dist-BEfX-0aW.js} +12 -12
- package/core/built/admin/assets/activitypub/{domain-C1qQvJ8C.js → domain-AaDlZlrA.js} +9 -9
- package/core/built/admin/assets/activitypub/{edit-profile-BcH-jEfM.js → edit-profile-DPi8Tl5M.js} +945 -945
- package/core/built/admin/assets/activitypub/{explore-AxwBh9dI.js → explore-CxTzjILQ.js} +8 -8
- package/core/built/admin/assets/activitypub/{feed-BaOlbh7a.js → feed-DPv5x2MX.js} +33 -33
- package/core/built/admin/assets/activitypub/{field-B7mYYQpN.js → field-DbgA8lat.js} +3 -3
- package/core/built/admin/assets/activitypub/{hash-BC9Q0N4c.js → hash-BWuZoYkA.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-DQ4ZnC1m.js → inbox-35VDQ2K2.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-vXez-5uJ.js → inbox-DSrF_i1O.js} +85 -85
- package/core/built/admin/assets/activitypub/{label-Chv5T8bw.js → label-CPjFBbo7.js} +3 -3
- package/core/built/admin/assets/activitypub/layout-CTgrezN7.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-DtSM2i1I.js → moderation-BkDC1XVZ.js} +11 -11
- package/core/built/admin/assets/activitypub/{note-Dckp4S-2.js → note-xEyH4xT-.js} +7 -7
- package/core/built/admin/assets/activitypub/{notifications-CG5T22vg.js → notifications-DClaL3ui.js} +9 -9
- package/core/built/admin/assets/activitypub/{preferences-D_799jdl.js → preferences-DpnOa-4Z.js} +20 -20
- package/core/built/admin/assets/activitypub/{profile-D2JfXBQl.js → profile-Dvi9mz-6.js} +237 -237
- package/core/built/admin/assets/activitypub/{reply-CpdMeAO5.js → reply-Cs9ySd6Z.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-CCHe2dQp.js → routes-DFBeTnfn.js} +1139 -1150
- package/core/built/admin/assets/activitypub/{separator-BI1FLsYM.js → separator-C5u_VjzY.js} +3 -3
- package/core/built/admin/assets/activitypub/{settings-kx-9Enkz.js → settings-CV2fFu6D.js} +13 -13
- package/core/built/admin/assets/activitypub/{site-x4_IjVJ0.js → site-_TgDd_EM.js} +81 -81
- package/core/built/admin/assets/activitypub/{step-1-DIDg4aHb.js → step-1-BfnNL2oF.js} +5 -5
- package/core/built/admin/assets/activitypub/{step-2-BfGe8BYt.js → step-2-DLndZkO-.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-3-mE9spAqw.js → step-3-A-PZTtRE.js} +10 -10
- package/core/built/admin/assets/activitypub/{tabs-CyPRQQ1N.js → tabs-BUbz7tea.js} +321 -319
- package/core/built/admin/assets/activitypub/{topic-filter-DLHBZT93.js → topic-filter-BdX_xYYT.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-VzbN99u_.js → use-activity-pub-queries-EwuRemHh.js} +2 -2
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-CAwXTmqH.js → use-navigate-with-base-path-cy4ACBc4.js} +92 -90
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-BAB6fNGt.js → use-reply-chain-data-CyFcGfan.js} +5 -5
- package/core/built/admin/assets/activitypub/{x-C8tAnXly.js → x-7zk8mV2p.js} +2 -2
- package/core/built/admin/assets/audience-CkBb2LlO.js +1 -0
- package/core/built/admin/assets/{automated-emails-of1MvVsv.js → automated-emails-6t2bIRWf.js} +2 -2
- package/core/built/admin/assets/{automations-B7-y3dXt.js → automations-DhKeS_U5.js} +1 -1
- package/core/built/admin/assets/{automations-DRFjW5fw.js → automations-cMllU545.js} +1 -1
- package/core/built/admin/assets/{bluesky-sharing-BbbjWdzs.js → bluesky-sharing-DPGpyD-G.js} +1 -1
- package/core/built/admin/assets/{box-BWbhXh21.js → box-By_EgGtm.js} +1 -1
- package/core/built/admin/assets/{breadcrumb-B-M9Ip_2.js → breadcrumb-DIfcF5ow.js} +1 -1
- package/core/built/admin/assets/build-CsiH26uS.js +1 -0
- package/core/built/admin/assets/{card-DGoDJzrn.js → card-aUHX0hyR.js} +1 -1
- package/core/built/admin/assets/{chart-BuRT2Y6p.js → chart-BnXyfH11.js} +1 -1
- package/core/built/admin/assets/{chart-helpers-xiSsW8r0.js → chart-helpers-DV0FkdcD.js} +1 -1
- package/core/built/admin/assets/{checkbox-EhJKHFdZ.js → checkbox-BIl077a0.js} +1 -1
- package/core/built/admin/assets/{chunk.361.3cdb584b973959e52ccc.js → chunk.332.05991a101d67f732dec3.js} +16 -12
- package/core/built/admin/assets/chunk.524.87b52f4fada529df2c4c.js +25 -0
- package/core/built/admin/assets/chunk.582.340bcca873e806cbd4bb.js +27 -0
- package/core/built/admin/assets/{code-editor-view-CZtJFGhR.js → code-editor-view-C0aWNwdl.js} +1 -1
- package/core/built/admin/assets/comments-qwhIjH3c.js +1 -0
- package/core/built/admin/assets/{container-BYz2Ed39.js → container-LiZf3XdY.js} +1 -1
- package/core/built/admin/assets/{data-list-16rkJYYi.js → data-list-CupF7bjM.js} +1 -1
- package/core/built/admin/assets/{date-range-select-CTlyo8zW.js → date-range-select-dXc-GsVe.js} +1 -1
- package/core/built/admin/assets/{disabled-sources-indicator-qs2GfLvl.js → disabled-sources-indicator-DYAXW-6V.js} +1 -1
- package/core/built/admin/assets/dist-BUKmD51u.js +1 -0
- package/core/built/admin/assets/{dist-2Tnz2Yfq.js → dist-CNlMj7ML.js} +1 -1
- package/core/built/admin/assets/{dist-DGzPJ_bO.js → dist-Cb5RSHSg.js} +1 -1
- package/core/built/admin/assets/{dist-P_ohUlTi.js → dist-CqO2lWS0.js} +1 -1
- package/core/built/admin/assets/{domain-CPNXKVOV.js → domain-B5ogXUBa.js} +1 -1
- package/core/built/admin/assets/{dropzone-BmCXnw6J.js → dropzone-BnFG7dDP.js} +1 -1
- package/core/built/admin/assets/{edit-profile-SGrJve5M.js → edit-profile-B07jCZy9.js} +1 -1
- package/core/built/admin/assets/editor-DDYSOXGN.js +8 -0
- package/core/built/admin/assets/{empty-indicator-oX1u1Pkn.js → empty-indicator-WB1WgT9h.js} +1 -1
- package/core/built/admin/assets/{explore-CUYLv9G9.js → explore-Ca1y8HW_.js} +1 -1
- package/core/built/admin/assets/{feed-CPdJMttL.js → feed-x4iFMBP4.js} +1 -1
- package/core/built/admin/assets/field-ChCAabZg.js +1 -0
- package/core/built/admin/assets/filter-sources-LdtH1e-T.js +1 -0
- package/core/built/admin/assets/{filters-bXkkWro8.js → filters-CLehPo_D.js} +1 -1
- package/core/built/admin/assets/filters-CjVKRP8U.js +1 -0
- package/core/built/admin/assets/{ghost-05f9a7182ed56903dba05878a5b8422b.js → ghost-7f01131115186d1af84ead76e79646dd.js} +275 -255
- package/core/built/admin/assets/{ghost-3063eae29e6c9cc6d6e7131928a27da0.css → ghost-d38c30b866e59f2e06a357b5eb844fe5.css} +1 -1
- package/core/built/admin/assets/{ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css → ghost-dark-1bffd5099ba7a749303133efacf8480b.css} +1 -1
- package/core/built/admin/assets/gift-link-modal-Buqh2vXh.js +1 -0
- package/core/built/admin/assets/{gift-links-nBxJjZiQ.js → gift-links-CsUhefWG.js} +1 -1
- package/core/built/admin/assets/growth-DajOBdN0.js +1 -0
- package/core/built/admin/assets/growth-Dy2UOSay.js +3 -0
- package/core/built/admin/assets/{hooks-BApwwBE0.js → hooks-CixO01lL.js} +1 -1
- package/core/built/admin/assets/{inbox-Xx1CdnfO.js → inbox-BUOLDoji.js} +13 -13
- package/core/built/admin/assets/index-08n05-rc.js +67 -0
- package/core/built/admin/assets/index-DgUzgFvS.css +1 -0
- package/core/built/admin/assets/{inline-EMAm3okk.js → inline-Cw-gigDW.js} +1 -1
- package/core/built/admin/assets/input-group-uSK3XT7b.js +1 -0
- package/core/built/admin/assets/{input-surface-BpAjZXY5.js → input-surface-BdOe4KzO.js} +1 -1
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +9132 -9087
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +121 -121
- package/core/built/admin/assets/koenig-lexical/style.css +1 -1
- package/core/built/admin/assets/{koenig-lexical-B61IALf5.js → koenig-lexical-BFc4yFed.js} +82 -82
- package/core/built/admin/assets/{kpi-card-DCdlyaSS.js → kpi-card-BN-E6WYX.js} +1 -1
- package/core/built/admin/assets/{kpi-card-BlZaG1Lo.js → kpi-card-CCt-qeWD.js} +1 -1
- package/core/built/admin/assets/{kpi-helpers-DpAuS1Nb.js → kpi-helpers-DlxTbTs4.js} +1 -1
- package/core/built/admin/assets/{kpi-tabs-Dme44bQS.js → kpi-tabs-BlcUttpn.js} +1 -1
- package/core/built/admin/assets/{label-dSs5aepE.js → label-AVrxwmsz.js} +1 -1
- package/core/built/admin/assets/label-picker-DVnpu_IF.js +1 -0
- package/core/built/admin/assets/labels-DAIqKed7.js +1 -0
- package/core/built/admin/assets/layout-B0YLh7R9.js +1 -0
- package/core/built/admin/assets/link-helpers-D9LsDOkG.js +1 -0
- package/core/built/admin/assets/{list-page-B6ANtzkd.js → list-page-CdsnQR9N.js} +1 -1
- package/core/built/admin/assets/member-custom-fields-C8NpZYza.js +1 -0
- package/core/built/admin/assets/member-detail-CIVAdKXf.js +1 -0
- package/core/built/admin/assets/members-oLPiSkXD.js +10 -0
- package/core/built/admin/assets/modals-CB7v-k3T.js +31 -0
- package/core/built/admin/assets/moderation-CQ3urTFE.js +1 -0
- package/core/built/admin/assets/newsletter-rbeDX9Wk.js +1 -0
- package/core/built/admin/assets/{newsletters-D1jbtV-h.js → newsletters-BXJbJgA-.js} +1 -1
- package/core/built/admin/assets/newsletters-vt3Ni1Ov.js +1 -0
- package/core/built/admin/assets/note-Dk877BTv.js +1 -0
- package/core/built/admin/assets/notifications-CPlLjPxO.js +1 -0
- package/core/built/admin/assets/{offers-CrY6nSRR.js → offers-DEniVRD5.js} +1 -1
- package/core/built/admin/assets/onboarding-route-DdStOtjy.js +1 -0
- package/core/built/admin/assets/overview--4V-kx9c.js +1 -0
- package/core/built/admin/assets/overview-DSLv30oz.js +1 -0
- package/core/built/admin/assets/{page-header-op0eN36I.js → page-header-pp4dWmOS.js} +1 -1
- package/core/built/admin/assets/{pages-BbNWFcGj.js → pages-B4goRPUn.js} +1 -1
- package/core/built/admin/assets/{post-analytics-WwRDEnrV.js → post-analytics-BMJrI81R.js} +1 -1
- package/core/built/admin/assets/post-analytics-header-pU2m9ZuV.js +1 -0
- package/core/built/admin/assets/post-analytics-provider-Btml5vJI.js +1 -0
- package/core/built/admin/assets/{post-share-modal-Dx-MEjhI.js → post-share-modal-AcUZkbfL.js} +1 -1
- package/core/built/admin/assets/{posts-EWpZIjkr.js → posts-DhXE7b6r.js} +1 -1
- package/core/built/admin/assets/preferences-Ru4CRPHC.js +5 -0
- package/core/built/admin/assets/profile-BNb1oj7D.js +1 -0
- package/core/built/admin/assets/{referrers-BCfFYSHc.js → referrers-pmJT4k3-.js} +1 -1
- package/core/built/admin/assets/{router-provider-C1R4AZ2o.js → router-provider-BmEZf6c6.js} +1 -1
- package/core/built/admin/assets/select-B0HteHrp.js +1 -0
- package/core/built/admin/assets/settings-B1C9Q3wo.js +4 -0
- package/core/built/admin/assets/{settings-H6HxFgfI.js → settings-BGgk7oCI.js} +1 -1
- package/core/built/admin/assets/{shade-app-B3heOAfz-CGXQwWeO.js → shade-app-B3heOAfz-BhQXxNkT.js} +1 -1
- package/core/built/admin/assets/{share-modal-BJCadJyp.js → share-modal-BeuydaBf.js} +1 -1
- package/core/built/admin/assets/social-urls-DA2lXrhW.js +8 -0
- package/core/built/admin/assets/{sort-button-DyYlfYp7.js → sort-button-Df4t2AL8.js} +1 -1
- package/core/built/admin/assets/{source-icon-_ubRDbg_.js → source-icon-ajoaKb41.js} +1 -1
- package/core/built/admin/assets/{stack-xiN0eQ6Z.js → stack-CIfOAAVf.js} +1 -1
- package/core/built/admin/assets/{stats-BQZMGMvn.js → stats-C_lfxZAw.js} +1 -1
- package/core/built/admin/assets/{stats-view-Doei-qCX.js → stats-view-Cxot1iD8.js} +1 -1
- package/core/built/admin/assets/{step-1-IKiLBPoC.js → step-1-ogAA4lDr.js} +1 -1
- package/core/built/admin/assets/{step-2-jJ41PsDN.js → step-2-C5Xini-7.js} +1 -1
- package/core/built/admin/assets/{step-3-CaqFAEqf.js → step-3-CZv1FV81.js} +2 -2
- package/core/built/admin/assets/{switch-t-WyENU2.js → switch-CyQcwMAv.js} +1 -1
- package/core/built/admin/assets/{table-DxUL78jU.js → table-DFj1wiYv.js} +1 -1
- package/core/built/admin/assets/tabs-D4y1gqUd.js +1 -0
- package/core/built/admin/assets/{tags-CNujGwkT.js → tags-Dmft-Y4O.js} +1 -1
- package/core/built/admin/assets/{text-DwtjwGkh.js → text-DU9Hv33_.js} +1 -1
- package/core/built/admin/assets/textarea-d9qEkMOP.js +1 -0
- package/core/built/admin/assets/{tiers-BgYLWRJv.js → tiers-DYsa4DCo.js} +1 -1
- package/core/built/admin/assets/{toggle-group-BeEpQ69p.js → toggle-group-R2QMFvXW.js} +1 -1
- package/core/built/admin/assets/{topic-filter-Bb5MOD-1.js → topic-filter-DGDxDalo.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data-Cds6XDjg.js → use-analytics-data-C76v4LIp.js} +1 -1
- package/core/built/admin/assets/use-filter-params-WrdhAISv.js +1 -0
- package/core/built/admin/assets/{use-growth-stats-D8uf98-G.js → use-growth-stats-aNXJOmQr.js} +1 -1
- package/core/built/admin/assets/{use-post-referrers-CRtgyuXB.js → use-post-referrers-CG0SZioj.js} +1 -1
- package/core/built/admin/assets/{use-reply-chain-data-DbKYX50v.js → use-reply-chain-data-RLdPKRmS.js} +1 -1
- package/core/built/admin/assets/{use-simple-pagination-DC01kpo0.js → use-simple-pagination-DgcF69KI.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-query-C7bQRJWw.js → use-tinybird-query-C1R_Kbmy.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-Az4tam7_.js → use-tinybird-token-C9fPjVM_.js} +1 -1
- package/core/built/admin/assets/{users-CcSCQFcQ.js → users-Dkv8NQZe.js} +1 -1
- package/core/built/admin/assets/{virtual-list-Dhuh9fGx.js → virtual-list-BmTUzeoF.js} +1 -1
- package/core/built/admin/assets/web-BqW0b0_C.js +1 -0
- package/core/built/admin/assets/web-Cy5GKMWM.js +2 -0
- package/core/built/admin/index.html +18 -18
- package/core/frontend/services/data/fetch-data.js +10 -5
- package/core/frontend/services/proxy.js +7 -8
- package/core/frontend/services/routing/api-adapter.js +115 -0
- package/core/frontend/services/routing/api-adapter.ts +157 -0
- package/core/frontend/services/routing/collection-router.js +5 -3
- package/core/frontend/services/routing/controllers/index.js +1 -1
- package/core/frontend/services/routing/controllers/rss.js +26 -31
- package/core/frontend/services/routing/controllers/rss.ts +66 -0
- package/core/frontend/services/routing/controllers/static.js +8 -7
- package/core/frontend/services/routing/parent-router.js +17 -4
- package/core/frontend/services/routing/permalink-adapter.js +26 -0
- package/core/frontend/services/routing/permalink-adapter.ts +23 -0
- package/core/frontend/services/routing/registry.js +59 -33
- package/core/frontend/services/routing/router-manager.js +14 -18
- package/core/frontend/services/routing/static-routes-router.js +11 -13
- package/core/frontend/services/routing/taxonomy-router.js +6 -2
- package/core/server/api/endpoints/automation-action-links.js +68 -0
- package/core/server/api/endpoints/automation-action-links.ts +46 -0
- package/core/server/api/endpoints/index.js +4 -0
- package/core/server/api/endpoints/settings.js +0 -2
- package/core/server/api/endpoints/utils/serializers/output/utils/url.js +11 -1
- package/core/server/data/migrations/versions/6.55/2026-07-27-11-25-44-add-to-hash-to-redirects.js +51 -0
- package/core/server/data/migrations/versions/6.55/2026-07-28-12-08-00-remove-routes-hash-from-settings.js +5 -0
- package/core/server/data/migrations/versions/6.56/2026-08-03-19-27-51-add-automation-run-step-id-to-automated-email-recipients.js +8 -0
- package/core/server/data/migrations/versions/6.56/2026-08-04-14-42-39-restrict-notification-add-permission-to-administrators.js +12 -0
- package/core/server/data/schema/commands.js +5 -0
- package/core/server/data/schema/default-settings/default-settings.json +0 -4
- package/core/server/data/schema/fixtures/fixtures.json +2 -2
- package/core/server/data/schema/schema.js +6 -1
- package/core/server/models/post.js +10 -1
- package/core/server/services/automations/automations-api.js +15 -0
- package/core/server/services/automations/automations-api.ts +19 -0
- package/core/server/services/automations/automations-repository.ts +20 -0
- package/core/server/services/automations/database-automations-repository.js +132 -30
- package/core/server/services/automations/database-automations-repository.ts +141 -12
- package/core/server/services/automations/database-date.js +10 -0
- package/core/server/services/automations/database-date.ts +5 -0
- package/core/server/services/automations/get-scheduler-idempotency-key.js +13 -0
- package/core/server/services/automations/get-scheduler-idempotency-key.ts +8 -0
- package/core/server/services/automations/poll.js +7 -2
- package/core/server/services/automations/poll.ts +10 -2
- package/core/server/services/automations/scheduler-poll-time.js +40 -0
- package/core/server/services/automations/scheduler-poll-time.ts +38 -0
- package/core/server/services/automations/service.js +19 -3
- package/core/server/services/automations/service.ts +20 -3
- package/core/server/services/comments/comments-service-emails.js +10 -7
- package/core/server/services/comments/comments-service.js +9 -4
- package/core/server/services/email-rendering/partials/email-wrapper.hbs +3 -1
- package/core/server/services/email-service/email-service-wrapper.js +6 -1
- package/core/server/services/email-service/email-templates/partials/styles.hbs +8 -0
- package/core/server/services/email-service/newsletter-email-event-storage.js +41 -10
- package/core/server/services/gift-links/CONTEXT.md +9 -0
- package/core/server/services/gifts/CONTEXT.md +55 -0
- package/core/server/services/gifts/README.md +28 -0
- package/core/server/services/gifts/gift-bookshelf-repository.js +65 -45
- package/core/server/services/gifts/gift-bookshelf-repository.ts +203 -74
- package/core/server/services/gifts/gift-checkout-adapter.js +59 -0
- package/core/server/services/gifts/gift-checkout-offer.js +74 -0
- package/core/server/services/gifts/gift-checkout-offer.ts +127 -0
- package/core/server/services/gifts/gift-codec.js +63 -0
- package/core/server/services/gifts/gift-codec.ts +62 -0
- package/core/server/services/gifts/gift-controller.js +6 -31
- package/core/server/services/gifts/gift-controller.ts +6 -69
- package/core/server/services/gifts/gift-email-service.ts +3 -2
- package/core/server/services/gifts/gift-schema.js +34 -0
- package/core/server/services/gifts/gift-schema.ts +39 -0
- package/core/server/services/gifts/gift-service-wrapper.js +13 -11
- package/core/server/services/gifts/gift-service.js +265 -52
- package/core/server/services/gifts/gift-service.ts +431 -97
- package/core/server/services/gifts/gift.ts +16 -39
- package/core/server/services/lib/dynamic-redirect-manager.js +12 -3
- package/core/server/services/link-redirection/link-redirect-repository.js +41 -4
- package/core/server/services/link-redirection/link-redirect.js +2 -0
- package/core/server/services/link-redirection/link-redirect.ts +3 -1
- package/core/server/services/link-redirection/link-redirects-service.js +38 -2
- package/core/server/services/link-tracking/click-event.js +3 -0
- package/core/server/services/link-tracking/index.js +38 -6
- package/core/server/services/link-tracking/link-click-repository.js +35 -9
- package/core/server/services/link-tracking/link-click-tracking-service.js +54 -4
- package/core/server/services/member-attribution/outbound-link-tagger.js +3 -1
- package/core/server/services/member-welcome-emails/member-welcome-email-renderer.js +20 -4
- package/core/server/services/member-welcome-emails/service.js +15 -3
- package/core/server/services/members/api.js +1 -2
- package/core/server/services/members/import-export/csv/formula.js +16 -0
- package/core/server/services/members/import-export/csv/formula.ts +14 -0
- package/core/server/services/members/import-export/csv/index.js +3 -1
- package/core/server/services/members/import-export/csv/index.ts +1 -0
- package/core/server/services/members/import-export/import/completion-email.js +22 -3
- package/core/server/services/members/import-export/import/completion-email.ts +29 -7
- package/core/server/services/members/import-export/import/importer.js +25 -4
- package/core/server/services/members/import-export/import/importer.ts +44 -5
- package/core/server/services/members/import-export/index.js +18 -1
- package/core/server/services/members/import-export/index.ts +32 -3
- package/core/server/services/members/members-api/controllers/router-controller.js +38 -36
- package/core/server/services/members/members-api/members-api.js +13 -7
- package/core/server/services/members/members-api/repositories/event-repository.js +4 -94
- package/core/server/services/members/members-api/services/member-bread-service.js +3 -3
- package/core/server/services/members/members-api/services/payments-service.js +6 -68
- package/core/server/services/members/service.js +8 -1
- package/core/server/services/members-custom-fields/schema.js +8 -1
- package/core/server/services/members-custom-fields/schema.ts +8 -0
- package/core/server/services/members-custom-fields/values-service.js +136 -8
- package/core/server/services/members-custom-fields/values-service.ts +152 -10
- package/core/server/services/mentions/service.js +5 -1
- package/core/server/services/oembed/oembed-service.js +44 -3
- package/core/server/services/posts/posts-service.js +11 -0
- package/core/server/services/route-settings/dynamic-routing-service.js +21 -52
- package/core/server/services/route-settings/index.js +1 -16
- package/core/server/services/route-settings/route-settings-parser.js +25 -25
- package/core/server/services/route-settings/route-settings-parser.ts +27 -27
- package/core/server/services/route-settings/validation-errors.js +68 -4
- package/core/server/services/route-settings/validation-errors.ts +79 -4
- package/core/server/services/settings/settings-service.js +0 -18
- package/core/server/services/stats/posts-stats-service.js +27 -23
- package/core/server/services/stripe/services/webhook/charge-refunded-event-service.js +1 -1
- package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +16 -4
- package/core/server/services/stripe/stripe-api.js +10 -0
- package/core/server/services/url/url-service-facade.js +1 -1
- package/core/server/services/url/url-service-facade.ts +8 -1
- package/core/server/web/api/endpoints/admin/routes.js +1 -0
- package/core/server/web/gift-preview/controller.js +10 -25
- package/core/shared/labs.js +2 -2
- package/package.json +8 -7
- package/pnpm-lock.yaml +28 -18
- package/pnpm-workspace.yaml +6 -4
- package/components/tryghost-kg-default-nodes-2.1.3.tgz +0 -0
- package/core/built/admin/assets/Growth-BTP1LthE.js +0 -3
- package/core/built/admin/assets/Newsletters-CSEX0myc.js +0 -1
- package/core/built/admin/assets/Overview-BjACEsJF.js +0 -1
- package/core/built/admin/assets/Web-CxxxjCcv.js +0 -2
- package/core/built/admin/assets/activitypub/layout-CziktJXo.js +0 -1
- package/core/built/admin/assets/audience-X_XsZivI.js +0 -1
- package/core/built/admin/assets/chunk.524.8365cd9280405c0f6216.js +0 -25
- package/core/built/admin/assets/chunk.582.61d078937e6102769f2c.js +0 -27
- package/core/built/admin/assets/comments-CvyXxOyN.js +0 -1
- package/core/built/admin/assets/constants-c-JNF9c2.js +0 -1
- package/core/built/admin/assets/dist-CjY-f5Z1.js +0 -1
- package/core/built/admin/assets/editor-BOG2YPUm.js +0 -8
- package/core/built/admin/assets/field-D0XISCK2.js +0 -1
- package/core/built/admin/assets/filter-sources-Bieps75g.js +0 -1
- package/core/built/admin/assets/filters-CuB-A7ma.js +0 -1
- package/core/built/admin/assets/gift-link-modal-su8MsRdg.js +0 -1
- package/core/built/admin/assets/growth-Ba6S5FQX.js +0 -1
- package/core/built/admin/assets/index-D8PbzuT9.css +0 -1
- package/core/built/admin/assets/index-ukW_0Uie.js +0 -67
- package/core/built/admin/assets/input-group-CGOXcy4l.js +0 -1
- package/core/built/admin/assets/label-picker-Uq91atex.js +0 -1
- package/core/built/admin/assets/labels-Cyayfd-e.js +0 -1
- package/core/built/admin/assets/layout-WUcz6tu1.js +0 -1
- package/core/built/admin/assets/link-helpers-tOlxmuH5.js +0 -1
- package/core/built/admin/assets/member-custom-fields-NCzrMuba.js +0 -1
- package/core/built/admin/assets/member-detail-DPWDtYnN.js +0 -1
- package/core/built/admin/assets/members-B9rO7qr4.js +0 -10
- package/core/built/admin/assets/modals-CxRaan1J.js +0 -31
- package/core/built/admin/assets/moderation-D8zon60E.js +0 -1
- package/core/built/admin/assets/multi-select-combobox-1wYm3nle.js +0 -1
- package/core/built/admin/assets/newsletter-DbYMRxRS.js +0 -1
- package/core/built/admin/assets/note-PiWPnnrh.js +0 -1
- package/core/built/admin/assets/notifications-DEgqqB9G.js +0 -1
- package/core/built/admin/assets/nql-BsgFMd93.js +0 -1
- package/core/built/admin/assets/onboarding-route-BzF6HeVn.js +0 -1
- package/core/built/admin/assets/overview-DixLeIqY.js +0 -1
- package/core/built/admin/assets/post-analytics-header-DsMoLx0R.js +0 -1
- package/core/built/admin/assets/post-analytics-provider-BJCPLMIb.js +0 -1
- package/core/built/admin/assets/preferences-D7-j6A4C.js +0 -5
- package/core/built/admin/assets/profile-Dl69QPp0.js +0 -1
- package/core/built/admin/assets/select-C1qDZnW4.js +0 -1
- package/core/built/admin/assets/settings-BbmC_Iqq.js +0 -4
- package/core/built/admin/assets/social-urls-BPL1nADp.js +0 -8
- package/core/built/admin/assets/tabs-BQcJQ1ke.js +0 -1
- package/core/built/admin/assets/textarea-Bjccvh_E.js +0 -1
- package/core/built/admin/assets/use-filter-params-DjXkhO54.js +0 -1
- package/core/built/admin/assets/web-LtHNiNBV.js +0 -1
- package/core/server/services/gifts/gift-repository.js +0 -2
- package/core/server/services/gifts/gift-repository.ts +0 -29
- package/core/server/services/route-settings/activation-bridge.js +0 -164
- package/core/server/services/route-settings/activation-bridge.ts +0 -210
- package/core/server/services/route-settings/default-settings-manager.js +0 -63
- package/core/server/services/route-settings/route-settings.js +0 -170
- package/core/server/services/route-settings/settings-loader.js +0 -60
- package/core/server/services/route-settings/settings-path-manager.js +0 -47
- package/core/server/services/route-settings/validate.js +0 -440
|
@@ -13,6 +13,7 @@ const express = require('../../../shared/express');
|
|
|
13
13
|
const _ = require('lodash');
|
|
14
14
|
const url = require('url');
|
|
15
15
|
const security = require('@tryghost/security');
|
|
16
|
+
const {resolveResourceRead} = require('./api-adapter');
|
|
16
17
|
const urlUtils = require('../../../shared/url-utils').default;
|
|
17
18
|
const registry = require('./registry');
|
|
18
19
|
|
|
@@ -197,6 +198,11 @@ class ParentRouter {
|
|
|
197
198
|
|
|
198
199
|
/**
|
|
199
200
|
* @description Figure out if the router has a redirect enabled.
|
|
201
|
+
*
|
|
202
|
+
* A route claims a resource by reading it: `data: tag.bacon` on this router
|
|
203
|
+
* means /tag/bacon/ should redirect here from wherever else it lives. Only
|
|
204
|
+
* `read` entries claim a slug, and an entry can opt out with `redirect: false`.
|
|
205
|
+
*
|
|
200
206
|
* @param {string} routerType
|
|
201
207
|
* @param {string} slug
|
|
202
208
|
* @returns {boolean}
|
|
@@ -204,14 +210,21 @@ class ParentRouter {
|
|
|
204
210
|
isRedirectEnabled(routerType, slug) {
|
|
205
211
|
debug('isRedirectEnabled', this.name, this.route && this.route.value, routerType, slug);
|
|
206
212
|
|
|
207
|
-
if (!this.data
|
|
213
|
+
if (!this.data) {
|
|
208
214
|
return false;
|
|
209
215
|
}
|
|
210
216
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
217
|
+
// Top-level shorthand (`data: tag.bacon`) is a single unnamed entry.
|
|
218
|
+
const entries = typeof this.data === 'string' ? [this.data] : Object.values(this.data);
|
|
219
|
+
|
|
220
|
+
return entries.some((entry) => {
|
|
221
|
+
if (typeof entry !== 'string' && entry.redirect === false) {
|
|
222
|
+
return false;
|
|
214
223
|
}
|
|
224
|
+
|
|
225
|
+
const read = resolveResourceRead(entry);
|
|
226
|
+
|
|
227
|
+
return !!read && read.resource === routerType && read.slug === slug;
|
|
215
228
|
});
|
|
216
229
|
}
|
|
217
230
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toExpressNotation = toExpressNotation;
|
|
4
|
+
exports.toDomainNotation = toDomainNotation;
|
|
5
|
+
/**
|
|
6
|
+
* Convert a domain-model permalink into Express / URL-service notation.
|
|
7
|
+
*
|
|
8
|
+
* @example toExpressNotation('/{slug}/') // => '/:slug/'
|
|
9
|
+
* @example toExpressNotation('/{primary_tag}/{slug}/') // => '/:primary_tag/:slug/'
|
|
10
|
+
* @example toExpressNotation('/:slug/') // => '/:slug/' (idempotent)
|
|
11
|
+
*/
|
|
12
|
+
function toExpressNotation(permalink) {
|
|
13
|
+
return permalink.replace(/{(\w+)}/g, ':$1');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Convert an Express / URL-service permalink back into domain-model notation.
|
|
17
|
+
* Will be used on the download path when serialising the canonical shape back
|
|
18
|
+
* to YAML — no production caller yet.
|
|
19
|
+
*
|
|
20
|
+
* @example toDomainNotation('/:slug/') // => '/{slug}/'
|
|
21
|
+
* @example toDomainNotation('/:primary_tag/:slug/') // => '/{primary_tag}/{slug}/'
|
|
22
|
+
* @example toDomainNotation('/{slug}/') // => '/{slug}/' (idempotent)
|
|
23
|
+
*/
|
|
24
|
+
function toDomainNotation(permalink) {
|
|
25
|
+
return permalink.replace(/:(\w+)/g, '{$1}');
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a domain-model permalink into Express / URL-service notation.
|
|
3
|
+
*
|
|
4
|
+
* @example toExpressNotation('/{slug}/') // => '/:slug/'
|
|
5
|
+
* @example toExpressNotation('/{primary_tag}/{slug}/') // => '/:primary_tag/:slug/'
|
|
6
|
+
* @example toExpressNotation('/:slug/') // => '/:slug/' (idempotent)
|
|
7
|
+
*/
|
|
8
|
+
export function toExpressNotation(permalink: string): string {
|
|
9
|
+
return permalink.replace(/{(\w+)}/g, ':$1');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Convert an Express / URL-service permalink back into domain-model notation.
|
|
14
|
+
* Will be used on the download path when serialising the canonical shape back
|
|
15
|
+
* to YAML — no production caller yet.
|
|
16
|
+
*
|
|
17
|
+
* @example toDomainNotation('/:slug/') // => '/{slug}/'
|
|
18
|
+
* @example toDomainNotation('/:primary_tag/:slug/') // => '/{primary_tag}/{slug}/'
|
|
19
|
+
* @example toDomainNotation('/{slug}/') // => '/{slug}/' (idempotent)
|
|
20
|
+
*/
|
|
21
|
+
export function toDomainNotation(permalink: string): string {
|
|
22
|
+
return permalink.replace(/:(\w+)/g, '{$1}');
|
|
23
|
+
}
|
|
@@ -1,58 +1,82 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
|
-
let routes = [];
|
|
3
|
-
let routers = {};
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
|
-
*
|
|
4
|
+
* Every registered router is a Ghost router — `ParentRouter` itself (the site
|
|
5
|
+
* and apps routers) or one of its subclasses (Collection, StaticRoutes,
|
|
6
|
+
* Taxonomy, StaticPages, Preview, Email, Unsubscribe). They wrap an Express
|
|
7
|
+
* router, reachable via `.router()`, but are not one themselves: the registry's
|
|
8
|
+
* own lookups read Ghost-side members (`.name`, `.routerName`, `.reset()`,
|
|
9
|
+
* `.getRssUrl()`) that an Express router does not have.
|
|
10
|
+
*
|
|
11
|
+
* Type-only import — no runtime require, so this does not close a cycle with
|
|
12
|
+
* `parent-router.js`, which requires this module.
|
|
13
|
+
*
|
|
14
|
+
* @typedef {import('./parent-router')} ParentRouter
|
|
7
15
|
*/
|
|
8
|
-
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @description The router registry is helpful for debugging purposes and lets you search existing routes and routers.
|
|
19
|
+
*
|
|
20
|
+
* Exported as a single shared instance so that every consumer
|
|
21
|
+
* (`routing/index.js`, `parent-router.js`) operates on the same registry, the
|
|
22
|
+
* same way the previous module-level state did — just held on an instance
|
|
23
|
+
* rather than in module-scoped `let` variables.
|
|
24
|
+
*/
|
|
25
|
+
class Registry {
|
|
26
|
+
constructor() {
|
|
27
|
+
/** @type {Array<{route: string, from: string}>} */
|
|
28
|
+
this.routes = [];
|
|
29
|
+
/** @type {Object<string, ParentRouter>} */
|
|
30
|
+
this.routers = {};
|
|
31
|
+
}
|
|
32
|
+
|
|
9
33
|
/**
|
|
10
|
-
* @description
|
|
34
|
+
* @description Gets called if you register a url pattern in express.
|
|
11
35
|
* @param {string} routerName
|
|
12
36
|
* @param {string} route
|
|
13
37
|
*/
|
|
14
38
|
setRoute(routerName, route) {
|
|
15
|
-
routes.push({route: route, from: routerName});
|
|
16
|
-
}
|
|
39
|
+
this.routes.push({route: route, from: routerName});
|
|
40
|
+
}
|
|
17
41
|
|
|
18
42
|
/**
|
|
19
|
-
* @description
|
|
43
|
+
* @description Gets called if you register a router in express.
|
|
20
44
|
* @param {string} name
|
|
21
|
-
* @param {
|
|
45
|
+
* @param {ParentRouter} router
|
|
22
46
|
*/
|
|
23
47
|
setRouter(name, router) {
|
|
24
|
-
routers[name] = router;
|
|
25
|
-
}
|
|
48
|
+
this.routers[name] = router;
|
|
49
|
+
}
|
|
26
50
|
|
|
27
51
|
/**
|
|
28
52
|
* @description Get all registered routes.
|
|
29
|
-
* @returns {Array}
|
|
53
|
+
* @returns {Array<{route: string, from: string}>}
|
|
30
54
|
*/
|
|
31
55
|
getAllRoutes() {
|
|
32
|
-
return _.cloneDeep(routes);
|
|
33
|
-
}
|
|
56
|
+
return _.cloneDeep(this.routes);
|
|
57
|
+
}
|
|
34
58
|
|
|
35
59
|
/**
|
|
36
60
|
* @description Get router by name.
|
|
37
61
|
* @param {string} name
|
|
38
|
-
* @returns {
|
|
62
|
+
* @returns {ParentRouter|undefined}
|
|
39
63
|
*/
|
|
40
64
|
getRouter(name) {
|
|
41
|
-
return routers[name];
|
|
42
|
-
}
|
|
65
|
+
return this.routers[name];
|
|
66
|
+
}
|
|
43
67
|
|
|
44
68
|
/**
|
|
45
|
-
* Gets a router by
|
|
69
|
+
* Gets a router by its internal router name
|
|
46
70
|
* @param {string} name internal router name
|
|
47
|
-
* @returns {
|
|
71
|
+
* @returns {ParentRouter|undefined}
|
|
48
72
|
*/
|
|
49
73
|
getRouterByName(name) {
|
|
50
|
-
for (let routerKey in routers) {
|
|
51
|
-
if (routers[routerKey].name === name) {
|
|
52
|
-
return routers[routerKey];
|
|
74
|
+
for (let routerKey in this.routers) {
|
|
75
|
+
if (this.routers[routerKey].name === name) {
|
|
76
|
+
return this.routers[routerKey];
|
|
53
77
|
}
|
|
54
78
|
}
|
|
55
|
-
}
|
|
79
|
+
}
|
|
56
80
|
|
|
57
81
|
/**
|
|
58
82
|
*
|
|
@@ -77,7 +101,7 @@ module.exports = {
|
|
|
77
101
|
getRssUrl(options) {
|
|
78
102
|
let rssUrl = null;
|
|
79
103
|
|
|
80
|
-
const collectionIndexRouter = _.find(routers, {name: 'CollectionRouter', routerName: 'index'});
|
|
104
|
+
const collectionIndexRouter = _.find(this.routers, {name: 'CollectionRouter', routerName: 'index'});
|
|
81
105
|
|
|
82
106
|
if (collectionIndexRouter) {
|
|
83
107
|
rssUrl = collectionIndexRouter.getRssUrl(options);
|
|
@@ -88,7 +112,7 @@ module.exports = {
|
|
|
88
112
|
}
|
|
89
113
|
}
|
|
90
114
|
|
|
91
|
-
const collectionRouters = _.filter(routers, {name: 'CollectionRouter'});
|
|
115
|
+
const collectionRouters = _.filter(this.routers, {name: 'CollectionRouter'});
|
|
92
116
|
|
|
93
117
|
if (collectionRouters && collectionRouters.length === 1) {
|
|
94
118
|
rssUrl = collectionRouters[0].getRssUrl(options);
|
|
@@ -108,32 +132,34 @@ module.exports = {
|
|
|
108
132
|
}
|
|
109
133
|
|
|
110
134
|
return rssUrl;
|
|
111
|
-
}
|
|
135
|
+
}
|
|
112
136
|
|
|
113
137
|
/**
|
|
114
138
|
* @description Reset all routes.
|
|
115
139
|
*/
|
|
116
140
|
resetAllRoutes() {
|
|
117
|
-
routes = [];
|
|
118
|
-
}
|
|
141
|
+
this.routes = [];
|
|
142
|
+
}
|
|
119
143
|
|
|
120
144
|
/**
|
|
121
145
|
* @description Reset all routers.
|
|
122
146
|
*/
|
|
123
147
|
resetAllRouters() {
|
|
124
|
-
_.each(routers, (value) => {
|
|
148
|
+
_.each(this.routers, (value) => {
|
|
125
149
|
if (value && typeof value.reset === 'function') {
|
|
126
150
|
value.reset();
|
|
127
151
|
}
|
|
128
152
|
});
|
|
129
153
|
|
|
130
|
-
routers = {};
|
|
131
|
-
}
|
|
154
|
+
this.routers = {};
|
|
155
|
+
}
|
|
132
156
|
|
|
133
157
|
/**
|
|
134
158
|
* @description Clear all routers (for testing).
|
|
135
159
|
*/
|
|
136
160
|
clearAllRouters() {
|
|
137
|
-
routers = {};
|
|
161
|
+
this.routers = {};
|
|
138
162
|
}
|
|
139
|
-
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = new Registry();
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const debug = require('@tryghost/debug')('frontend:routing');
|
|
2
|
-
const _ = require('lodash');
|
|
3
2
|
const StaticRoutesRouter = require('./static-routes-router');
|
|
4
3
|
const StaticPagesRouter = require('./static-pages-router');
|
|
5
4
|
const CollectionRouter = require('./collection-router');
|
|
@@ -91,10 +90,10 @@ class RouterManager {
|
|
|
91
90
|
* 5. Static Pages: Weaker than collections, because we first try to find a post slug and fallback to lookup a static page.
|
|
92
91
|
* 6. Internal Apps: Weakest
|
|
93
92
|
*
|
|
94
|
-
* @param {
|
|
93
|
+
* @param {RouteSettings} routeSettings
|
|
95
94
|
*/
|
|
96
|
-
start(
|
|
97
|
-
debug('routing start',
|
|
95
|
+
start(routeSettings) {
|
|
96
|
+
debug('routing start', routeSettings);
|
|
98
97
|
const RESOURCE_CONFIG = require(`./config`);
|
|
99
98
|
|
|
100
99
|
const unsubscribeRouter = new UnsubscribeRouter();
|
|
@@ -111,30 +110,30 @@ class RouterManager {
|
|
|
111
110
|
this.siteRouter.mountRouter(previewRouter.router());
|
|
112
111
|
this.registry.setRouter('previewRouter', previewRouter);
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
const staticRoutesRouter = new StaticRoutesRouter(
|
|
113
|
+
for (const route of routeSettings.routes) {
|
|
114
|
+
const staticRoutesRouter = new StaticRoutesRouter(route.path, route, this.routerCreated.bind(this));
|
|
116
115
|
this.siteRouter.mountRouter(staticRoutesRouter.router());
|
|
117
116
|
|
|
118
117
|
this.registry.setRouter(staticRoutesRouter.identifier, staticRoutesRouter);
|
|
119
|
-
}
|
|
118
|
+
}
|
|
120
119
|
|
|
121
|
-
|
|
122
|
-
const collectionRouter = new CollectionRouter(
|
|
120
|
+
for (const collection of routeSettings.collections) {
|
|
121
|
+
const collectionRouter = new CollectionRouter(collection.path, collection, RESOURCE_CONFIG, this.routerCreated.bind(this));
|
|
123
122
|
this.siteRouter.mountRouter(collectionRouter.router());
|
|
124
123
|
this.registry.setRouter(collectionRouter.identifier, collectionRouter);
|
|
125
|
-
}
|
|
124
|
+
}
|
|
126
125
|
|
|
127
126
|
const staticPagesRouter = new StaticPagesRouter(RESOURCE_CONFIG, this.routerCreated.bind(this));
|
|
128
127
|
this.siteRouter.mountRouter(staticPagesRouter.router());
|
|
129
128
|
|
|
130
129
|
this.registry.setRouter('staticPagesRouter', staticPagesRouter);
|
|
131
130
|
|
|
132
|
-
|
|
133
|
-
const taxonomyRouter = new TaxonomyRouter(key,
|
|
131
|
+
for (const [key, permalink] of Object.entries(routeSettings.taxonomies)) {
|
|
132
|
+
const taxonomyRouter = new TaxonomyRouter(key, permalink, RESOURCE_CONFIG, this.routerCreated.bind(this));
|
|
134
133
|
this.siteRouter.mountRouter(taxonomyRouter.router());
|
|
135
134
|
|
|
136
135
|
this.registry.setRouter(taxonomyRouter.identifier, taxonomyRouter);
|
|
137
|
-
}
|
|
136
|
+
}
|
|
138
137
|
|
|
139
138
|
const appRouter = new ParentRouter('AppsRouter');
|
|
140
139
|
this.siteRouter.mountRouter(appRouter.router());
|
|
@@ -181,15 +180,12 @@ module.exports = RouterManager;
|
|
|
181
180
|
|
|
182
181
|
/**
|
|
183
182
|
* @typedef {Object} RouterConfig
|
|
184
|
-
* @property {RouteSettings} [routeSettings] -
|
|
183
|
+
* @property {RouteSettings} [routeSettings] - parsed route settings domain model
|
|
185
184
|
* @property {URLServiceFacade} urlService - resource-based URL service facade
|
|
186
185
|
*/
|
|
187
186
|
|
|
188
187
|
/**
|
|
189
|
-
* @typedef {
|
|
190
|
-
* @property {Object} routes
|
|
191
|
-
* @property {Object} collections
|
|
192
|
-
* @property {Object} taxonomies
|
|
188
|
+
* @typedef {import('@tryghost/adapter-base-route-settings').RouteSettings} RouteSettings
|
|
193
189
|
*/
|
|
194
190
|
|
|
195
191
|
/**
|
|
@@ -15,7 +15,7 @@ class StaticRoutesRouter extends ParentRouter {
|
|
|
15
15
|
|
|
16
16
|
this.route = {value: mainRoute};
|
|
17
17
|
this.templates = object.templates || [];
|
|
18
|
-
this.data = object.data || {
|
|
18
|
+
this.data = object.data || {};
|
|
19
19
|
this.routerName = mainRoute === '/' ? 'index' : mainRoute.replace(/\//g, '');
|
|
20
20
|
this.routerCreated = routerCreated;
|
|
21
21
|
|
|
@@ -30,12 +30,12 @@ class StaticRoutesRouter extends ParentRouter {
|
|
|
30
30
|
this.limit = object.limit;
|
|
31
31
|
this.order = object.order;
|
|
32
32
|
|
|
33
|
-
this.
|
|
33
|
+
this.type = object.type;
|
|
34
34
|
|
|
35
35
|
debug(this.route.value, this.templates, this.filter, this.data);
|
|
36
36
|
this._registerChannelRoutes();
|
|
37
37
|
} else {
|
|
38
|
-
this.contentType = object.
|
|
38
|
+
this.contentType = object.contentType;
|
|
39
39
|
debug(this.route.value, this.templates);
|
|
40
40
|
this._registerStaticRoute();
|
|
41
41
|
}
|
|
@@ -56,11 +56,11 @@ class StaticRoutesRouter extends ParentRouter {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// REGISTER: channel route
|
|
59
|
-
this.mountRoute(this.route.value, controllers[this.
|
|
59
|
+
this.mountRoute(this.route.value, controllers[this.type]);
|
|
60
60
|
|
|
61
61
|
// REGISTER: pagination
|
|
62
62
|
this.router().param('page', middleware.pageParam);
|
|
63
|
-
this.mountRoute(urlUtils.urlJoin(this.route.value, 'page', ':page(\\d+)'), controllers[this.
|
|
63
|
+
this.mountRoute(urlUtils.urlJoin(this.route.value, 'page', ':page(\\d+)'), controllers[this.type]);
|
|
64
64
|
|
|
65
65
|
this.routerCreated(this);
|
|
66
66
|
}
|
|
@@ -74,13 +74,13 @@ class StaticRoutesRouter extends ParentRouter {
|
|
|
74
74
|
*/
|
|
75
75
|
_prepareChannelContext(req, res, next) {
|
|
76
76
|
res.routerOptions = {
|
|
77
|
-
type: this.
|
|
77
|
+
type: this.type,
|
|
78
78
|
name: this.routerName,
|
|
79
79
|
context: [this.routerName],
|
|
80
80
|
filter: this.filter,
|
|
81
81
|
limit: this.limit,
|
|
82
82
|
order: this.order,
|
|
83
|
-
data: this.data
|
|
83
|
+
data: this.data,
|
|
84
84
|
templates: this.templates
|
|
85
85
|
};
|
|
86
86
|
|
|
@@ -117,7 +117,7 @@ class StaticRoutesRouter extends ParentRouter {
|
|
|
117
117
|
message: `Missing template ${res.routerOptions.templates.map(x => `${x}.hbs`).join(', ')} for route "${req.originalUrl}".`
|
|
118
118
|
});
|
|
119
119
|
},
|
|
120
|
-
data: this.data
|
|
120
|
+
data: this.data,
|
|
121
121
|
context: [this.routerName],
|
|
122
122
|
contentType: this.contentType
|
|
123
123
|
};
|
|
@@ -131,11 +131,9 @@ class StaticRoutesRouter extends ParentRouter {
|
|
|
131
131
|
* @returns {boolean}
|
|
132
132
|
*/
|
|
133
133
|
isChannel(object) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return this.controller === 'channel';
|
|
134
|
+
// parseRouteSettings always sets `type` ('channel' | 'template') on
|
|
135
|
+
// every route, so a channel is simply `type === 'channel'`.
|
|
136
|
+
return object?.type === 'channel';
|
|
139
137
|
}
|
|
140
138
|
}
|
|
141
139
|
|
|
@@ -5,6 +5,7 @@ const RSSRouter = require('./rss-router');
|
|
|
5
5
|
const urlUtils = require('../../../shared/url-utils').default;
|
|
6
6
|
const controllers = require('./controllers');
|
|
7
7
|
const middleware = require('./middleware');
|
|
8
|
+
const {toExpressNotation} = require('./permalink-adapter');
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* @description Taxonomies are groupings of posts based on a common relation.
|
|
@@ -17,8 +18,9 @@ class TaxonomyRouter extends ParentRouter {
|
|
|
17
18
|
this.taxonomyKey = key;
|
|
18
19
|
this.RESOURCE_CONFIG = RESOURCE_CONFIG;
|
|
19
20
|
|
|
21
|
+
// convert domain `{slug}` -> Express/URL-service `:slug` at this boundary
|
|
20
22
|
this.permalinks = {
|
|
21
|
-
value: permalinks
|
|
23
|
+
value: toExpressNotation(permalinks)
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
this.permalinks.getValue = () => {
|
|
@@ -74,7 +76,9 @@ class TaxonomyRouter extends ParentRouter {
|
|
|
74
76
|
type: 'channel',
|
|
75
77
|
name: this.taxonomyKey,
|
|
76
78
|
permalinks: this.permalinks.getValue(),
|
|
77
|
-
data
|
|
79
|
+
// Route data in domain form — the API adapter resolves it to a
|
|
80
|
+
// controller call, and fetch-data fills `%s` in from the request.
|
|
81
|
+
data: {[this.taxonomyKey]: {type: 'read', resource: this.getResourceType(), slug: '%s'}},
|
|
78
82
|
filter: this.RESOURCE_CONFIG.TAXONOMIES[this.taxonomyKey].filter,
|
|
79
83
|
resourceType: this.getResourceType(),
|
|
80
84
|
context: [this.taxonomyKey],
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const automationsApi = __importStar(require("../../services/automations/automations-api"));
|
|
37
|
+
const controller = {
|
|
38
|
+
docName: 'automation_action_links',
|
|
39
|
+
browse: {
|
|
40
|
+
headers: {
|
|
41
|
+
cacheInvalidate: false
|
|
42
|
+
},
|
|
43
|
+
options: [
|
|
44
|
+
'automation_id',
|
|
45
|
+
'action_id'
|
|
46
|
+
],
|
|
47
|
+
validation: {
|
|
48
|
+
options: {
|
|
49
|
+
automation_id: {
|
|
50
|
+
required: true
|
|
51
|
+
},
|
|
52
|
+
action_id: {
|
|
53
|
+
required: true
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
permissions: {
|
|
58
|
+
docName: 'automations',
|
|
59
|
+
method: 'read'
|
|
60
|
+
},
|
|
61
|
+
async query(frame) {
|
|
62
|
+
return {
|
|
63
|
+
data: await automationsApi.browseActionLinks(frame.options.automation_id, frame.options.action_id)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
module.exports = controller;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as automationsApi from '../../services/automations/automations-api';
|
|
2
|
+
|
|
3
|
+
type BrowseFrame = {
|
|
4
|
+
options: {
|
|
5
|
+
automation_id: string;
|
|
6
|
+
action_id: string;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const controller = {
|
|
11
|
+
docName: 'automation_action_links',
|
|
12
|
+
|
|
13
|
+
browse: {
|
|
14
|
+
headers: {
|
|
15
|
+
cacheInvalidate: false
|
|
16
|
+
},
|
|
17
|
+
options: [
|
|
18
|
+
'automation_id',
|
|
19
|
+
'action_id'
|
|
20
|
+
],
|
|
21
|
+
validation: {
|
|
22
|
+
options: {
|
|
23
|
+
automation_id: {
|
|
24
|
+
required: true
|
|
25
|
+
},
|
|
26
|
+
action_id: {
|
|
27
|
+
required: true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
permissions: {
|
|
32
|
+
docName: 'automations',
|
|
33
|
+
method: 'read'
|
|
34
|
+
},
|
|
35
|
+
async query(frame: BrowseFrame) {
|
|
36
|
+
return {
|
|
37
|
+
data: await automationsApi.browseActionLinks(
|
|
38
|
+
frame.options.automation_id,
|
|
39
|
+
frame.options.action_id
|
|
40
|
+
)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
module.exports = controller;
|
|
@@ -11,6 +11,10 @@ module.exports = {
|
|
|
11
11
|
return apiFramework.pipeline(require('./automations'), localUtils);
|
|
12
12
|
},
|
|
13
13
|
|
|
14
|
+
get automationActionLinks() {
|
|
15
|
+
return apiFramework.pipeline(require('./automation-action-links'), localUtils);
|
|
16
|
+
},
|
|
17
|
+
|
|
14
18
|
get automationEmailPreviews() {
|
|
15
19
|
return apiFramework.pipeline(require('./automation-email-previews'), localUtils);
|
|
16
20
|
},
|
|
@@ -174,8 +174,6 @@ const controller = {
|
|
|
174
174
|
async query(frame) {
|
|
175
175
|
const content = await fs.readFile(frame.file.path, 'utf8');
|
|
176
176
|
await routeSettings.api.upload(content);
|
|
177
|
-
const getRoutesHash = () => routeSettings.api.getCurrentHash();
|
|
178
|
-
await settingsService.syncRoutesHash(getRoutesHash);
|
|
179
177
|
}
|
|
180
178
|
},
|
|
181
179
|
|
|
@@ -24,7 +24,17 @@ const forPost = (id, attrs, frame, type = 'posts') => {
|
|
|
24
24
|
return attrs;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
// Diagnostic only: hand the compare-mode URL service the producing api
|
|
28
|
+
// endpoint. The parity/thin-resource logs capture a caller stack, but it
|
|
29
|
+
// truncates at the async api-framework boundary and never names the
|
|
30
|
+
// endpoint; the api-framework Frame carries it, so pass it through. Omitted
|
|
31
|
+
// for non-api callers (mentions, email) whose frame has no endpoint fields.
|
|
32
|
+
const options = {absolute: true};
|
|
33
|
+
if (frame && (frame.docName || frame.method)) {
|
|
34
|
+
options.serializerContext = {apiType: frame.apiType, docName: frame.docName, method: frame.method};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
attrs.url = urlService.facade.getUrlForResource({...attrs, id, type}, options);
|
|
28
38
|
|
|
29
39
|
/**
|
|
30
40
|
* CASE: admin api should serve preview urls
|
package/core/server/data/migrations/versions/6.55/2026-07-27-11-25-44-add-to-hash-to-redirects.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const {combineNonTransactionalMigrations, createAddColumnMigration, createNonTransactionalMigration} = require('../../utils');
|
|
3
|
+
const {addIndex, addUnique, dropIndex, dropUnique, getIndexes} = require('../../../schema/commands');
|
|
4
|
+
|
|
5
|
+
const uniqueColumns = ['automation_action_revision_id', 'to_hash'];
|
|
6
|
+
const leftoverIndexName = 'redirects_automation_action_revision_id_index';
|
|
7
|
+
|
|
8
|
+
module.exports = combineNonTransactionalMigrations(
|
|
9
|
+
createAddColumnMigration('redirects', 'to_hash', {
|
|
10
|
+
type: 'binary',
|
|
11
|
+
maxlength: 32,
|
|
12
|
+
nullable: true
|
|
13
|
+
}, {algorithm: 'auto'}),
|
|
14
|
+
createNonTransactionalMigration(
|
|
15
|
+
async function up(knex) {
|
|
16
|
+
await addUnique('redirects', uniqueColumns, knex);
|
|
17
|
+
|
|
18
|
+
// A previous down() leaves a standalone index behind (see below).
|
|
19
|
+
// InnoDB drops the index it created for the foreign key itself once
|
|
20
|
+
// the composite unique can serve the constraint, but not one we
|
|
21
|
+
// created, so drop it here to keep a rolled-back-and-remigrated
|
|
22
|
+
// database in the same shape as every other one.
|
|
23
|
+
const indexes = await getIndexes('redirects', knex);
|
|
24
|
+
|
|
25
|
+
if (indexes.includes(leftoverIndexName)) {
|
|
26
|
+
await dropIndex('redirects', ['automation_action_revision_id'], knex);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
async function down(knex) {
|
|
30
|
+
try {
|
|
31
|
+
await dropUnique('redirects', uniqueColumns, knex);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
// The composite unique ends up as the only index covering the
|
|
34
|
+
// automation_action_revision_id FK: fresh installs create it
|
|
35
|
+
// that way, and on upgrades InnoDB drops the FK's own index
|
|
36
|
+
// once the composite can serve the constraint. MySQL won't
|
|
37
|
+
// drop the last index a foreign key depends on, so re-add a
|
|
38
|
+
// single-column one when it objects.
|
|
39
|
+
if (err.code === 'ER_DROP_INDEX_FK') {
|
|
40
|
+
logging.warn('Cannot drop unique constraint over redirects(automation_action_revision_id, to_hash) while it backs the foreign key, re-adding index for automation_action_revision_id');
|
|
41
|
+
|
|
42
|
+
await addIndex('redirects', ['automation_action_revision_id'], knex);
|
|
43
|
+
await dropUnique('redirects', uniqueColumns, knex);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
);
|