ghost 6.54.0 → 6.55.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.2.0.tgz +0 -0
- package/components/tryghost-adapter-base-sso-0.1.1.tgz +0 -0
- package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
- package/components/tryghost-kg-default-cards-10.3.3.tgz +0 -0
- package/core/boot.js +3 -6
- package/core/built/admin/assets/{account-migration-DLvVA5yq.js → account-migration-sjHLx5dy.js} +1 -1
- package/core/built/admin/assets/activitypub/{account-migration-DHbZcxGM.js → account-migration-DoYXtnZ8.js} +4 -4
- package/core/built/admin/assets/activitypub/activitypub.js +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-zfxUey_L.js → bluesky-sharing-Bxeh6MKW.js} +4 -4
- package/core/built/admin/assets/activitypub/{dist-BqkDUQxJ2.js → dist-ByFmDSNP2.js} +64 -63
- package/core/built/admin/assets/activitypub/{dist-Ba_QxHHl.js → dist-D8sFfdpC.js} +2 -2
- package/core/built/admin/assets/activitypub/{domain-CmwSZLHK.js → domain-CWueFW6q.js} +5 -5
- package/core/built/admin/assets/activitypub/{edit-profile-CXdwNmVG.js → edit-profile-BGxPU7N5.js} +3 -3
- package/core/built/admin/assets/activitypub/{explore-DfbjzGM1.js → explore-DBK-u0Ch.js} +3 -3
- package/core/built/admin/assets/activitypub/{feed-DSEBJOqf.js → feed-Bcir5RQZ.js} +3 -3
- package/core/built/admin/assets/activitypub/{field-CY7XVcx6.js → field-BV-CIT3d.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-DtQ0kytT.js → inbox-yC0nfvzl.js} +4 -4
- package/core/built/admin/assets/activitypub/{label-Dw96GQ7u.js → label-DTRS9TDk.js} +2 -2
- package/core/built/admin/assets/activitypub/layout-qx-bUL1k.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-Dg_-I-8C.js → moderation-Dwl9t0pb.js} +4 -4
- package/core/built/admin/assets/activitypub/{note-Cy1-uKMY.js → note-B-zKsZ7r.js} +3 -3
- package/core/built/admin/assets/activitypub/{notifications-B_fvoLIM.js → notifications-DjJZD54t.js} +3 -3
- package/core/built/admin/assets/activitypub/{preferences-ByJseZp6.js → preferences-CoU8vs6d.js} +6 -6
- package/core/built/admin/assets/activitypub/{profile-BFtbnIjz.js → profile-BAsaJekx.js} +6 -6
- package/core/built/admin/assets/activitypub/{routes-Dh3xXfce.js → routes-CLH3OVTP.js} +28 -25
- package/core/built/admin/assets/activitypub/{settings-DTgqJPxM.js → settings-DA6pNJ-Q.js} +3 -3
- package/core/built/admin/assets/activitypub/{site-CdL9ZLqm.js → site-CQD42Pw5.js} +2 -2
- package/core/built/admin/assets/activitypub/{tabs-ogqwoBlb.js → tabs-Cg0saow1.js} +7 -7
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-CxonteFD.js → use-reply-chain-data-Br4aOWOh.js} +2 -2
- package/core/built/admin/assets/audience-DjEWNhp3.js +1 -0
- package/core/built/admin/assets/{automated-emails-Cn87L5Md.js → automated-emails-DRy7qY-J.js} +2 -2
- package/core/built/admin/assets/{automations-BP_aHamJ.js → automations-Bx3VcFIL.js} +1 -1
- package/core/built/admin/assets/{automations-B7-y3dXt.js → automations-DhKeS_U5.js} +1 -1
- package/core/built/admin/assets/{bluesky-sharing-Bh36XPh4.js → bluesky-sharing-ClMd0-Ft.js} +1 -1
- package/core/built/admin/assets/{breadcrumb-D34YWnaw.js → breadcrumb-BD0U2ygg.js} +1 -1
- package/core/built/admin/assets/{chart-helpers-DbklaJw9.js → chart-helpers-fjQKRVyY.js} +1 -1
- package/core/built/admin/assets/checkbox-CWa28lgO.js +1 -0
- package/core/built/admin/assets/{chunk.962.b73442b07be930bb5d85.js → chunk.211.6f7328d63c41536451b3.js} +737 -559
- package/core/built/admin/assets/{chunk.962.b73442b07be930bb5d85.js.LICENSE.txt → chunk.211.6f7328d63c41536451b3.js.LICENSE.txt} +2 -0
- package/core/built/admin/assets/{chunk.589.096f4d0bb775e5229aa9.js → chunk.481.6c7395a49484bb4583aa.js} +41 -38
- package/core/built/admin/assets/chunk.524.cffd399783a519e404a9.js +25 -0
- package/core/built/admin/assets/chunk.582.eebf0d0b2d202bb746a5.js +27 -0
- package/core/built/admin/assets/code-editor-view-CCr0rBWS.js +1 -0
- package/core/built/admin/assets/comments-DyUSMUdj.js +1 -0
- package/core/built/admin/assets/{date-range-select-B5vSsrpx.js → date-range-select-BFp58EMk.js} +1 -1
- package/core/built/admin/assets/{disabled-sources-indicator-NkOIoMue.js → disabled-sources-indicator-CUxMfiPa.js} +1 -1
- package/core/built/admin/assets/dist-2Tnz2Yfq.js +1 -0
- package/core/built/admin/assets/dist-CjY-f5Z1.js +1 -0
- package/core/built/admin/assets/dist-DIC8yz5C.js +1 -0
- package/core/built/admin/assets/domain-C0bV2UV8.js +1 -0
- package/core/built/admin/assets/dropzone-DlK-K2DQ.js +5 -0
- package/core/built/admin/assets/{edit-profile-rvDGrS8J.js → edit-profile-BKT-REJw.js} +1 -1
- package/core/built/admin/assets/editor-Dp865O-4.js +8 -0
- package/core/built/admin/assets/{explore-BZAZOg5X.js → explore-ClUpJZOp.js} +1 -1
- package/core/built/admin/assets/{feed-CFV8xDw9.js → feed-DF92dUMP.js} +1 -1
- package/core/built/admin/assets/field-Do7lieBA.js +1 -0
- package/core/built/admin/assets/{filter-sources-Fx8wiYYw.js → filter-sources-BV2rnpfA.js} +1 -1
- package/core/built/admin/assets/filters-CUXJ2Nm9.js +1 -0
- package/core/built/admin/assets/{filters-CGX_pf2N.js → filters-DfbIWc_l.js} +1 -1
- package/core/built/admin/assets/{ghost-3063eae29e6c9cc6d6e7131928a27da0.css → ghost-a9c788f6f0b1ea6cf0f14ca4b13f4496.css} +1 -1
- package/core/built/admin/assets/{ghost-b1dce91ad3232cc259ee5fbbf9526243.js → ghost-c4057474943effc568c5659ccc4909d7.js} +407 -406
- package/core/built/admin/assets/{ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css → ghost-dark-db36d795d21c61426837df40af270966.css} +1 -1
- package/core/built/admin/assets/gift-link-modal-f9VIMNDv.js +1 -0
- package/core/built/admin/assets/{gift-links-nBxJjZiQ.js → gift-links-CsUhefWG.js} +1 -1
- package/core/built/admin/assets/growth-B3I6gNLm.js +1 -0
- package/core/built/admin/assets/{Growth-CSaHoSVD.js → growth-CVw1My4S.js} +2 -2
- package/core/built/admin/assets/{hooks-BApwwBE0.js → hooks-CixO01lL.js} +1 -1
- package/core/built/admin/assets/{inbox-BRp1_aaC.js → inbox-CFBSu4Ed.js} +12 -12
- package/core/built/admin/assets/index-9Cw8z3rA.css +1 -0
- package/core/built/admin/assets/index-BGG7NckO.js +67 -0
- package/core/built/admin/assets/input-group-BSgG_lVw.js +1 -0
- package/core/built/admin/assets/input-surface-BpAjZXY5.js +1 -0
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +974 -937
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +28 -28
- package/core/built/admin/assets/koenig-lexical/style.css +1 -1
- package/core/built/admin/assets/{koenig-lexical-CM7UFNdL.js → koenig-lexical-f8vHRYvz.js} +28 -28
- package/core/built/admin/assets/{kpi-card-BrGH6FsT.js → kpi-card-DSap9rAy.js} +1 -1
- package/core/built/admin/assets/{kpi-card-CIGyijjx.js → kpi-card-DU0rn9Cj.js} +1 -1
- package/core/built/admin/assets/{kpi-helpers-_HRRsklE.js → kpi-helpers-Dz33AV6h.js} +1 -1
- package/core/built/admin/assets/{kpi-tabs-BSvh9eoq.js → kpi-tabs-BtTTrKvJ.js} +1 -1
- package/core/built/admin/assets/{label-BOR9XdKl.js → label-DS8Mi6G5.js} +1 -1
- package/core/built/admin/assets/label-picker-1DvSuLA1.js +1 -0
- package/core/built/admin/assets/labels-CDSUt4J_.js +1 -0
- package/core/built/admin/assets/layout-yQEi2qDM.js +1 -0
- package/core/built/admin/assets/{link-helpers-tOlxmuH5.js → link-helpers-7EYqvvHs.js} +1 -1
- package/core/built/admin/assets/member-custom-fields-yOMHyAg9.js +1 -0
- package/core/built/admin/assets/member-detail-BAq7gDaa.js +1 -0
- package/core/built/admin/assets/members-CQpVFJu4.js +10 -0
- package/core/built/admin/assets/modals-ReORvWnu.js +31 -0
- package/core/built/admin/assets/moderation-DySbgyUS.js +1 -0
- package/core/built/admin/assets/newsletter-CJQvtHqN.js +1 -0
- package/core/built/admin/assets/{Newsletters-C5cs6FGo.js → newsletters-B3QQXfGT.js} +1 -1
- package/core/built/admin/assets/{newsletters-D1jbtV-h.js → newsletters-BXJbJgA-.js} +1 -1
- package/core/built/admin/assets/note-C8kxrz6w.js +1 -0
- package/core/built/admin/assets/notifications-CgtSfX7t.js +1 -0
- package/core/built/admin/assets/{offers-CrY6nSRR.js → offers-DEniVRD5.js} +1 -1
- package/core/built/admin/assets/onboarding-route-4qtziA9d.js +1 -0
- package/core/built/admin/assets/overview-Bf2sbznq.js +1 -0
- package/core/built/admin/assets/overview-CBfePxcr.js +1 -0
- package/core/built/admin/assets/{page-header-C0jVxtS8.js → page-header-B3Wb9Jqv.js} +1 -1
- package/core/built/admin/assets/{pages-BbNWFcGj.js → pages-B4goRPUn.js} +1 -1
- package/core/built/admin/assets/{post-analytics-Iw7dk1mT.js → post-analytics-We-ko5Cb.js} +1 -1
- package/core/built/admin/assets/post-analytics-header-Bmc9su6q.js +1 -0
- package/core/built/admin/assets/post-analytics-provider-B6UynTGb.js +1 -0
- package/core/built/admin/assets/{post-share-modal-DBfKl2GZ.js → post-share-modal-DFfO93_0.js} +1 -1
- package/core/built/admin/assets/{posts-EWpZIjkr.js → posts-DhXE7b6r.js} +1 -1
- package/core/built/admin/assets/{preferences-D4EANGoc.js → preferences-DJPfHEGu.js} +2 -2
- package/core/built/admin/assets/profile-DqBQp-gT.js +1 -0
- package/core/built/admin/assets/{referrers-BCfFYSHc.js → referrers-pmJT4k3-.js} +1 -1
- package/core/built/admin/assets/select-C5_xEt5b.js +1 -0
- package/core/built/admin/assets/settings-BwiVIXau.js +4 -0
- package/core/built/admin/assets/{settings-Bz3RZRmE.js → settings-WXNeWyU1.js} +1 -1
- package/core/built/admin/assets/shade-app-B3heOAfz-CGXQwWeO.js +3 -0
- package/core/built/admin/assets/{share-modal-CkdTTMJd.js → share-modal-DsgW3wbg.js} +1 -1
- package/core/built/admin/assets/social-urls-BQPFEk1_.js +8 -0
- package/core/built/admin/assets/{sort-button-DZp9Y2r1.js → sort-button-Bb_FCl7e.js} +1 -1
- package/core/built/admin/assets/{source-icon-CHr9qJ2Y.js → source-icon-BeaRxUn9.js} +1 -1
- package/core/built/admin/assets/{stats-DGoXZxWE.js → stats-Bjj_kmJ1.js} +1 -1
- package/core/built/admin/assets/{stats-view-D2-1L0ms.js → stats-view-BxPbW6K1.js} +1 -1
- package/core/built/admin/assets/{step-1-RdahbwyG.js → step-1-B1e3-1F8.js} +1 -1
- package/core/built/admin/assets/{step-2-D83PeRwd.js → step-2-C5WaeBJo.js} +1 -1
- package/core/built/admin/assets/{step-3-p_Op4wv4.js → step-3-B46iVPwu.js} +2 -2
- package/core/built/admin/assets/switch-z5Y6Uzt6.js +1 -0
- package/core/built/admin/assets/{table-B8LgTQJZ.js → table-CB-4_HBJ.js} +1 -1
- package/core/built/admin/assets/tabs-CCEgKYzq.js +1 -0
- package/core/built/admin/assets/{tags-B4l891z2.js → tags-Cg2VJGmG.js} +1 -1
- package/core/built/admin/assets/textarea-Bjccvh_E.js +1 -0
- package/core/built/admin/assets/{tiers-BgYLWRJv.js → tiers-DYsa4DCo.js} +1 -1
- package/core/built/admin/assets/{toggle-group-DNXDkAwf.js → toggle-group-b3IlxvhV.js} +1 -1
- package/core/built/admin/assets/{topic-filter-DZGjEcz3.js → topic-filter-DAFT87tQ.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data-CaT8RirX.js → use-analytics-data-S0FTd43s.js} +1 -1
- package/core/built/admin/assets/use-filter-params-Gpoq2E1L.js +1 -0
- package/core/built/admin/assets/{use-growth-stats-9Db2CuJe.js → use-growth-stats-CIaiHOVb.js} +1 -1
- package/core/built/admin/assets/{use-post-referrers-BV54YcQS.js → use-post-referrers-Cq2vBPrA.js} +1 -1
- package/core/built/admin/assets/{use-reply-chain-data-DuYZGDan.js → use-reply-chain-data-DBDRtGu-.js} +1 -1
- package/core/built/admin/assets/{use-simple-pagination-8fTua9Nt.js → use-simple-pagination-CjYNxdwe.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-query-Dz156HvZ.js → use-tinybird-query-falHAtuK.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-C9RUdL_n.js → use-tinybird-token-D7-8ND1y.js} +1 -1
- package/core/built/admin/assets/{users-CcSCQFcQ.js → users-Dkv8NQZe.js} +1 -1
- package/core/built/admin/assets/{virtual-list-BCvP0YF-.js → virtual-list-CvnC9zF2.js} +1 -1
- package/core/built/admin/assets/web-B_5GZRvH.js +1 -0
- package/core/built/admin/assets/web-jFYWCKDn.js +2 -0
- package/core/built/admin/index.html +14 -10
- package/core/frontend/services/proxy.js +10 -1
- package/core/frontend/services/routing/router-manager.js +14 -14
- package/core/frontend/services/routing/static-routes-router.js +8 -10
- package/core/server/adapters/storage/LocalFilesStorage.js +13 -11
- package/core/server/adapters/storage/LocalFilesStorage.ts +24 -0
- package/core/server/adapters/storage/LocalImagesStorage.js +14 -12
- package/core/server/adapters/storage/LocalImagesStorage.ts +24 -0
- package/core/server/adapters/storage/LocalMediaStorage.js +13 -11
- package/core/server/adapters/storage/LocalMediaStorage.ts +24 -0
- package/core/server/adapters/storage/LocalStorageBase.js +107 -167
- package/core/server/adapters/storage/LocalStorageBase.ts +342 -0
- package/core/server/adapters/storage/utils.js +36 -50
- package/core/server/adapters/storage/utils.ts +60 -0
- 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/db.js +6 -0
- package/core/server/api/endpoints/index.js +4 -0
- package/core/server/api/endpoints/members.js +25 -28
- package/core/server/api/endpoints/pages.js +6 -1
- package/core/server/api/endpoints/posts.js +11 -2
- package/core/server/api/endpoints/settings.js +0 -2
- package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +4 -1
- package/core/server/api/endpoints/utils/serializers/output/members.js +18 -87
- package/core/server/api/endpoints/utils/serializers/output/utils/url.js +11 -1
- package/core/server/data/exporter/export-filename.js +2 -1
- package/core/server/data/importer/importers/data/revue-subscriber-importer.js +6 -10
- package/core/server/data/importer/importers/json-to-html.js +24 -4
- package/core/server/data/migrations/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/schema/commands.js +5 -0
- package/core/server/data/schema/default-settings/default-settings.json +0 -4
- package/core/server/data/schema/schema.js +5 -1
- package/core/server/lib/image/image-size.js +3 -17
- package/core/server/lib/image/image-utils.js +15 -1
- package/core/server/lib/request-external.js +1 -1
- package/core/server/models/user.js +46 -70
- package/core/server/services/auth/session/session-service.js +28 -1
- package/core/server/services/automations/automations-api.js +21 -6
- package/core/server/services/automations/automations-api.ts +25 -6
- package/core/server/services/automations/automations-repository.ts +19 -0
- package/core/server/services/automations/database-automations-repository.js +116 -28
- package/core/server/services/automations/database-automations-repository.ts +118 -9
- 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/poll.js +5 -2
- package/core/server/services/automations/poll.ts +7 -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 +15 -3
- package/core/server/services/automations/service.ts +16 -3
- package/core/server/services/comments/comments-service-emails.js +14 -8
- 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/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 +30 -9
- package/core/server/services/link-tracking/link-click-tracking-service.js +44 -3
- package/core/server/services/member-attribution/outbound-link-tagger.js +3 -1
- package/core/server/services/member-welcome-emails/member-welcome-email-renderer.js +19 -4
- package/core/server/services/member-welcome-emails/service.js +11 -3
- package/core/server/services/members/{importer → import-export}/config.js +4 -9
- package/core/server/services/members/{importer → import-export}/config.ts +4 -9
- 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 +12 -0
- package/core/server/services/members/import-export/csv/index.ts +3 -0
- package/core/server/services/members/import-export/csv/parse.js +64 -0
- package/core/server/services/members/import-export/csv/parse.ts +69 -0
- package/core/server/services/members/import-export/csv/serialize.js +13 -0
- package/core/server/services/members/import-export/csv/serialize.ts +18 -0
- package/core/server/services/members/import-export/export/exporter.js +202 -0
- package/core/server/services/members/import-export/export/exporter.ts +325 -0
- package/core/server/services/members/import-export/import/completion-email.js +84 -0
- package/core/server/services/members/import-export/import/completion-email.ts +141 -0
- package/core/server/services/members/import-export/import/importer.js +297 -0
- package/core/server/services/members/import-export/import/importer.ts +468 -0
- package/core/server/services/members/import-export/import/reader.js +32 -0
- package/core/server/services/members/import-export/import/reader.ts +33 -0
- package/core/server/services/members/import-export/import/row.js +33 -0
- package/core/server/services/members/import-export/import/row.ts +52 -0
- package/core/server/services/members/import-export/import/spool.js +30 -0
- package/core/server/services/members/import-export/import/spool.ts +38 -0
- package/core/server/services/members/import-export/index.js +99 -0
- package/core/server/services/members/import-export/index.ts +137 -0
- package/core/server/services/members/members-api/controllers/router-controller.js +7 -0
- package/core/server/services/members/service.js +25 -20
- package/core/server/services/members-custom-fields/values-service.js +19 -7
- package/core/server/services/members-custom-fields/values-service.ts +19 -7
- package/core/server/services/mentions/service.js +5 -1
- package/core/server/services/posts/posts-exporter.js +6 -4
- package/core/server/services/posts/posts-service.js +2 -2
- package/core/server/services/route-settings/activation-bridge.js +59 -49
- package/core/server/services/route-settings/activation-bridge.ts +91 -51
- package/core/server/services/route-settings/dynamic-routing-service.js +22 -51
- package/core/server/services/route-settings/index.js +1 -16
- package/core/server/services/settings/settings-service.js +0 -18
- package/core/server/services/themes/storage.js +9 -0
- package/core/server/services/themes/theme-storage.js +1 -1
- 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/shared/config/defaults.json +2 -1
- package/core/shared/express.js +6 -1
- package/core/shared/labs.js +2 -1
- package/package.json +11 -11
- package/pnpm-lock.yaml +18 -18
- package/pnpm-workspace.yaml +8 -7
- package/components/tryghost-adapter-base-scheduling-0.1.1.tgz +0 -0
- package/core/built/admin/assets/Overview-j4NaeUNm.js +0 -1
- package/core/built/admin/assets/Web-_fD935OX.js +0 -2
- package/core/built/admin/assets/activitypub/layout-IdVq3lRy.js +0 -1
- package/core/built/admin/assets/audience-BKRdsFmy.js +0 -1
- package/core/built/admin/assets/checkbox-DA4-1UiI.js +0 -1
- package/core/built/admin/assets/chunk.524.45e0875f41b71e46e849.js +0 -25
- package/core/built/admin/assets/chunk.582.51defd4b009f0de8d4d5.js +0 -27
- package/core/built/admin/assets/code-editor-view-BKBrkffZ.js +0 -1
- package/core/built/admin/assets/comments-CzVNIT8b.js +0 -1
- package/core/built/admin/assets/constants-c-JNF9c2.js +0 -1
- package/core/built/admin/assets/dist-CT46_f_J.js +0 -1
- package/core/built/admin/assets/domain-B7_n5nfx.js +0 -1
- package/core/built/admin/assets/dropzone-DcuJEEUf.js +0 -5
- package/core/built/admin/assets/editor-BCiIyFjm.js +0 -8
- package/core/built/admin/assets/field-BW-M2Zwp.js +0 -1
- package/core/built/admin/assets/filters-DtcXMZDU.js +0 -1
- package/core/built/admin/assets/gift-link-modal-Bk8qpnMw.js +0 -1
- package/core/built/admin/assets/growth-Ck2s3JjR.js +0 -1
- package/core/built/admin/assets/index-BBf502Wg.js +0 -69
- package/core/built/admin/assets/index-BCCZKxP2.css +0 -1
- package/core/built/admin/assets/input-group-DjuYnNCd.js +0 -1
- package/core/built/admin/assets/label-picker-BdNAWuUX.js +0 -1
- package/core/built/admin/assets/labels-Cyayfd-e.js +0 -1
- package/core/built/admin/assets/layout-Bw4GnxXp.js +0 -1
- package/core/built/admin/assets/member-custom-fields-DvFyamLu.js +0 -1
- package/core/built/admin/assets/member-detail-Cg2vTqvJ.js +0 -1
- package/core/built/admin/assets/members-DsPxYAVm.js +0 -10
- package/core/built/admin/assets/modals-Bf_fyvHZ.js +0 -31
- package/core/built/admin/assets/moderation-Dlp7M5sa.js +0 -1
- package/core/built/admin/assets/multi-select-combobox-CH1o8XXQ.js +0 -1
- package/core/built/admin/assets/newsletter-CQ5CAYUI.js +0 -1
- package/core/built/admin/assets/note-BrAZ7Z0o.js +0 -1
- package/core/built/admin/assets/notifications-BnbHLOPC.js +0 -1
- package/core/built/admin/assets/onboarding-route-eU146kuA.js +0 -1
- package/core/built/admin/assets/overview-BpbaK-xu.js +0 -1
- package/core/built/admin/assets/post-analytics-header-D9pJ4iNm.js +0 -1
- package/core/built/admin/assets/post-analytics-provider-BDqcfBor.js +0 -1
- package/core/built/admin/assets/profile-dJ44Bn_W.js +0 -1
- package/core/built/admin/assets/select--2uVN9_-.js +0 -1
- package/core/built/admin/assets/settings-SD9bxIpt.js +0 -4
- package/core/built/admin/assets/social-urls-BvFZwYcE.js +0 -8
- package/core/built/admin/assets/switch-qp518gFQ.js +0 -1
- package/core/built/admin/assets/tabs-D3ZOYkM7.js +0 -1
- package/core/built/admin/assets/textarea-CTlb3Uu6.js +0 -1
- package/core/built/admin/assets/use-filter-params-DeQ8sX4N.js +0 -1
- package/core/built/admin/assets/web-DTZnnUGr.js +0 -1
- package/core/server/services/mail/templates/newsletter.html +0 -876
- package/core/server/services/members/csv/index.js +0 -10
- package/core/server/services/members/csv/index.ts +0 -3
- package/core/server/services/members/csv/parse.js +0 -94
- package/core/server/services/members/csv/parse.ts +0 -111
- package/core/server/services/members/csv/types.js +0 -2
- package/core/server/services/members/csv/types.ts +0 -39
- package/core/server/services/members/csv/unparse.js +0 -69
- package/core/server/services/members/csv/unparse.ts +0 -79
- package/core/server/services/members/exporter/query.js +0 -233
- package/core/server/services/members/importer/index.js +0 -30
- package/core/server/services/members/importer/labels.js +0 -125
- package/core/server/services/members/importer/members-csv-importer.js +0 -520
- 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
- /package/core/server/services/members/{importer → import-export/import}/email-template.js +0 -0
- /package/core/server/services/members/{importer/members-csv-importer-stripe-utils.js → import-export/import/stripe-utils.js} +0 -0
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.buildRouterSettings = buildRouterSettings;
|
|
7
7
|
const lodash_1 = __importDefault(require("lodash"));
|
|
8
8
|
const errors_1 = __importDefault(require("@tryghost/errors"));
|
|
9
9
|
const config_1 = require("../../../frontend/services/routing/config");
|
|
@@ -87,78 +87,88 @@ function expandRouteData(routeData) {
|
|
|
87
87
|
function convertSlugsToColons(value) {
|
|
88
88
|
return value.replace(/{(\w+)}/g, ':$1');
|
|
89
89
|
}
|
|
90
|
-
function
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
expanded.data = expandRouteData(route.data);
|
|
95
|
-
}
|
|
90
|
+
function buildRouterRoute(route) {
|
|
91
|
+
const data = route.data !== undefined ? expandRouteData(route.data) : undefined;
|
|
92
|
+
// Build per branch: RouterRoute is a discriminated union, so each member is
|
|
93
|
+
// constructed as its concrete type. `route` is narrowed by the check.
|
|
96
94
|
if (route.type === 'channel') {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
const result = {
|
|
96
|
+
path: route.path,
|
|
97
|
+
type: 'channel',
|
|
98
|
+
templates: route.templates || []
|
|
99
|
+
};
|
|
100
|
+
if (data !== undefined) {
|
|
101
|
+
result.data = data;
|
|
101
102
|
}
|
|
102
|
-
if (
|
|
103
|
-
|
|
103
|
+
if (route.filter !== undefined) {
|
|
104
|
+
result.filter = route.filter;
|
|
104
105
|
}
|
|
105
|
-
if (
|
|
106
|
-
|
|
106
|
+
if (route.order !== undefined) {
|
|
107
|
+
result.order = route.order;
|
|
107
108
|
}
|
|
108
|
-
if (
|
|
109
|
-
|
|
109
|
+
if (route.limit !== undefined) {
|
|
110
|
+
result.limit = route.limit;
|
|
110
111
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const template = route;
|
|
114
|
-
if (template.contentType !== undefined) {
|
|
115
|
-
expanded.content_type = template.contentType;
|
|
112
|
+
if (route.rss !== undefined) {
|
|
113
|
+
result.rss = route.rss;
|
|
116
114
|
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
const result = {
|
|
118
|
+
path: route.path,
|
|
119
|
+
type: 'template',
|
|
120
|
+
templates: route.templates || []
|
|
121
|
+
};
|
|
122
|
+
if (data !== undefined) {
|
|
123
|
+
result.data = data;
|
|
117
124
|
}
|
|
118
|
-
|
|
125
|
+
if (route.contentType !== undefined) {
|
|
126
|
+
result.contentType = route.contentType;
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
119
129
|
}
|
|
120
|
-
function
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
130
|
+
function buildRouterCollection(collection) {
|
|
131
|
+
const result = {
|
|
132
|
+
path: collection.path,
|
|
133
|
+
permalink: convertSlugsToColons(collection.permalink),
|
|
134
|
+
templates: collection.templates || []
|
|
135
|
+
};
|
|
124
136
|
if (collection.data !== undefined) {
|
|
125
|
-
|
|
137
|
+
result.data = expandRouteData(collection.data);
|
|
126
138
|
}
|
|
127
139
|
if (collection.filter !== undefined) {
|
|
128
|
-
|
|
140
|
+
result.filter = collection.filter;
|
|
129
141
|
}
|
|
130
142
|
if (collection.order !== undefined) {
|
|
131
|
-
|
|
143
|
+
result.order = collection.order;
|
|
132
144
|
}
|
|
133
145
|
if (collection.limit !== undefined) {
|
|
134
|
-
|
|
146
|
+
result.limit = collection.limit;
|
|
135
147
|
}
|
|
136
148
|
if (collection.rss !== undefined) {
|
|
137
|
-
|
|
149
|
+
result.rss = collection.rss;
|
|
138
150
|
}
|
|
139
|
-
return
|
|
151
|
+
return result;
|
|
140
152
|
}
|
|
141
153
|
/**
|
|
142
|
-
* Converts a RouteSettings domain model into the
|
|
143
|
-
*
|
|
154
|
+
* Converts a RouteSettings domain model into the array shape that
|
|
155
|
+
* RouterManager.start() iterates. Each route/collection carries its own `path`,
|
|
156
|
+
* and taxonomies become `{key, permalink}` entries, so the routing layer no
|
|
157
|
+
* longer reads paths from map keys.
|
|
144
158
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
159
|
+
* Temporary adapter: removed in HKG-1898 once the routers consume the domain
|
|
160
|
+
* model directly.
|
|
147
161
|
*/
|
|
148
|
-
function
|
|
149
|
-
const
|
|
150
|
-
for (const route of settings.routes) {
|
|
151
|
-
routes[route.path] = expandRoute(route);
|
|
152
|
-
}
|
|
153
|
-
const collections = {};
|
|
154
|
-
for (const collection of settings.collections) {
|
|
155
|
-
collections[collection.path] = expandCollection(collection);
|
|
156
|
-
}
|
|
157
|
-
const taxonomies = {};
|
|
162
|
+
function buildRouterSettings(settings) {
|
|
163
|
+
const taxonomies = [];
|
|
158
164
|
for (const [key, value] of Object.entries(settings.taxonomies)) {
|
|
159
165
|
if (value) {
|
|
160
|
-
taxonomies
|
|
166
|
+
taxonomies.push({ key, permalink: convertSlugsToColons(value) });
|
|
161
167
|
}
|
|
162
168
|
}
|
|
163
|
-
return {
|
|
169
|
+
return {
|
|
170
|
+
routes: settings.routes.map(buildRouterRoute),
|
|
171
|
+
collections: settings.collections.map(buildRouterCollection),
|
|
172
|
+
taxonomies
|
|
173
|
+
};
|
|
164
174
|
}
|
|
@@ -121,90 +121,130 @@ function convertSlugsToColons(value: string): string {
|
|
|
121
121
|
return value.replace(/{(\w+)}/g, ':$1');
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Router-facing shapes. RouterManager consumes the domain model after the two
|
|
126
|
+
* conversions the bridge still applies: `data` expanded to `{query, router}`,
|
|
127
|
+
* and collection/taxonomy permalinks rewritten to `:slug`.
|
|
128
|
+
*
|
|
129
|
+
* Routes and collections are written as their domain counterpart with just
|
|
130
|
+
* `data` overridden to the expanded shape — `Omit<…, 'data'> & {data?}` rather
|
|
131
|
+
* than `extends`, because the override changes `data`'s type (interface
|
|
132
|
+
* extension can only add fields, not retype them). That keeps the delta from
|
|
133
|
+
* the domain model explicit: `data` is the only structural difference. When the
|
|
134
|
+
* bridge is removed (HKG-1898) the override falls away and these collapse back
|
|
135
|
+
* to `Route` / `CollectionConfig`.
|
|
136
|
+
*/
|
|
137
|
+
type RouterChannelRoute = Omit<ChannelRoute, 'data'> & {data?: ExpandedData};
|
|
138
|
+
type RouterTemplateRoute = Omit<TemplateRoute, 'data'> & {data?: ExpandedData};
|
|
139
|
+
type RouterRoute = RouterChannelRoute | RouterTemplateRoute;
|
|
140
|
+
|
|
141
|
+
type RouterCollection = Omit<CollectionConfig, 'data'> & {data?: ExpandedData};
|
|
142
|
+
|
|
143
|
+
// Taxonomies and RouteSettings have no direct domain counterpart to derive from:
|
|
144
|
+
// the domain stores taxonomies as a `{tag, author}` map, which the bridge
|
|
145
|
+
// flattens into these `{key, permalink}` entries, and RouterSettings drops
|
|
146
|
+
// `yamlSource` and swaps all three array element types (routes, collections,
|
|
147
|
+
// taxonomies) — so they stay standalone.
|
|
148
|
+
interface RouterTaxonomy {
|
|
149
|
+
key: string;
|
|
150
|
+
permalink: string;
|
|
151
|
+
}
|
|
126
152
|
|
|
127
|
-
|
|
153
|
+
export interface RouterSettings {
|
|
154
|
+
routes: RouterRoute[];
|
|
155
|
+
collections: RouterCollection[];
|
|
156
|
+
taxonomies: RouterTaxonomy[];
|
|
157
|
+
}
|
|
128
158
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
159
|
+
function buildRouterRoute(route: Route): RouterRoute {
|
|
160
|
+
const data = route.data !== undefined ? expandRouteData(route.data) : undefined;
|
|
132
161
|
|
|
162
|
+
// Build per branch: RouterRoute is a discriminated union, so each member is
|
|
163
|
+
// constructed as its concrete type. `route` is narrowed by the check.
|
|
133
164
|
if (route.type === 'channel') {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
165
|
+
const result: RouterChannelRoute = {
|
|
166
|
+
path: route.path,
|
|
167
|
+
type: 'channel',
|
|
168
|
+
templates: route.templates || []
|
|
169
|
+
};
|
|
170
|
+
if (data !== undefined) {
|
|
171
|
+
result.data = data;
|
|
138
172
|
}
|
|
139
|
-
if (
|
|
140
|
-
|
|
173
|
+
if (route.filter !== undefined) {
|
|
174
|
+
result.filter = route.filter;
|
|
141
175
|
}
|
|
142
|
-
if (
|
|
143
|
-
|
|
176
|
+
if (route.order !== undefined) {
|
|
177
|
+
result.order = route.order;
|
|
144
178
|
}
|
|
145
|
-
if (
|
|
146
|
-
|
|
179
|
+
if (route.limit !== undefined) {
|
|
180
|
+
result.limit = route.limit;
|
|
147
181
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (template.contentType !== undefined) {
|
|
151
|
-
expanded.content_type = template.contentType;
|
|
182
|
+
if (route.rss !== undefined) {
|
|
183
|
+
result.rss = route.rss;
|
|
152
184
|
}
|
|
185
|
+
return result;
|
|
153
186
|
}
|
|
154
187
|
|
|
155
|
-
|
|
188
|
+
const result: RouterTemplateRoute = {
|
|
189
|
+
path: route.path,
|
|
190
|
+
type: 'template',
|
|
191
|
+
templates: route.templates || []
|
|
192
|
+
};
|
|
193
|
+
if (data !== undefined) {
|
|
194
|
+
result.data = data;
|
|
195
|
+
}
|
|
196
|
+
if (route.contentType !== undefined) {
|
|
197
|
+
result.contentType = route.contentType;
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
156
200
|
}
|
|
157
201
|
|
|
158
|
-
function
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
202
|
+
function buildRouterCollection(collection: CollectionConfig): RouterCollection {
|
|
203
|
+
const result: RouterCollection = {
|
|
204
|
+
path: collection.path,
|
|
205
|
+
permalink: convertSlugsToColons(collection.permalink),
|
|
206
|
+
templates: collection.templates || []
|
|
207
|
+
};
|
|
163
208
|
|
|
164
209
|
if (collection.data !== undefined) {
|
|
165
|
-
|
|
210
|
+
result.data = expandRouteData(collection.data);
|
|
166
211
|
}
|
|
167
|
-
|
|
168
212
|
if (collection.filter !== undefined) {
|
|
169
|
-
|
|
213
|
+
result.filter = collection.filter;
|
|
170
214
|
}
|
|
171
215
|
if (collection.order !== undefined) {
|
|
172
|
-
|
|
216
|
+
result.order = collection.order;
|
|
173
217
|
}
|
|
174
218
|
if (collection.limit !== undefined) {
|
|
175
|
-
|
|
219
|
+
result.limit = collection.limit;
|
|
176
220
|
}
|
|
177
221
|
if (collection.rss !== undefined) {
|
|
178
|
-
|
|
222
|
+
result.rss = collection.rss;
|
|
179
223
|
}
|
|
180
224
|
|
|
181
|
-
return
|
|
225
|
+
return result;
|
|
182
226
|
}
|
|
183
227
|
|
|
184
228
|
/**
|
|
185
|
-
* Converts a RouteSettings domain model into the
|
|
186
|
-
*
|
|
229
|
+
* Converts a RouteSettings domain model into the array shape that
|
|
230
|
+
* RouterManager.start() iterates. Each route/collection carries its own `path`,
|
|
231
|
+
* and taxonomies become `{key, permalink}` entries, so the routing layer no
|
|
232
|
+
* longer reads paths from map keys.
|
|
187
233
|
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
234
|
+
* Temporary adapter: removed in HKG-1898 once the routers consume the domain
|
|
235
|
+
* model directly.
|
|
190
236
|
*/
|
|
191
|
-
export function
|
|
192
|
-
const
|
|
193
|
-
for (const route of settings.routes) {
|
|
194
|
-
routes[route.path] = expandRoute(route);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const collections: Record<string, any> = {};
|
|
198
|
-
for (const collection of settings.collections) {
|
|
199
|
-
collections[collection.path] = expandCollection(collection);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const taxonomies: Record<string, string> = {};
|
|
237
|
+
export function buildRouterSettings(settings: RouteSettings): RouterSettings {
|
|
238
|
+
const taxonomies: RouterTaxonomy[] = [];
|
|
203
239
|
for (const [key, value] of Object.entries(settings.taxonomies)) {
|
|
204
240
|
if (value) {
|
|
205
|
-
taxonomies
|
|
241
|
+
taxonomies.push({key, permalink: convertSlugsToColons(value)});
|
|
206
242
|
}
|
|
207
243
|
}
|
|
208
244
|
|
|
209
|
-
return {
|
|
245
|
+
return {
|
|
246
|
+
routes: settings.routes.map(buildRouterRoute),
|
|
247
|
+
collections: settings.collections.map(buildRouterCollection),
|
|
248
|
+
taxonomies
|
|
249
|
+
};
|
|
210
250
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const crypto = require('crypto');
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
1
|
const debug = require('@tryghost/debug')('services:route-settings:service');
|
|
4
2
|
const logging = require('@tryghost/logging');
|
|
5
3
|
const errors = require('@tryghost/errors');
|
|
@@ -9,12 +7,6 @@ const messages = {
|
|
|
9
7
|
loadError: 'Could not load routes.yaml file.'
|
|
10
8
|
};
|
|
11
9
|
|
|
12
|
-
/**
|
|
13
|
-
* md5 of the expanded default route settings — the routes_hash value for a
|
|
14
|
-
* site that has never customised its routes.
|
|
15
|
-
*/
|
|
16
|
-
const DEFAULT_ROUTES_SETTING_HASH = '3d180d52c663d173a6be791ef411ed01';
|
|
17
|
-
|
|
18
10
|
function isStoredContentError(err) {
|
|
19
11
|
return err.errorType === 'ValidationError' || err.errorType === 'IncorrectUsageError';
|
|
20
12
|
}
|
|
@@ -27,26 +19,21 @@ class DynamicRoutingService {
|
|
|
27
19
|
constructor() {
|
|
28
20
|
/** @type {RouteSettingsStore} */
|
|
29
21
|
this.store = null;
|
|
30
|
-
this.settingsLoader = null;
|
|
31
22
|
this.routerManager = null;
|
|
32
23
|
this.urlService = null;
|
|
33
24
|
}
|
|
34
25
|
|
|
35
26
|
/**
|
|
36
|
-
* Wire the storage-layer
|
|
37
|
-
*
|
|
38
|
-
*
|
|
27
|
+
* Wire the storage-layer dependency so the API surface (upload, download)
|
|
28
|
+
* works immediately after boot — even when the frontend is disabled and
|
|
29
|
+
* `start()` is never called.
|
|
39
30
|
*
|
|
40
31
|
* @param {object} deps
|
|
41
32
|
* @param {RouteSettingsStore} deps.store - adapter-manager provided store
|
|
42
|
-
* @param {object} [deps.settingsLoader] - legacy SettingsLoader used as a
|
|
43
|
-
* read-path fallback when the stricter store parser rejects a file
|
|
44
|
-
* (see loadRouteSettings)
|
|
45
33
|
*/
|
|
46
|
-
configure({store
|
|
34
|
+
configure({store}) {
|
|
47
35
|
debug('configure');
|
|
48
36
|
this.store = store;
|
|
49
|
-
this.settingsLoader = settingsLoader;
|
|
50
37
|
}
|
|
51
38
|
|
|
52
39
|
/**
|
|
@@ -67,49 +54,33 @@ class DynamicRoutingService {
|
|
|
67
54
|
}
|
|
68
55
|
|
|
69
56
|
async loadRouteSettings() {
|
|
70
|
-
const {
|
|
57
|
+
const {buildRouterSettings} = require('./activation-bridge');
|
|
71
58
|
|
|
72
59
|
try {
|
|
73
|
-
return
|
|
60
|
+
return buildRouterSettings(await this.store.get());
|
|
74
61
|
} catch (err) {
|
|
75
|
-
|
|
76
|
-
|
|
62
|
+
// A stored-content error means the site's routes.yaml is invalid —
|
|
63
|
+
// either it fails validation or it isn't parseable YAML. Log a
|
|
64
|
+
// targeted error so the failure is easy to spot in the logs, then
|
|
65
|
+
// rethrow so the caller surfaces the genuine error rather than
|
|
66
|
+
// silently degrading.
|
|
67
|
+
if (isStoredContentError(err)) {
|
|
68
|
+
logging.error(new errors.InternalServerError({
|
|
69
|
+
message: 'Route settings could not be loaded because the routes.yaml file is invalid. Please fix the file.',
|
|
70
|
+
code: 'ROUTE_SETTINGS_VALIDATION_ERROR',
|
|
71
|
+
err,
|
|
72
|
+
errorDetails: {reason: err.message}
|
|
73
|
+
}));
|
|
77
74
|
}
|
|
78
|
-
logging.error(new errors.InternalServerError({
|
|
79
|
-
message: 'Route settings failed the stricter validation and were loaded with the legacy validator instead. Please review the routes.yaml file.',
|
|
80
|
-
code: 'ROUTE_SETTINGS_VALIDATION_FALLBACK',
|
|
81
|
-
err,
|
|
82
|
-
errorDetails: {reason: err.message}
|
|
83
|
-
}));
|
|
84
|
-
|
|
85
|
-
return this.settingsLoader.loadSettings();
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
getDefaultHash() {
|
|
90
|
-
return DEFAULT_ROUTES_SETTING_HASH;
|
|
91
|
-
}
|
|
92
75
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return crypto.createHash('md5')
|
|
97
|
-
.update(JSON.stringify(expanded), 'binary')
|
|
98
|
-
.digest('hex');
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
99
78
|
}
|
|
100
79
|
|
|
101
80
|
async download() {
|
|
102
|
-
|
|
103
|
-
const settings = await this.store.get();
|
|
104
|
-
|
|
105
|
-
return settings.yamlSource;
|
|
106
|
-
} catch (err) {
|
|
107
|
-
if (!this.settingsLoader || !isStoredContentError(err)) {
|
|
108
|
-
throw err;
|
|
109
|
-
}
|
|
81
|
+
const settings = await this.store.get();
|
|
110
82
|
|
|
111
|
-
|
|
112
|
-
}
|
|
83
|
+
return settings.yamlSource;
|
|
113
84
|
}
|
|
114
85
|
|
|
115
86
|
async upload(yamlContent) {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const config = require('../../../shared/config');
|
|
2
|
-
const parseYaml = require('./yaml-parser');
|
|
3
1
|
const DynamicRoutingService = require('./dynamic-routing-service');
|
|
4
2
|
|
|
5
3
|
const service = new DynamicRoutingService();
|
|
@@ -7,15 +5,9 @@ const service = new DynamicRoutingService();
|
|
|
7
5
|
module.exports = {
|
|
8
6
|
init: async () => {
|
|
9
7
|
const adapterManager = require('../adapter-manager').default;
|
|
10
|
-
const SettingsLoader = require('./settings-loader');
|
|
11
|
-
const SettingsPathManager = require('./settings-path-manager');
|
|
12
|
-
|
|
13
|
-
const settingsPathManager = new SettingsPathManager({type: 'routes', paths: [config.getContentPath('settings')]});
|
|
14
|
-
const settingsLoader = new SettingsLoader({parseYaml, settingFilePath: settingsPathManager.getDefaultFilePath()});
|
|
15
8
|
|
|
16
9
|
service.configure({
|
|
17
|
-
store: adapterManager.getAdapter('route-settings')
|
|
18
|
-
settingsLoader
|
|
10
|
+
store: adapterManager.getAdapter('route-settings')
|
|
19
11
|
});
|
|
20
12
|
},
|
|
21
13
|
|
|
@@ -27,10 +19,6 @@ module.exports = {
|
|
|
27
19
|
return service.loadRouteSettings.bind(service);
|
|
28
20
|
},
|
|
29
21
|
|
|
30
|
-
get getDefaultHash() {
|
|
31
|
-
return service.getDefaultHash.bind(service);
|
|
32
|
-
},
|
|
33
|
-
|
|
34
22
|
/**
|
|
35
23
|
* Methods backing the Admin API settings endpoint — delegate to the
|
|
36
24
|
* service instance so the endpoint stays decoupled from service wiring.
|
|
@@ -41,9 +29,6 @@ module.exports = {
|
|
|
41
29
|
},
|
|
42
30
|
get download() {
|
|
43
31
|
return service.download.bind(service);
|
|
44
|
-
},
|
|
45
|
-
get getCurrentHash() {
|
|
46
|
-
return service.getCurrentHash.bind(service);
|
|
47
32
|
}
|
|
48
33
|
}
|
|
49
34
|
};
|
|
@@ -183,24 +183,6 @@ module.exports = {
|
|
|
183
183
|
return fields;
|
|
184
184
|
},
|
|
185
185
|
|
|
186
|
-
/**
|
|
187
|
-
* Handles synchronization of routes.yaml hash loaded in the frontend with
|
|
188
|
-
* the value stored in the settings table.
|
|
189
|
-
* getRoutesHash is a function to allow keeping "frontend" decoupled from settings
|
|
190
|
-
*
|
|
191
|
-
* @param {function} getRoutesHash function fetching currently loaded routes file hash
|
|
192
|
-
*/
|
|
193
|
-
async syncRoutesHash(getRoutesHash) {
|
|
194
|
-
const currentRoutesHash = await getRoutesHash();
|
|
195
|
-
|
|
196
|
-
if (SettingsCache.get('routes_hash') !== currentRoutesHash) {
|
|
197
|
-
return await models.Settings.edit([{
|
|
198
|
-
key: 'routes_hash',
|
|
199
|
-
value: currentRoutesHash
|
|
200
|
-
}], {context: {internal: true}});
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
|
|
204
186
|
/**
|
|
205
187
|
* Handles email setting synchronization when email has been verified per instance
|
|
206
188
|
*
|
|
@@ -27,6 +27,8 @@ const messages = {
|
|
|
27
27
|
destroyActive: 'Deleting the active theme is not allowed.'
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
const INVALID_THEME_REGEX = /^[./]*$/;
|
|
31
|
+
|
|
30
32
|
let themeStorage;
|
|
31
33
|
|
|
32
34
|
const getStorage = () => {
|
|
@@ -60,6 +62,13 @@ module.exports = {
|
|
|
60
62
|
});
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
// Reject theme names that only contain path elements.
|
|
66
|
+
if (INVALID_THEME_REGEX.test(themeName)) {
|
|
67
|
+
throw new errors.ValidationError({
|
|
68
|
+
message: 'Invalid theme name.'
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
63
72
|
let checkedTheme;
|
|
64
73
|
let overrideTheme;
|
|
65
74
|
let renamedExisting = false;
|
|
@@ -4,7 +4,7 @@ const path = require('path');
|
|
|
4
4
|
const config = require('../../../shared/config');
|
|
5
5
|
const security = require('@tryghost/security');
|
|
6
6
|
const {compress} = require('@tryghost/zip');
|
|
7
|
-
const LocalStorageBase = require('../../adapters/storage/LocalStorageBase');
|
|
7
|
+
const LocalStorageBase = require('../../adapters/storage/LocalStorageBase').default;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @TODO: combine with loader.js?
|
|
@@ -49,7 +49,7 @@ class UrlServiceFacade {
|
|
|
49
49
|
}
|
|
50
50
|
const url = this.urlService.getUrlByResourceId(resource.id, options);
|
|
51
51
|
if (this.isComparing() && !options?.skipComparison) {
|
|
52
|
-
const context = this._compareContext(resource);
|
|
52
|
+
const context = this._compareContext(resource, options?.serializerContext ? { serializer: options.serializerContext } : {});
|
|
53
53
|
// Snapshot: callers mutate the resource's nested objects in place
|
|
54
54
|
// after this returns, but the comparison runs later via setImmediate.
|
|
55
55
|
const snapshot = _.cloneDeep(resource);
|
|
@@ -43,6 +43,12 @@ export interface UrlOptions {
|
|
|
43
43
|
// rows per rebuild would only capture stacks and recompute for nothing.
|
|
44
44
|
// Dies with compare mode.
|
|
45
45
|
skipComparison?: boolean;
|
|
46
|
+
// Diagnostic only: the producing api endpoint (docName/method/apiType),
|
|
47
|
+
// threaded from the output serializer so a compare mismatch or thin-resource
|
|
48
|
+
// throw names its producer in the logs. The compare-log caller stack
|
|
49
|
+
// truncates at the async api-framework boundary, so the stack alone can't.
|
|
50
|
+
// Ignored by both backends; only read into the compare context.
|
|
51
|
+
serializerContext?: {apiType?: string; docName?: string; method?: string};
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/**
|
|
@@ -138,7 +144,8 @@ export class UrlServiceFacade {
|
|
|
138
144
|
}
|
|
139
145
|
const url = this.urlService.getUrlByResourceId(resource.id, options);
|
|
140
146
|
if (this.isComparing() && !options?.skipComparison) {
|
|
141
|
-
const context = this._compareContext(resource
|
|
147
|
+
const context = this._compareContext(resource,
|
|
148
|
+
options?.serializerContext ? {serializer: options.serializerContext} : {});
|
|
142
149
|
// Snapshot: callers mutate the resource's nested objects in place
|
|
143
150
|
// after this returns, but the comparison runs later via setImmediate.
|
|
144
151
|
const snapshot = _.cloneDeep(resource);
|
|
@@ -208,6 +208,7 @@ module.exports = function apiRoutes() {
|
|
|
208
208
|
|
|
209
209
|
// ## Automations
|
|
210
210
|
router.get('/automations', mw.authAdminApi, http(api.automations.browse));
|
|
211
|
+
router.get('/automations/:automation_id/actions/:action_id/links', mw.authAdminApi, http(api.automationActionLinks.browse));
|
|
211
212
|
router.get('/automations/:id', mw.authAdminApi, http(api.automations.read));
|
|
212
213
|
router.post('/automations/:id/email_preview', mw.authAdminApi, http(api.automationEmailPreviews.preview));
|
|
213
214
|
router.post('/automations/:id/email_test', shared.middleware.brute.previewEmailLimiter, mw.authAdminApi, http(api.automationEmailPreviews.sendTestEmail));
|
package/core/shared/express.js
CHANGED
|
@@ -2,6 +2,7 @@ const debug = require('@tryghost/debug')('shared:express');
|
|
|
2
2
|
const express = require('express');
|
|
3
3
|
const {createLazyRouter} = require('express-lazy-router');
|
|
4
4
|
const sentry = require('./sentry');
|
|
5
|
+
const config = require('../../core/shared/config');
|
|
5
6
|
|
|
6
7
|
const lazyLoad = createLazyRouter();
|
|
7
8
|
|
|
@@ -17,7 +18,11 @@ module.exports = (name) => {
|
|
|
17
18
|
|
|
18
19
|
// Make sure 'req.secure' is valid for proxied requests
|
|
19
20
|
// (X-Forwarded-Proto header will be checked, if present)
|
|
20
|
-
|
|
21
|
+
if (config.get('usingLoopbackReverseProxy')) {
|
|
22
|
+
app.set('trust proxy', 'loopback');
|
|
23
|
+
} else {
|
|
24
|
+
app.enable('trust proxy');
|
|
25
|
+
}
|
|
21
26
|
|
|
22
27
|
// Sentry must be our first error handler. Mounting it here means all custom error handlers will come after
|
|
23
28
|
app.use(sentry.errorHandler);
|
package/core/shared/labs.js
CHANGED