ghost 6.63.0 → 6.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/lib/duplicate-deps.js +204 -0
- package/bin/validate-adapters.js +50 -6
- package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
- package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
- package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
- package/components/tryghost-api-framework-0.0.0.tgz +0 -0
- package/components/tryghost-i18n-0.0.0.tgz +0 -0
- package/components/{tryghost-kg-default-cards-10.3.5.tgz → tryghost-kg-default-cards-10.3.6.tgz} +0 -0
- package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
- package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
- package/components/tryghost-kg-lexical-html-renderer-1.5.1.tgz +0 -0
- package/components/tryghost-limit-service-0.0.0.tgz +0 -0
- package/components/tryghost-metafield-types-0.0.0.tgz +0 -0
- package/content/themes/source/assets/built/screen.css +1 -1
- package/content/themes/source/assets/css/screen.css +1 -1
- package/content/themes/source/package.json +7 -7
- package/core/boot.js +10 -4
- package/core/built/admin/assets/Combination-DWfJPcz9.js +41 -0
- package/core/built/admin/assets/{PolarAngleAxis-pkMyqz8g.js → PolarAngleAxis-a81ieQUO.js} +2 -2
- package/core/built/admin/assets/RadialBarChart-CHRBhiBN.js +1 -0
- package/core/built/admin/assets/_baseAssignValue-DcPokYW8.js +1 -0
- package/core/built/admin/assets/about-39CAfroa.js +1 -0
- package/core/built/admin/assets/accordion-CJmRaqK7.js +1 -0
- package/core/built/admin/assets/account-migration-DYf7skbb.js +1 -0
- package/core/built/admin/assets/action-list-Crnh-_UI.js +1 -0
- package/core/built/admin/assets/add-integration-modal-B12oRifD.js +1 -0
- package/core/built/admin/assets/add-newsletter-modal-CTvXiIqY.js +1 -0
- package/core/built/admin/assets/add-recommendation-modal-CJf92edY.js +1 -0
- package/core/built/admin/assets/analytics-PHR1Fggi.js +1 -0
- package/core/built/admin/assets/announcement-bar-modal-Bql0CXdp.js +1 -0
- package/core/built/admin/assets/api-keys-CubH-7_H.js +1 -0
- package/core/built/admin/assets/{api-keys-BGPzLHzA.js → api-keys-omLA6iYn.js} +1 -1
- package/core/built/admin/assets/{audience-ceV3XVHq.js → audience-6GXevic-.js} +1 -1
- package/core/built/admin/assets/automated-emails-DJQ4uNZo.js +1 -0
- package/core/built/admin/assets/automations-DcZSLFDU.js +1 -0
- package/core/built/admin/assets/automations-hDVcRPjh.js +1 -0
- package/core/built/admin/assets/avatar-flipboard-DiAGgshK.js +1 -0
- package/core/built/admin/assets/badge-qP06OT7C.js +1 -0
- package/core/built/admin/assets/bluesky-sharing-CJw4d4Mf.js +1 -0
- package/core/built/admin/assets/box-CZ_LSVSy.js +1 -0
- package/core/built/admin/assets/brand-icon-D3ffDYaC.js +1 -0
- package/core/built/admin/assets/breadcrumb-Chn1Ip_q.js +1 -0
- package/core/built/admin/assets/button-DvIh2Bq-.js +1 -0
- package/core/built/admin/assets/calendar-1QGoStFM.js +1 -0
- package/core/built/admin/assets/card-FHQ4D10L.js +1 -0
- package/core/built/admin/assets/chart-helpers-CNpA7re_.js +1 -0
- package/core/built/admin/assets/{chart-BrhA41Zi.js → chart-jVz9Nf9t.js} +9 -9
- package/core/built/admin/assets/checkbox-DKht9xMl.js +1 -0
- package/core/built/admin/assets/{chunk-KS7C4IRE-DCsL4i4D.js → chunk-KS7C4IRE-DhOcHQOU.js} +1 -1
- package/core/built/admin/assets/{chunk.254.035b85ec456ebbd7336b.js → chunk.368.22ce1b732c0b40abd3f1.js} +159 -120
- package/core/built/admin/assets/chunk.524.cc9be98e44890cedc8c8.js +25 -0
- package/core/built/admin/assets/{chunk.582.98b485f9b2802f540897.js → chunk.582.e6fe742b3217207b11a6.js} +23 -30
- package/core/built/admin/assets/{chunk.901.4ccc639821020230bcca.js → chunk.972.4b8c97f93d66db15e751.js} +10625 -10088
- package/core/built/admin/assets/clean-tracked-url-dkN05vOf.js +1 -0
- package/core/built/admin/assets/code-editor-view-BLQIV85-.js +1 -0
- package/core/built/admin/assets/code-editor-view-Cg5eJxcr.js +1 -0
- package/core/built/admin/assets/color-picker-DQoghc0t.js +3 -0
- package/core/built/admin/assets/color-picker-field-BbeK5RRs.js +1 -0
- package/core/built/admin/assets/combobox-weO4FBbv.js +1 -0
- package/core/built/admin/assets/command-DlLrCm9V.js +1 -0
- package/core/built/admin/assets/comments-BjTitLmP.js +1 -0
- package/core/built/admin/assets/components-CwL6a6As-CCRaoCeP.js +1 -0
- package/core/built/admin/assets/{config-kSHvwdTG.js → config-BPljH6wF.js} +1 -1
- package/core/built/admin/assets/confirmation-context-IyqoXVk-.js +1 -0
- package/core/built/admin/assets/container-DAimjOF_.js +1 -0
- package/core/built/admin/assets/content-api-modal-0ZjuLcQ8.js +1 -0
- package/core/built/admin/assets/context-menu-BtioYFrg.js +1 -0
- package/core/built/admin/assets/copy-field-C6ujqJlP.js +1 -0
- package/core/built/admin/assets/create-ghost-browse-value-source-DAZMWZNq.js +1 -0
- package/core/built/admin/assets/custom-integration-modal-Dm8QI_J4.js +1 -0
- package/core/built/admin/assets/data-list-C0CKkeWW.js +1 -0
- package/core/built/admin/assets/date-range-select-DrjHQdgz.js +1 -0
- package/core/built/admin/assets/design-and-theme-modal-CXVOzBWu.js +2 -0
- package/core/built/admin/assets/detail-page-QpLIL-EO.js +1 -0
- package/core/built/admin/assets/dirty-confirm-dialog-DWwxREGh.js +1 -0
- package/core/built/admin/assets/disabled-sources-indicator-CLZhMv8J.js +1 -0
- package/core/built/admin/assets/dist-BRQkNYN1.js +11 -0
- package/core/built/admin/assets/{dist-B3keLvjj.js → dist-BXHrDV19.js} +2 -2
- package/core/built/admin/assets/dist-Bf-HQtVL.js +1 -0
- package/core/built/admin/assets/dist-Bm-PB47a.js +6 -0
- package/core/built/admin/assets/{dist-B6bJuxL3.js → dist-C2lYC76d.js} +1 -1
- package/core/built/admin/assets/dist-CUwte9v_.js +1 -0
- package/core/built/admin/assets/dist-Cm2qbZKL.js +1 -0
- package/core/built/admin/assets/{dist-BtaTA7Ii.js → dist-D7yMk931.js} +1 -1
- package/core/built/admin/assets/{dist-zwwGt8Yf.js → dist-DNAdeRyr.js} +1 -1
- package/core/built/admin/assets/dist-DS6zpxid.js +1 -0
- package/core/built/admin/assets/dist-DVVKsyPh.js +23 -0
- package/core/built/admin/assets/dist-DxfQlAmn.js +1 -0
- package/core/built/admin/assets/dist-DziNzWI2.js +1 -0
- package/core/built/admin/assets/dist-FEQQAwTe.js +1 -0
- package/core/built/admin/assets/dist-nmRzULcD.js +1 -0
- package/core/built/admin/assets/domain-DBrBic6q.js +1 -0
- package/core/built/admin/assets/dropzone-D61QVcEY.js +5 -0
- package/core/built/admin/assets/edit-profile-jCqJBxqw.js +1 -0
- package/core/built/admin/assets/editor-8Fm4UBEd.js +8 -0
- package/core/built/admin/assets/editor-screen-BSX_uC2B.js +27 -0
- package/core/built/admin/assets/email-previews-Bs-JDhIw.js +1 -0
- package/core/built/admin/assets/email-sending-status-context-C76KYL1V.js +1 -0
- package/core/built/admin/assets/email-sending-status-provider-DnNhlIvt.js +1 -0
- package/core/built/admin/assets/{emails-vFMk4yYl.js → emails-CgvIIz3q.js} +1 -1
- package/core/built/admin/assets/{embed-signup-form-modal-DGqsORxS.js → embed-signup-form-modal-DqtBs1WE.js} +1 -1
- package/core/built/admin/assets/empty-indicator-L4Ql5Db7.js +1 -0
- package/core/built/admin/assets/en-Cx75dJv5.js +1 -0
- package/core/built/admin/assets/esm--rhhUGIG.js +2 -0
- package/core/built/admin/assets/explore-DXhDCtKw.js +1 -0
- package/core/built/admin/assets/feature-flag-overrides-context-CrcQKm9Z.js +1 -0
- package/core/built/admin/assets/feature-image-placeholder-e2q6TcH6.js +1 -0
- package/core/built/admin/assets/feed-mmt4noNL.js +1 -0
- package/core/built/admin/assets/feedback-BTPBQLT5.js +1 -0
- package/core/built/admin/assets/field-p7KnP98B.js +1 -0
- package/core/built/admin/assets/filter-bar-CiIKBg3D.js +1 -0
- package/core/built/admin/assets/filter-sources-I-dRaQxl.js +1 -0
- package/core/built/admin/assets/filters-1injvyxJ.js +1 -0
- package/core/built/admin/assets/filters-DnpO6GWX.js +1 -0
- package/core/built/admin/assets/first-promoter-modal-wr73Dldc.js +1 -0
- package/core/built/admin/assets/focus-koenig-editor-on-bottom-click-CkFA8EkI.js +1 -0
- package/core/built/admin/assets/framework-provider-DB-svAju.js +4 -0
- package/core/built/admin/assets/{ghost-b4e8a403baba61905cd7560e30b9732d.js → ghost-a1e6e172c6917e8ef8fa6b0007756d9b.js} +39 -30
- package/core/built/admin/assets/gift-link-modal-C3H7YFXO.js +1 -0
- package/core/built/admin/assets/{gift-links-CfLSnst2.js → gift-links-D8gl_yJS.js} +1 -1
- package/core/built/admin/assets/global-data-context-3MItMry2.js +1 -0
- package/core/built/admin/assets/grid-5vplBYri.js +1 -0
- package/core/built/admin/assets/growth-B1og1kQp.js +1 -0
- package/core/built/admin/assets/growth-Bf6OHZlK.js +3 -0
- package/core/built/admin/assets/heading-BB21QAbb.js +1 -0
- package/core/built/admin/assets/history-modal-t_qEnxPx.js +1 -0
- package/core/built/admin/assets/hooks-DYfTEQLk.js +2 -0
- package/core/built/admin/assets/html-field-COLQbV4r.js +1 -0
- package/core/built/admin/assets/iframe-buffering-Bq1el-gw.js +1 -0
- package/core/built/admin/assets/images-4mvoc3lB.js +1 -0
- package/core/built/admin/assets/{inbox-gJHG7_xd.js → inbox-DgSZ6w2p.js} +34 -34
- package/core/built/admin/assets/index-B3HZU2i8.css +2 -0
- package/core/built/admin/assets/index-DDd-zhNL.js +4 -0
- package/core/built/admin/assets/index.es-Ct5XQNSj.js +1 -0
- package/core/built/admin/assets/inline-B8H6NzIw.js +1 -0
- package/core/built/admin/assets/input-group-CLIN2ykI.js +1 -0
- package/core/built/admin/assets/{input-surface-BsrIZeSF.js → input-surface-wSO5CRy5.js} +1 -1
- package/core/built/admin/assets/integration-header-CKGrXNVP.js +1 -0
- package/core/built/admin/assets/{integrations-B4kuRBFY.js → integrations-DnJrZnHv.js} +1 -1
- package/core/built/admin/assets/invite-user-modal-BaN2mdhI.js +1 -0
- package/core/built/admin/assets/jsx-runtime-BlNNh7jY.js +1 -0
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +3 -3
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +1 -1
- package/core/built/admin/assets/{koenig-lexical-CGXb0F8o.js → koenig-lexical-CXVgQFUk.js} +1 -1
- package/core/built/admin/assets/koenig-loader-B1XPPY5C.js +2 -0
- package/core/built/admin/assets/kpi-card-CRLPVlFW.js +1 -0
- package/core/built/admin/assets/kpi-card-CRPbW8NZ.js +1 -0
- package/core/built/admin/assets/kpi-helpers-D7zT96bp.js +1 -0
- package/core/built/admin/assets/kpi-tabs-DE_yh9Go.js +1 -0
- package/core/built/admin/assets/label-CgeBxy4o.js +1 -0
- package/core/built/admin/assets/label-picker-DGDp4Vwr.js +1 -0
- package/core/built/admin/assets/labels-KMkFoRG6.js +1 -0
- package/core/built/admin/assets/layout-DWnOMly4.js +1 -0
- package/core/built/admin/assets/lib-_QYaUU89.js +2 -0
- package/core/built/admin/assets/link-helpers-8J7ixADV.js +1 -0
- package/core/built/admin/assets/links-FwNCVyVe.js +1 -0
- package/core/built/admin/assets/list-page-DLMP0PxC.js +1 -0
- package/core/built/admin/assets/luxon-BXCsmep3.js +1 -0
- package/core/built/admin/assets/member-activity-ClMWFyvN.js +1 -0
- package/core/built/admin/assets/member-activity-feed-BQY5Rwaj.js +1 -0
- package/core/built/admin/assets/member-custom-fields-Dd_ie1zG.js +1 -0
- package/core/built/admin/assets/member-detail-DjwkGVne.js +1 -0
- package/core/built/admin/assets/members--N9lhk1N.js +4 -0
- package/core/built/admin/assets/modal-page-Dz-9TP4E.js +1 -0
- package/core/built/admin/assets/moderation-DfYBKq9s.js +1 -0
- package/core/built/admin/assets/multi-select-combobox-BcBEzUW_.js +1 -0
- package/core/built/admin/assets/navigation-modal-Cd-scywg.js +1 -0
- package/core/built/admin/assets/newsletter-detail-modal-CFRY6vg_.js +1 -0
- package/core/built/admin/assets/newsletter-emails-4ntck1AC.js +1 -0
- package/core/built/admin/assets/newsletter-o6eCJtab.js +1 -0
- package/core/built/admin/assets/newsletters-Bmlv0edG.js +1 -0
- package/core/built/admin/assets/{newsletters-Rq1M3GD-.js → newsletters-Dz77m__5.js} +1 -1
- package/core/built/admin/assets/note-CWs3LF-0.js +1 -0
- package/core/built/admin/assets/notifications-BjSvTJqh.js +1 -0
- package/core/built/admin/assets/{nql-BLpCn7qX.js → nql-DnDc7UuU.js} +1 -1
- package/core/built/admin/assets/nql-lang-CeTB_Bhv.js +19 -0
- package/core/built/admin/assets/{offers--e2nGvkW.js → offers-ByWSK0rR.js} +1 -1
- package/core/built/admin/assets/offers-container-modal-Bc9A196w.js +1 -0
- package/core/built/admin/assets/onboarding-B4hfBi9a.js +1 -0
- package/core/built/admin/assets/onboarding-DV_XbHts.js +1 -0
- package/core/built/admin/assets/onboarding-route-Di1LJYEE.js +1 -0
- package/core/built/admin/assets/overview-DE7NHZQN.js +1 -0
- package/core/built/admin/assets/overview-DEF-ZY6x.js +1 -0
- package/core/built/admin/assets/page-header-B-G_g42C.js +1 -0
- package/core/built/admin/assets/pagemenu-CnkTDO71.js +1 -0
- package/core/built/admin/assets/{pages-CjDY2CBI.js → pages-DZ_YGB1D.js} +1 -1
- package/core/built/admin/assets/pages-route-VT7r7YhG.js +1 -0
- package/core/built/admin/assets/papaparse.min-BlhnCUXn.js +10 -0
- package/core/built/admin/assets/pintura-modal-BljM7hf8.js +1 -0
- package/core/built/admin/assets/portal-frame-D9V8iq5x.js +1 -0
- package/core/built/admin/assets/portal-modal-B5OOR9ZD.js +1 -0
- package/core/built/admin/assets/post-analytics-context-bt2YTBAC.js +1 -0
- package/core/built/admin/assets/post-analytics-header-J0WciLx6.js +1 -0
- package/core/built/admin/assets/post-analytics-provider-CgreZDjS.js +1 -0
- package/core/built/admin/assets/post-analytics-rGb-PgD-.js +1 -0
- package/core/built/admin/assets/post-share-modal-D0BbTo4W.js +1 -0
- package/core/built/admin/assets/posts-list-screen-CO5jAWoU.js +2 -0
- package/core/built/admin/assets/posts-route-DV-CXWK9.js +1 -0
- package/core/built/admin/assets/{posts-pCPrhQeR.js → posts-tcoO3iRG.js} +1 -1
- package/core/built/admin/assets/preferences-Tac29oG6.js +5 -0
- package/core/built/admin/assets/preview-chrome-C2lQgZBZ.js +1 -0
- package/core/built/admin/assets/preview-modal-CjRbBr8U.js +1 -0
- package/core/built/admin/assets/profile-yiM1f_Og.js +1 -0
- package/core/built/admin/assets/prop-types-6lTeqvom.js +1 -0
- package/core/built/admin/assets/radio-group-CKROWsw4.js +1 -0
- package/core/built/admin/assets/react-BXwhMTuc.js +1 -0
- package/core/built/admin/assets/{jsx-runtime-DX3WBWVO.js → react-dom-CMOtJ5MH.js} +2 -2
- package/core/built/admin/assets/{referrers-D8oHPmDB.js → referrers-1R8bPpoV.js} +1 -1
- package/core/built/admin/assets/router-provider-CU87qxXw.js +1 -0
- package/core/built/admin/assets/select-CKaC4ggu.js +1 -0
- package/core/built/admin/assets/settings-81kxUa28.js +1 -0
- package/core/built/admin/assets/settings-BVXFqBVK.js +4 -0
- package/core/built/admin/assets/settings-breadcrumbs-czGRx-iu.js +1 -0
- package/core/built/admin/assets/{shade-app-CcS3f8MZ-vwURazk8.js → shade-app-CcS3f8MZ-D5BnfHck.js} +1 -1
- package/core/built/admin/assets/share-modal-BL-16PiB.js +1 -0
- package/core/built/admin/assets/skeleton-DwCva0-b.js +1 -0
- package/core/built/admin/assets/slack-modal-D7W_fNON.js +1 -0
- package/core/built/admin/assets/sort-button-Dquc83jY.js +1 -0
- package/core/built/admin/assets/source-icon-CQboPZQ3.js +1 -0
- package/core/built/admin/assets/stack-BURz77VS.js +1 -0
- package/core/built/admin/assets/{stats-D9PDLS3x.js → stats-Cvp8Ep5m.js} +1 -1
- package/core/built/admin/assets/stats-view-NDja_g96.js +1 -0
- package/core/built/admin/assets/step-1-BKhjy0PV.js +1 -0
- package/core/built/admin/assets/step-2-PxA1OM7R.js +1 -0
- package/core/built/admin/assets/step-3-BJbAiq16.js +2 -0
- package/core/built/admin/assets/stripe-button-C3cfCAou.js +1 -0
- package/core/built/admin/assets/stripe-connect-modal-FyE3Ey2c.js +1 -0
- package/core/built/admin/assets/switch-zfUUy9Jh.js +1 -0
- package/core/built/admin/assets/table-dE4GTIRT.js +1 -0
- package/core/built/admin/assets/tabs-B3XK93sR.js +1 -0
- package/core/built/admin/assets/tag-detail-D4P-tZdM.js +2 -0
- package/core/built/admin/assets/tag-picker-BNSZ6Qxw.js +1 -0
- package/core/built/admin/assets/tags-BsZcaJ6h.js +1 -0
- package/core/built/admin/assets/{tags-ChfdwJyS.js → tags-NwZ7BPK6.js} +1 -1
- package/core/built/admin/assets/testimonials-modal-Dkt6ODLW.js +1 -0
- package/core/built/admin/assets/text-DC-ot6u2.js +1 -0
- package/core/built/admin/assets/textarea-B4FffFmE.js +1 -0
- package/core/built/admin/assets/themes-DtcEFQWm.js +1 -0
- package/core/built/admin/assets/tier-detail-modal-a77Z2VMH.js +1 -0
- package/core/built/admin/assets/{tiers-BCpIOGQr.js → tiers-6mPzCXlM.js} +1 -1
- package/core/built/admin/assets/toggle-group-D2p4okmJ.js +1 -0
- package/core/built/admin/assets/topic-filter-DVOe3D-b.js +1 -0
- package/core/built/admin/assets/transistor-modal-C8RMkhOD.js +1 -0
- package/core/built/admin/assets/trend-badge-B9v7kMF8.js +1 -0
- package/core/built/admin/assets/unsplash-modal-DXt7Brum.js +1 -0
- package/core/built/admin/assets/use-analytics-data-ChHqiZXv.js +1 -0
- package/core/built/admin/assets/use-availability-hPdeG76y.js +1 -0
- package/core/built/admin/assets/{use-check-theme-limit-error-DRUjK4YM.js → use-check-theme-limit-error-JD-J5aaZ.js} +2 -2
- package/core/built/admin/assets/use-email-sending-status-DNMtL5B9.js +1 -0
- package/core/built/admin/assets/use-filter-params-BSFigDIn.js +1 -0
- package/core/built/admin/assets/use-filterable-api-CEMSAYPg.js +1 -0
- package/core/built/admin/assets/use-form-DJKZJhQh.js +1 -0
- package/core/built/admin/assets/use-growth-stats-CqqdnESN.js +1 -0
- package/core/built/admin/assets/use-host-limits-mpTkZIq8.js +1 -0
- package/core/built/admin/assets/use-limiter-DBGjYqu7.js +19 -0
- package/core/built/admin/assets/use-navigate-with-base-path-88EQpw2k.js +1 -0
- package/core/built/admin/assets/use-pintura-config-BmU45Ruy.js +1 -0
- package/core/built/admin/assets/use-pintura-editor-Bz2bZ4iT.js +1 -0
- package/core/built/admin/assets/use-post-referrers-DyPjyBSN.js +1 -0
- package/core/built/admin/assets/use-query-params-DlOHCo-R.js +1 -0
- package/core/built/admin/assets/use-reply-chain-data-DmD2yX5D.js +1 -0
- package/core/built/admin/assets/use-router-history-entry-CKx9LhqD.js +1 -0
- package/core/built/admin/assets/use-sending-eta-CQeG6OP_.js +1 -0
- package/core/built/admin/assets/use-setting-group-Dza6bQ7W.js +1 -0
- package/core/built/admin/assets/use-settings-navigation-BIjI5mL3.js +1 -0
- package/core/built/admin/assets/use-simple-pagination-DwVxe-Lo.js +1 -0
- package/core/built/admin/assets/use-staff-users-i_Mq9OGR.js +1 -0
- package/core/built/admin/assets/{use-tinybird-query-CmdbCS9X.js → use-tinybird-query-DXoF74NM.js} +1 -1
- package/core/built/admin/assets/use-tinybird-token-Lk1RSn0t.js +1 -0
- package/core/built/admin/assets/use-unsaved-changes-guard-CKVPWz_F.js +1 -0
- package/core/built/admin/assets/use-upgrade-route-CVjDlNSs.js +1 -0
- package/core/built/admin/assets/{use-url-input-fvp-TpPx.js → use-url-input-DpmbDppC.js} +1 -1
- package/core/built/admin/assets/user-detail-modal-BU4QCHE7.js +1 -0
- package/core/built/admin/assets/{users-DVNWrqg9.js → users-C60_hpn6.js} +1 -1
- package/core/built/admin/assets/{validator-Cr0sMKuW.js → validator-DlFQP70j.js} +1 -1
- package/core/built/admin/assets/virtual-list-DScLNuU8.js +1 -0
- package/core/built/admin/assets/web-BZS-t4H0.js +1 -0
- package/core/built/admin/assets/web-DxAUxnK3.js +2 -0
- package/core/built/admin/assets/zapier-modal-BafLUO4R.js +1 -0
- package/core/built/admin/index.html +35 -32
- package/core/cli/command.js +17 -2
- package/core/frontend/meta/asset-url.js +1 -16
- package/core/frontend/services/asset-hash/index.js +32 -2
- package/core/frontend/services/routing/controllers/unsubscribe.js +2 -1
- package/core/frontend/services/rss/generate-feed.js +1 -1
- package/core/frontend/services/theme-engine/active.js +2 -4
- package/core/frontend/services/theme-engine/i18n/i18n.js +11 -1
- package/core/frontend/services/theme-engine/i18next/theme-i18n.js +1 -1
- package/core/frontend/web/middleware/llms-discovery.js +34 -43
- package/core/server/adapters/route-settings/S3RouteSettingsStore.js +1 -1
- package/core/server/adapters/storage/LocalFilesStorage.js +12 -2
- package/core/server/adapters/storage/LocalStorageBase.js +13 -0
- package/core/server/api/endpoints/actions.js +2 -1
- package/core/server/api/endpoints/automated-emails.js +3 -2
- package/core/server/api/endpoints/automations.js +77 -49
- package/core/server/api/endpoints/emails.js +8 -3
- package/core/server/api/endpoints/index.js +1 -1
- package/core/server/api/endpoints/invites.js +2 -1
- package/core/server/api/endpoints/labels.js +6 -2
- package/core/server/api/endpoints/member-metafields.js +2 -2
- package/core/server/api/endpoints/members.js +22 -6
- package/core/server/api/endpoints/pages.js +2 -6
- package/core/server/api/endpoints/posts.js +3 -11
- package/core/server/api/endpoints/snippets.js +2 -1
- package/core/server/api/endpoints/tags.js +6 -2
- package/core/server/api/endpoints/users.js +2 -6
- package/core/server/api/endpoints/utils/api-filter-utils.js +62 -3
- package/core/server/api/endpoints/utils/serializers/output/utils/clean.js +2 -0
- package/core/server/api/endpoints/utils/serializers/output/utils/extra-attrs.js +3 -0
- package/core/server/api/endpoints/utils/validators/input/settings.js +15 -1
- package/core/server/data/exporter/exporter.js +2 -1
- package/core/server/data/exporter/table-lists.js +3 -5
- package/core/server/data/importer/importers/data/settings-importer.js +8 -2
- package/core/server/data/migrations/versions/6.64/2026-09-03-15-40-25-add-member-access-to-members-metafields.js +12 -0
- package/core/server/data/migrations/versions/6.64/2026-09-08-11-01-12-add-posts-auto-excerpt-and-reading-time-columns.js +17 -0
- package/core/server/data/migrations/versions/6.64/2026-09-09-13-56-18-add-automation-run-updated-at-indexes.js +6 -0
- package/core/server/data/migrations/versions/6.64/2026-09-09-13-56-18-add-tinybird-syncs-table.js +10 -0
- package/core/server/data/schema/schema.js +28 -2
- package/core/server/data/seeders/importers/automations-importer.js +0 -1
- package/core/server/data/seeders/importers/comments-importer.js +1 -1
- package/core/server/data/seeders/importers/email-recipients-importer.js +1 -1
- package/core/server/data/seeders/importers/emails-importer.js +1 -1
- package/core/server/data/seeders/importers/members-importer.js +1 -1
- package/core/server/data/seeders/importers/members-login-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +1 -1
- package/core/server/data/seeders/utils/blog-info.js +4 -3
- package/core/server/data/seeders/utils/event-generator.js +72 -46
- package/core/server/data/tinybird/datasources/_mv_automation_run_steps.datasource +10 -0
- package/core/server/data/tinybird/datasources/_mv_automation_runs.datasource +10 -0
- package/core/server/data/tinybird/datasources/_mv_pending_automation_runs.datasource +10 -0
- package/core/server/data/tinybird/datasources/automation_run_events.datasource +12 -0
- package/core/server/data/tinybird/datasources/automation_run_step_events.datasource +12 -0
- package/core/server/data/tinybird/endpoints/api_automation_browse_stats.pipe +43 -0
- package/core/server/data/tinybird/fixtures/automation_run_events.ndjson +7 -0
- package/core/server/data/tinybird/fixtures/automation_run_step_events.ndjson +8 -0
- package/core/server/data/tinybird/pipes/mv_automation_run_steps.pipe +13 -0
- package/core/server/data/tinybird/pipes/mv_automation_runs.pipe +15 -0
- package/core/server/data/tinybird/pipes/mv_pending_automation_runs.pipe +7 -0
- package/core/server/data/tinybird/tests/api_automation_browse_stats.yaml +18 -0
- package/core/server/ghost-server.js +3 -3
- package/core/server/lib/generate-password.js +54 -0
- package/core/server/lib/public-jwk.js +77 -0
- package/core/server/models/user.js +11 -9
- package/core/server/services/adapter-manager/base-classes.js +21 -3
- package/core/server/services/automations/automations-api.js +46 -1
- package/core/server/services/automations/tinybird-automation-stats.js +56 -0
- package/core/server/services/content-import/import/media.js +1 -1
- package/core/server/services/email-analytics/email-analytics-service-wrapper.js +15 -29
- package/core/server/services/email-analytics/email-analytics-service.js +19 -3
- package/core/server/services/email-analytics/index.js +9 -4
- package/core/server/services/email-rendering/finalize.js +7 -2
- package/core/server/services/email-service/README.md +3 -0
- package/core/server/services/email-service/email-renderer.js +7 -2
- package/core/server/services/email-service/email-service-wrapper.js +1 -1
- package/core/server/services/email-service/email-service.js +43 -34
- package/core/server/services/email-service/sending-status.js +10 -4
- package/core/server/services/gifts/gift-email-service.js +10 -3
- package/core/server/services/gifts/index.js +1 -0
- package/core/server/services/i18n.js +1 -1
- package/core/server/services/identity-tokens/identity-token-service-wrapper.js +3 -4
- package/core/server/services/limits.js +17 -1
- package/core/server/services/member-welcome-emails/service.js +1 -1
- package/core/server/services/members/import-export/index.js +5 -4
- package/core/server/services/members/members-api/controllers/router-controller.js +7 -2
- package/core/server/services/members/members-api/controllers/well-known-controller.js +2 -1
- package/core/server/services/members/members-api/repositories/event-repository.js +4 -0
- package/core/server/services/members/members-api/services/member-bread-service.js +15 -12
- package/core/server/services/members/members-api/services/token-service.js +11 -12
- package/core/server/services/members/middleware.js +9 -2
- package/core/server/services/members/request-integrity-token-provider.js +2 -1
- package/core/server/services/members-metafields/access.js +31 -20
- package/core/server/services/members-metafields/actions.js +1 -0
- package/core/server/services/members-metafields/codec.js +9 -2
- package/core/server/services/members-metafields/definitions-service.js +56 -46
- package/core/server/services/members-metafields/index.js +2 -2
- package/core/server/services/members-metafields/models.js +2 -0
- package/core/server/services/members-metafields/queries.js +39 -11
- package/core/server/services/members-metafields/schema.js +2 -0
- package/core/server/services/members-metafields/serializers.js +1 -0
- package/core/server/services/members-metafields/values-service.js +20 -11
- package/core/server/services/mentions/mention-discovery-service.js +1 -1
- package/core/server/services/mentions/mention-sending-service.js +1 -1
- package/core/server/services/mentions/mention.js +1 -1
- package/core/server/services/oembed/oembed-service.js +36 -11
- package/core/server/services/posts/post-scheduling.js +20 -0
- package/core/server/services/staff/staff-service-emails.js +5 -1
- package/core/server/services/stats/stats-service.js +12 -3
- package/core/server/services/tier-checkout-config/service.js +17 -1
- package/core/server/services/tinybird/tinybird-service.js +1 -0
- package/core/server/services/tinybird-sync/get-ingest-config.js +39 -0
- package/core/server/services/tinybird-sync/index.js +28 -0
- package/core/server/services/tinybird-sync/sync-table-to-tinybird.js +149 -0
- package/core/server/services/tinybird-sync/tinybird-sync-service.js +62 -0
- package/core/server/web/api/endpoints/admin/routes.js +33 -34
- package/core/server/web/well-known.js +12 -16
- package/core/shared/config/defaults.json +1 -2
- package/core/shared/{flush-logs.js → flush.js} +7 -3
- package/core/shared/labs.js +2 -0
- package/core/shared/timing-safe-string-equal.js +26 -0
- package/package.json +42 -42
- package/patches/@elastic__elasticsearch@8.19.2.patch +67 -0
- package/patches/juice@11.1.1.patch +46 -0
- package/pnpm-lock.yaml +457 -1391
- package/pnpm-workspace.yaml +34 -21
- package/scripts/prune.mts +70 -3
- package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
- package/core/built/admin/assets/Combination-B0l4MKVh.js +0 -41
- package/core/built/admin/assets/RadialBarChart-JAKoS4KT.js +0 -1
- package/core/built/admin/assets/_baseAssignValue-C_vooEQc.js +0 -1
- package/core/built/admin/assets/about-C1C3s5-g.js +0 -1
- package/core/built/admin/assets/accordion-CxGsDKwa.js +0 -1
- package/core/built/admin/assets/account-migration-CbUhW6gk.js +0 -1
- package/core/built/admin/assets/action-list-C4v0-du8.js +0 -1
- package/core/built/admin/assets/add-integration-modal-BT_onDJy.js +0 -1
- package/core/built/admin/assets/add-newsletter-modal-Cx1kQpiY.js +0 -1
- package/core/built/admin/assets/add-recommendation-modal-B5nvAhvr.js +0 -1
- package/core/built/admin/assets/analytics-DjoJWPI7.js +0 -1
- package/core/built/admin/assets/announcement-bar-modal-Dwd0EGFP.js +0 -1
- package/core/built/admin/assets/api-keys-BoeacM-s.js +0 -1
- package/core/built/admin/assets/automated-emails-BLesE41L.js +0 -1
- package/core/built/admin/assets/automations-BN4u3GR8.js +0 -1
- package/core/built/admin/assets/automations-C-ZTUwW3.js +0 -1
- package/core/built/admin/assets/avatar-flipboard-C6Kj3Awu.js +0 -1
- package/core/built/admin/assets/bluesky-sharing-vzh-oPXL.js +0 -1
- package/core/built/admin/assets/box-CdfQAP_F.js +0 -1
- package/core/built/admin/assets/brand-icon-CrIGOA3Z.js +0 -1
- package/core/built/admin/assets/breadcrumb-CaLk2b7D.js +0 -1
- package/core/built/admin/assets/build-CsiH26uS.js +0 -1
- package/core/built/admin/assets/button-Dvcv1QSR.js +0 -1
- package/core/built/admin/assets/calendar-Bl9RLcZX.js +0 -1
- package/core/built/admin/assets/card--VNbfgo3.js +0 -1
- package/core/built/admin/assets/chart-helpers-FHywU0pj.js +0 -1
- package/core/built/admin/assets/checkbox-BtayFtjg.js +0 -1
- package/core/built/admin/assets/chunk.524.e6975095fccdf22d90f8.js +0 -32
- package/core/built/admin/assets/code-editor-view-C3ZfoF1X.js +0 -1
- package/core/built/admin/assets/code-editor-view-CAyRWy1s.js +0 -1
- package/core/built/admin/assets/color-picker-G4kGR7rp.js +0 -3
- package/core/built/admin/assets/color-picker-field-DQFVTNnT.js +0 -1
- package/core/built/admin/assets/combobox-BnYzgEB4.js +0 -1
- package/core/built/admin/assets/command-C_vyTikI.js +0 -1
- package/core/built/admin/assets/comments-aBrxfnZf.js +0 -1
- package/core/built/admin/assets/components-CwL6a6As-B0E0-NBJ.js +0 -1
- package/core/built/admin/assets/confirmation-context-DwXX_Y5h.js +0 -1
- package/core/built/admin/assets/container-BuQG1wuP.js +0 -1
- package/core/built/admin/assets/content-api-modal-D2G0nJP6.js +0 -1
- package/core/built/admin/assets/context-menu-DOVB6yaz.js +0 -1
- package/core/built/admin/assets/copy-field-DCJwh9qf.js +0 -1
- package/core/built/admin/assets/create-ghost-browse-value-source-5C53jJaX.js +0 -1
- package/core/built/admin/assets/custom-field-type-option-BAuW0F-E.js +0 -1
- package/core/built/admin/assets/custom-integration-modal-AbJGVyKc.js +0 -1
- package/core/built/admin/assets/data-list-CA2jYGPq.js +0 -1
- package/core/built/admin/assets/date-range-select-BY3K-ukj.js +0 -1
- package/core/built/admin/assets/design-and-theme-modal-BvEy4_pC.js +0 -2
- package/core/built/admin/assets/detail-page-Dnv-CdR1.js +0 -1
- package/core/built/admin/assets/dirty-confirm-dialog-DVPuGz3U.js +0 -1
- package/core/built/admin/assets/disabled-sources-indicator-Cy7Zp4c8.js +0 -1
- package/core/built/admin/assets/dist-4m6pHdc0.js +0 -23
- package/core/built/admin/assets/dist-8YJUlf3B.js +0 -1
- package/core/built/admin/assets/dist-CZgIBXQN.js +0 -1
- package/core/built/admin/assets/dist-CiHx7vA5.js +0 -6
- package/core/built/admin/assets/dist-DIC8yz5C.js +0 -1
- package/core/built/admin/assets/dist-Dcsslyo72.js +0 -1
- package/core/built/admin/assets/dist-Dgt2cr6a.js +0 -1
- package/core/built/admin/assets/dist-ECAUrdGc.js +0 -1
- package/core/built/admin/assets/dist-JLOy8o0Q.js +0 -1
- package/core/built/admin/assets/dist-Ndy-PuGN.js +0 -1
- package/core/built/admin/assets/dist-Z97pCNqS.js +0 -11
- package/core/built/admin/assets/domain-Dl61QGuk.js +0 -1
- package/core/built/admin/assets/dropzone-Dtz5Rmjt.js +0 -5
- package/core/built/admin/assets/edit-profile-DNJSMDwm.js +0 -1
- package/core/built/admin/assets/editor-DbAen9zf.js +0 -8
- package/core/built/admin/assets/editor-screen-BFWThIai.js +0 -26
- package/core/built/admin/assets/email-sending-status-context-CWDOD1FN.js +0 -1
- package/core/built/admin/assets/email-sending-status-provider-DCPkDICt.js +0 -1
- package/core/built/admin/assets/empty-indicator-D9QdpuNX.js +0 -1
- package/core/built/admin/assets/en-B1jX3WMs.js +0 -1
- package/core/built/admin/assets/esm-CXo5SEPy.js +0 -2
- package/core/built/admin/assets/explore-nnRr1Fja.js +0 -1
- package/core/built/admin/assets/feature-flag-overrides-context-DQjdJFAk.js +0 -1
- package/core/built/admin/assets/feature-image-placeholder-BrIHmPs8.js +0 -1
- package/core/built/admin/assets/feed-BNUcNu-W.js +0 -1
- package/core/built/admin/assets/feedback-DJ4Zb9rZ.js +0 -1
- package/core/built/admin/assets/field-C93_Mg6j.js +0 -1
- package/core/built/admin/assets/filter-bar-Da1qxybu.js +0 -1
- package/core/built/admin/assets/filter-sources-CGJb4C5r.js +0 -1
- package/core/built/admin/assets/filters--kKP-EC8.js +0 -1
- package/core/built/admin/assets/filters-DxA_a4FP.js +0 -1
- package/core/built/admin/assets/first-promoter-modal-BYDtrz2S.js +0 -1
- package/core/built/admin/assets/focus-koenig-editor-on-bottom-click-BbSnGOtK.js +0 -1
- package/core/built/admin/assets/framework-provider-DqI25epG.js +0 -4
- package/core/built/admin/assets/gift-link-modal-B7u5bD4e.js +0 -1
- package/core/built/admin/assets/global-data-context-gAMDH9u1.js +0 -1
- package/core/built/admin/assets/grid-Dj29PY05.js +0 -1
- package/core/built/admin/assets/growth-Cd1uO9d2.js +0 -1
- package/core/built/admin/assets/growth-aG32xfdE.js +0 -3
- package/core/built/admin/assets/heading-Dh5SFVjL.js +0 -1
- package/core/built/admin/assets/history-modal-Df8lW8h-.js +0 -1
- package/core/built/admin/assets/hooks-Cy_-oZ4o.js +0 -2
- package/core/built/admin/assets/html-field-DA4eU7eq.js +0 -1
- package/core/built/admin/assets/iframe-buffering-B2OKJzbz.js +0 -1
- package/core/built/admin/assets/images-KXmyO3Ss.js +0 -1
- package/core/built/admin/assets/index-BHHXtR5C.css +0 -2
- package/core/built/admin/assets/index-CgMCwsxN.js +0 -4
- package/core/built/admin/assets/index.es-CY6-yuw9.js +0 -1
- package/core/built/admin/assets/inline-BWSs_VzR.js +0 -1
- package/core/built/admin/assets/input-group-BE8rM2y1.js +0 -1
- package/core/built/admin/assets/integration-header-Bm6IDb1A.js +0 -1
- package/core/built/admin/assets/invite-user-modal-B4CuNcx4.js +0 -1
- package/core/built/admin/assets/koenig-loader-BeM5rFPX.js +0 -2
- package/core/built/admin/assets/kpi-card-B21aToe8.js +0 -1
- package/core/built/admin/assets/kpi-card-pz6Wv4Ae.js +0 -1
- package/core/built/admin/assets/kpi-helpers-Dq5jelmP.js +0 -1
- package/core/built/admin/assets/kpi-tabs-DEZHpKUt.js +0 -1
- package/core/built/admin/assets/label-OLCzze8N.js +0 -1
- package/core/built/admin/assets/label-picker-BigOvMPV.js +0 -1
- package/core/built/admin/assets/labels-Dr0SgUQD.js +0 -1
- package/core/built/admin/assets/layout-DUTL8SH5.js +0 -1
- package/core/built/admin/assets/lib-7QPTI0FS.js +0 -1
- package/core/built/admin/assets/limit-service-BhiEvqcP.js +0 -20
- package/core/built/admin/assets/link-helpers-BRAg9SCj.js +0 -1
- package/core/built/admin/assets/links-BDHPTlyj.js +0 -1
- package/core/built/admin/assets/list-page-BucXJ0hi.js +0 -1
- package/core/built/admin/assets/luxon-D1RVjjpq.js +0 -1
- package/core/built/admin/assets/member-custom-fields-TRTHCAz9.js +0 -1
- package/core/built/admin/assets/member-detail-b6dRwc3C.js +0 -1
- package/core/built/admin/assets/members-Czt5lJSc.js +0 -4
- package/core/built/admin/assets/modal-page-xCivTMvI.js +0 -1
- package/core/built/admin/assets/moderation-ZWefD9uH.js +0 -1
- package/core/built/admin/assets/multi-select-combobox-CT13MTo-.js +0 -1
- package/core/built/admin/assets/navigation-modal-C8FEhBK5.js +0 -1
- package/core/built/admin/assets/newsletter-5VYW4RyJ.js +0 -1
- package/core/built/admin/assets/newsletter-detail-modal-ChjC0ZqH.js +0 -1
- package/core/built/admin/assets/newsletter-emails-DZH6I-PY.js +0 -1
- package/core/built/admin/assets/newsletters-DOC9KBcX.js +0 -1
- package/core/built/admin/assets/note-DIV-Pojr.js +0 -1
- package/core/built/admin/assets/notifications-s20-H49V.js +0 -1
- package/core/built/admin/assets/nql-lang-CaWrLesS.js +0 -19
- package/core/built/admin/assets/offers-container-modal-BmG5M5Tv.js +0 -1
- package/core/built/admin/assets/onboarding-CUuy9unR.js +0 -1
- package/core/built/admin/assets/onboarding-pXyct0Jm.js +0 -1
- package/core/built/admin/assets/onboarding-route-CK4pcXoR.js +0 -1
- package/core/built/admin/assets/overview-CaPsciMs.js +0 -1
- package/core/built/admin/assets/overview-a8GfcsKX.js +0 -1
- package/core/built/admin/assets/page-header-DM_KyoFI.js +0 -1
- package/core/built/admin/assets/pagemenu-vgZVUVKR.js +0 -1
- package/core/built/admin/assets/pages-route-BzKZYdV5.js +0 -1
- package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +0 -10
- package/core/built/admin/assets/pintura-modal-DExCF1ii.js +0 -1
- package/core/built/admin/assets/portal-frame-Cqanidq4.js +0 -1
- package/core/built/admin/assets/portal-modal-oinBgA27.js +0 -1
- package/core/built/admin/assets/post-analytics-C5oJ1dWV.js +0 -1
- package/core/built/admin/assets/post-analytics-context-D0Mw-Pmv.js +0 -1
- package/core/built/admin/assets/post-analytics-header-OATo3X_r.js +0 -1
- package/core/built/admin/assets/post-analytics-provider-tOpIVGT5.js +0 -1
- package/core/built/admin/assets/post-share-modal-DvhC1XgV.js +0 -1
- package/core/built/admin/assets/posts-list-screen-o4ZjbgS3.js +0 -2
- package/core/built/admin/assets/posts-route-9F--xdIb.js +0 -1
- package/core/built/admin/assets/preferences--vNubsqD.js +0 -5
- package/core/built/admin/assets/preview-chrome-BljUBlOk.js +0 -1
- package/core/built/admin/assets/preview-modal-YYbzlYdO.js +0 -1
- package/core/built/admin/assets/profile-BllKV3dR.js +0 -1
- package/core/built/admin/assets/prop-types-DeUPn3oD.js +0 -1
- package/core/built/admin/assets/radio-group-DL8GI8rt.js +0 -1
- package/core/built/admin/assets/react-Bb3IsNbi.js +0 -1
- package/core/built/admin/assets/rolldown-runtime-DAXXjFlN.js +0 -1
- package/core/built/admin/assets/router-provider-BSvTXgZY.js +0 -1
- package/core/built/admin/assets/select-v5YbA3Mw.js +0 -1
- package/core/built/admin/assets/settings-PEsZupw1.js +0 -4
- package/core/built/admin/assets/settings-breadcrumbs-NwPnCTC7.js +0 -1
- package/core/built/admin/assets/settings-u_s1CRkr.js +0 -1
- package/core/built/admin/assets/share-modal-SskCmVGL.js +0 -1
- package/core/built/admin/assets/skeleton-Ce9GgUpf.js +0 -1
- package/core/built/admin/assets/slack-modal-XxSJiYgo.js +0 -1
- package/core/built/admin/assets/sort-button-Cx1KtINE.js +0 -1
- package/core/built/admin/assets/source-icon-Bdp9Im_5.js +0 -1
- package/core/built/admin/assets/stack-B2eszIiq.js +0 -1
- package/core/built/admin/assets/stats-view-W2g6Jsd-.js +0 -1
- package/core/built/admin/assets/step-1-BQYzvBzr.js +0 -1
- package/core/built/admin/assets/step-2-xES32xJV.js +0 -1
- package/core/built/admin/assets/step-3-DA_XK5kW.js +0 -2
- package/core/built/admin/assets/stripe-button-CVsLHelt.js +0 -1
- package/core/built/admin/assets/stripe-connect-modal-ClmLOMGS.js +0 -1
- package/core/built/admin/assets/switch-CI4gLWqb.js +0 -1
- package/core/built/admin/assets/table-BenqVupI.js +0 -1
- package/core/built/admin/assets/tabs-eBBlxPp8.js +0 -1
- package/core/built/admin/assets/tag-detail-Ce8Se2qd.js +0 -2
- package/core/built/admin/assets/tag-picker-C3UR-uJ-.js +0 -1
- package/core/built/admin/assets/tags-B-kJxCs7.js +0 -1
- package/core/built/admin/assets/testimonials-modal-9Q6fT06V.js +0 -1
- package/core/built/admin/assets/text-BQDSDsKs.js +0 -1
- package/core/built/admin/assets/textarea-DJ1Q5V39.js +0 -1
- package/core/built/admin/assets/tier-detail-modal-CDyYdqK7.js +0 -1
- package/core/built/admin/assets/toggle-group-CviIkyok.js +0 -1
- package/core/built/admin/assets/topic-filter-I2jCBGxm.js +0 -1
- package/core/built/admin/assets/transistor-modal-p53u3W8y.js +0 -1
- package/core/built/admin/assets/trend-badge-CideVzQd.js +0 -1
- package/core/built/admin/assets/unsplash-modal-DY8UcKcE.js +0 -1
- package/core/built/admin/assets/use-analytics-data-DAIGcr2f.js +0 -1
- package/core/built/admin/assets/use-filter-params-JkZhIS8L.js +0 -1
- package/core/built/admin/assets/use-filterable-api-BVEVMrhZ.js +0 -1
- package/core/built/admin/assets/use-form-vRjI0Kwk.js +0 -1
- package/core/built/admin/assets/use-growth-stats-937CUj6j.js +0 -1
- package/core/built/admin/assets/use-host-limits-D0Dv3tKA.js +0 -1
- package/core/built/admin/assets/use-limiter-CohWfzvK.js +0 -2
- package/core/built/admin/assets/use-navigate-with-base-path-BkxcPj5l.js +0 -1
- package/core/built/admin/assets/use-pintura-config-xgytjU35.js +0 -1
- package/core/built/admin/assets/use-pintura-editor-CaV1mbfO.js +0 -1
- package/core/built/admin/assets/use-post-referrers-BCQI7fDg.js +0 -1
- package/core/built/admin/assets/use-query-params-BfzuqbcD.js +0 -1
- package/core/built/admin/assets/use-reply-chain-data-CYRhoaxY.js +0 -1
- package/core/built/admin/assets/use-router-history-entry-NOKcd--l.js +0 -1
- package/core/built/admin/assets/use-setting-group-bLKMwoBT.js +0 -1
- package/core/built/admin/assets/use-settings-navigation-B-qrriKD.js +0 -1
- package/core/built/admin/assets/use-simple-pagination-CNPd6Rf6.js +0 -1
- package/core/built/admin/assets/use-staff-users-pRIMIyiW.js +0 -1
- package/core/built/admin/assets/use-tinybird-token-KLne235s.js +0 -1
- package/core/built/admin/assets/use-unsaved-changes-guard-7-ug0JdH.js +0 -1
- package/core/built/admin/assets/use-upgrade-route-Dm_qqKr0.js +0 -1
- package/core/built/admin/assets/user-detail-modal-D3KlGYv-.js +0 -1
- package/core/built/admin/assets/virtual-list-CZ3RK2Yf.js +0 -1
- package/core/built/admin/assets/web-ClEJsCAj.js +0 -2
- package/core/built/admin/assets/web-X9rdnrtq.js +0 -1
- package/core/built/admin/assets/zapier-modal-DfVhV17j.js +0 -1
- /package/core/built/admin/assets/{chunk.901.4ccc639821020230bcca.js.LICENSE.txt → chunk.972.4b8c97f93d66db15e751.js.LICENSE.txt} +0 -0
|
@@ -29,12 +29,15 @@ const messages = {
|
|
|
29
29
|
retryEmailNotFailed: 'Only failed emails can be retried',
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
// Resume scanner won't pick up `submitting` rows older than this. Rows beyond
|
|
33
|
-
// are flipped to `failed` on first boot so they surface in admin UI for operator
|
|
34
|
-
// rather than being silently resumed (and sending stale newsletters to current members).
|
|
32
|
+
// Resume scanner won't pick up `pending` or `submitting` rows older than this. Rows beyond
|
|
33
|
+
// the cutoff are flipped to `failed` on first boot so they surface in admin UI for operator
|
|
34
|
+
// review rather than being silently resumed (and sending stale newsletters to current members).
|
|
35
35
|
// Override via `bulkEmail:resumeMaxAgeMs` in config.
|
|
36
36
|
const DEFAULT_RESUME_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
37
37
|
|
|
38
|
+
// Non-terminal email statuses, both of which the boot scanner recovers.
|
|
39
|
+
const RESUMABLE_EMAIL_STATUSES = ['pending', 'submitting'];
|
|
40
|
+
|
|
38
41
|
class EmailService {
|
|
39
42
|
#batchSendingService;
|
|
40
43
|
#sendingService;
|
|
@@ -223,28 +226,31 @@ class EmailService {
|
|
|
223
226
|
}
|
|
224
227
|
|
|
225
228
|
/**
|
|
226
|
-
* Boot-time scanner:
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
229
|
+
* Boot-time scanner: recovers newsletter emails a previous container left without work.
|
|
230
|
+
* Two shapes, both resumed through the normal emailJob path:
|
|
231
|
+
* - `submitting` — the send was cut off mid-flight.
|
|
232
|
+
* - `pending` — dispatch was dropped from the in-memory job queue before the job ever
|
|
233
|
+
* started, so no batch work exists and nothing else will ever pick the row up.
|
|
234
|
+
* Iterates sequentially; one failure does not skip others. Rows older than the configured
|
|
235
|
+
* max-age are flipped to `failed` (not resumed) so stale content does not get sent to
|
|
236
|
+
* current members.
|
|
230
237
|
*/
|
|
231
238
|
async resumeInterruptedSends() {
|
|
232
239
|
const maxAgeMs = this.#config?.get?.('bulkEmail:resumeMaxAgeMs') ?? DEFAULT_RESUME_MAX_AGE_MS;
|
|
233
240
|
const cutoffIso = new Date(Date.now() - maxAgeMs).toISOString();
|
|
234
241
|
|
|
235
242
|
// Stale rows: too old to safely resume. Flip to `failed` so they surface in admin UI
|
|
236
|
-
// for operator review instead of being silently
|
|
243
|
+
// for operator review instead of being silently stuck in their current status forever.
|
|
237
244
|
const stale = await this.#models.Email.findAll({
|
|
238
|
-
filter: `status:
|
|
245
|
+
filter: `status:[${RESUMABLE_EMAIL_STATUSES.join(',')}]+created_at:<'${cutoffIso}'`,
|
|
239
246
|
});
|
|
240
|
-
const
|
|
241
|
-
for (const email of staleList) {
|
|
247
|
+
for (const email of stale.models) {
|
|
242
248
|
try {
|
|
243
249
|
const locked = await this.#batchSendingService.updateStatusLock(
|
|
244
250
|
this.#models.Email,
|
|
245
251
|
email.id,
|
|
246
252
|
'failed',
|
|
247
|
-
['
|
|
253
|
+
[email.get('status')],
|
|
248
254
|
);
|
|
249
255
|
if (locked) {
|
|
250
256
|
logging.warn(
|
|
@@ -257,20 +263,19 @@ class EmailService {
|
|
|
257
263
|
}
|
|
258
264
|
|
|
259
265
|
// Fresh rows: within the cutoff. Resume through the normal emailJob path.
|
|
260
|
-
const
|
|
261
|
-
filter: `status:
|
|
266
|
+
const fresh = await this.#models.Email.findAll({
|
|
267
|
+
filter: `status:[${RESUMABLE_EMAIL_STATUSES.join(',')}]+created_at:>'${cutoffIso}'`,
|
|
262
268
|
});
|
|
263
|
-
|
|
264
|
-
if (staleList.length === 0 && list.length === 0) {
|
|
269
|
+
if (stale.models.length === 0 && fresh.models.length === 0) {
|
|
265
270
|
return;
|
|
266
271
|
}
|
|
267
|
-
if (
|
|
272
|
+
if (fresh.models.length > 0) {
|
|
268
273
|
logging.info(
|
|
269
|
-
`Email resume: found ${
|
|
274
|
+
`Email resume: found ${fresh.models.length} pending or submitting email(s) within max age (${maxAgeMs}ms)`,
|
|
270
275
|
);
|
|
271
276
|
}
|
|
272
277
|
|
|
273
|
-
for (const email of
|
|
278
|
+
for (const email of fresh.models) {
|
|
274
279
|
try {
|
|
275
280
|
await this.#resumeOneEmail(email);
|
|
276
281
|
} catch (e) {
|
|
@@ -279,23 +284,24 @@ class EmailService {
|
|
|
279
284
|
}
|
|
280
285
|
|
|
281
286
|
logging.info(
|
|
282
|
-
`Email resume scan complete: ${
|
|
287
|
+
`Email resume scan complete: ${stale.models.length} stale email(s) flipped to failed, ${fresh.models.length} fresh email(s) rescheduled`,
|
|
283
288
|
);
|
|
284
289
|
}
|
|
285
290
|
|
|
286
291
|
async #resumeOneEmail(email) {
|
|
292
|
+
const status = email.get('status');
|
|
287
293
|
const post = await email.getLazyRelation('post');
|
|
288
294
|
const postStatus = post ? post.get('status') : null;
|
|
289
295
|
const sendable = postStatus === 'published' || postStatus === 'sent';
|
|
290
296
|
|
|
291
297
|
if (!sendable) {
|
|
292
298
|
// Parent post was unpublished or deleted while the email was in flight.
|
|
293
|
-
// Can't resume — mark the email as failed so it stops showing as
|
|
299
|
+
// Can't resume — mark the email as failed so it stops showing as unsent.
|
|
294
300
|
const locked = await this.#batchSendingService.updateStatusLock(
|
|
295
301
|
this.#models.Email,
|
|
296
302
|
email.id,
|
|
297
303
|
'failed',
|
|
298
|
-
[
|
|
304
|
+
[status],
|
|
299
305
|
);
|
|
300
306
|
if (locked) {
|
|
301
307
|
logging.warn(
|
|
@@ -305,19 +311,22 @@ class EmailService {
|
|
|
305
311
|
return;
|
|
306
312
|
}
|
|
307
313
|
|
|
308
|
-
//
|
|
309
|
-
// If updateStatusLock returns undefined, another path
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
logging.info(
|
|
318
|
-
`Email resume: ${email.id} status changed before lock could be taken — skipping`,
|
|
314
|
+
// `pending` is already what emailJob's status lock (['pending', 'failed']) admits, so
|
|
315
|
+
// only `submitting` needs flipping. If updateStatusLock returns undefined, another path
|
|
316
|
+
// raced us — leave it to whoever won.
|
|
317
|
+
if (status === 'submitting') {
|
|
318
|
+
const locked = await this.#batchSendingService.updateStatusLock(
|
|
319
|
+
this.#models.Email,
|
|
320
|
+
email.id,
|
|
321
|
+
'pending',
|
|
322
|
+
['submitting'],
|
|
319
323
|
);
|
|
320
|
-
|
|
324
|
+
if (!locked) {
|
|
325
|
+
logging.info(
|
|
326
|
+
`Email resume: ${email.id} status changed before lock could be taken — skipping`,
|
|
327
|
+
);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
321
330
|
}
|
|
322
331
|
|
|
323
332
|
// Structured breadcrumb so post-incident timing/batch state is recoverable from logs.
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.EmailSendingStatus = exports.SendingStatus = exports.SendingProgress = exports.SendingPhase = void 0;
|
|
4
4
|
exports.buildSendingStatus = buildSendingStatus;
|
|
5
5
|
const zod_1 = require("zod");
|
|
6
|
-
const
|
|
6
|
+
const ETA_WINDOW_MS = 60_000;
|
|
7
7
|
const ETA_MIN_INTERVALS = 2;
|
|
8
8
|
exports.SendingPhase = zod_1.z.enum(['preparing', 'submitting']);
|
|
9
9
|
exports.SendingProgress = zod_1.z.object({
|
|
@@ -96,12 +96,18 @@ function estimateSecondsRemaining({ remaining, samples, attemptStartedAt, }) {
|
|
|
96
96
|
completions.push({ ...sample });
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
-
// Limit usable timestamps, not rows: fast sends may finish many batches per timestamp.
|
|
100
|
-
const window = completions.slice(-ETA_COMPLETION_WINDOW);
|
|
101
99
|
// Three distinct timestamps provide two measured intervals for an initial rate.
|
|
102
|
-
if (
|
|
100
|
+
if (completions.length < ETA_MIN_INTERVALS + 1) {
|
|
103
101
|
return null;
|
|
104
102
|
}
|
|
103
|
+
// Include the baseline at or before the last minute so the first interval's
|
|
104
|
+
// recipients have their full elapsed time. Sparse sends still need two intervals.
|
|
105
|
+
const cutoff = completions[completions.length - 1].timestamp - ETA_WINDOW_MS;
|
|
106
|
+
let baseline = completions.length - 1;
|
|
107
|
+
while (baseline > 0 && completions[baseline].timestamp > cutoff) {
|
|
108
|
+
baseline -= 1;
|
|
109
|
+
}
|
|
110
|
+
const window = completions.slice(Math.max(0, Math.min(baseline, completions.length - ETA_MIN_INTERVALS - 1)));
|
|
105
111
|
// Measure combined throughput across the window, including overlapping workers.
|
|
106
112
|
// The first completion is only the baseline: its recipients were processed
|
|
107
113
|
// before the measured time span.
|
|
@@ -13,6 +13,7 @@ const gift_date_1 = require("./gift-date");
|
|
|
13
13
|
const DEFAULT_ACCENT_COLOR = '#15212A';
|
|
14
14
|
class GiftEmailService {
|
|
15
15
|
transactionalMailer;
|
|
16
|
+
config;
|
|
16
17
|
bulkMailer;
|
|
17
18
|
settingsCache;
|
|
18
19
|
urlUtils;
|
|
@@ -21,7 +22,8 @@ class GiftEmailService {
|
|
|
21
22
|
blogIcon;
|
|
22
23
|
renderer;
|
|
23
24
|
t;
|
|
24
|
-
constructor({ transactionalMailer, bulkMailer, settingsCache, urlUtils, getFromAddress, getReplyToAddress, blogIcon, t, }) {
|
|
25
|
+
constructor({ config, transactionalMailer, bulkMailer, settingsCache, urlUtils, getFromAddress, getReplyToAddress, blogIcon, t, }) {
|
|
26
|
+
this.config = config;
|
|
25
27
|
this.transactionalMailer = transactionalMailer;
|
|
26
28
|
this.bulkMailer = bulkMailer;
|
|
27
29
|
this.settingsCache = settingsCache;
|
|
@@ -205,6 +207,11 @@ class GiftEmailService {
|
|
|
205
207
|
buyerName,
|
|
206
208
|
interpolation: { escapeValue: false },
|
|
207
209
|
});
|
|
210
|
+
const tags = [constants_1.GIFT_DELIVERY_EMAIL_TAG];
|
|
211
|
+
const mailgunTagFromConfig = this.config.get('bulkEmail:mailgun:tag');
|
|
212
|
+
if (typeof mailgunTagFromConfig === 'string' && mailgunTagFromConfig.length > 0) {
|
|
213
|
+
tags.push(mailgunTagFromConfig);
|
|
214
|
+
}
|
|
208
215
|
if (!this.bulkMailer.isConfigured()) {
|
|
209
216
|
await this.transactionalMailer.send({
|
|
210
217
|
to: recipientEmail,
|
|
@@ -214,7 +221,7 @@ class GiftEmailService {
|
|
|
214
221
|
from: this.getFromAddress(),
|
|
215
222
|
replyTo: this.getReplyToAddress(),
|
|
216
223
|
forceTextContent: true,
|
|
217
|
-
tags
|
|
224
|
+
tags,
|
|
218
225
|
disableTracking: true,
|
|
219
226
|
});
|
|
220
227
|
return { providerMessageId: null };
|
|
@@ -225,7 +232,7 @@ class GiftEmailService {
|
|
|
225
232
|
plaintext: text,
|
|
226
233
|
from: this.getFromAddress(),
|
|
227
234
|
replyTo: this.getReplyToAddress(),
|
|
228
|
-
tags
|
|
235
|
+
tags,
|
|
229
236
|
disable_tracking: true,
|
|
230
237
|
}, { [recipientEmail]: {} }, []);
|
|
231
238
|
const providerMessageId = (0, mailgun_message_id_1.getMailgunMessageId)(response) ?? null;
|
|
@@ -52,6 +52,7 @@ function init(options) {
|
|
|
52
52
|
getStripeApi: () => require('../stripe').api,
|
|
53
53
|
});
|
|
54
54
|
const giftEmailService = new gift_email_service_1.GiftEmailService({
|
|
55
|
+
config,
|
|
55
56
|
transactionalMailer: new GhostMailer(),
|
|
56
57
|
bulkMailer: new MailgunClient({ config, settings: settingsCache }),
|
|
57
58
|
settingsCache,
|
|
@@ -19,7 +19,7 @@ exports.t = (...args) => {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
exports.init = () => {
|
|
22
|
-
const i18n = require('@tryghost/i18n');
|
|
22
|
+
const i18n = require('@tryghost/i18n').default;
|
|
23
23
|
const events = require('../lib/common/events');
|
|
24
24
|
const settingsCache = require('../../shared/settings-cache');
|
|
25
25
|
|
|
@@ -13,12 +13,11 @@ module.exports = class IdentityTokenServiceWrapper {
|
|
|
13
13
|
const issuer = urlUtils.urlFor('admin', true);
|
|
14
14
|
|
|
15
15
|
const settings = require('../../../shared/settings-cache');
|
|
16
|
-
const
|
|
16
|
+
const { getPublicKeyInfo } = require('../../lib/public-jwk');
|
|
17
17
|
|
|
18
18
|
const privateKey = settings.get('ghost_private_key');
|
|
19
|
-
const
|
|
20
|
-
const key = await keyStore.add(privateKey, 'pem');
|
|
19
|
+
const { kid } = await getPublicKeyInfo(privateKey);
|
|
21
20
|
|
|
22
|
-
IdentityTokenServiceWrapper.instance = new IdentityTokenService(privateKey, issuer,
|
|
21
|
+
IdentityTokenServiceWrapper.instance = new IdentityTokenService(privateKey, issuer, kid);
|
|
23
22
|
}
|
|
24
23
|
};
|
|
@@ -2,7 +2,7 @@ const errors = require('@tryghost/errors');
|
|
|
2
2
|
const config = require('../../shared/config');
|
|
3
3
|
const db = require('../data/db');
|
|
4
4
|
const logging = require('@tryghost/logging');
|
|
5
|
-
const LimitService = require('@tryghost/limit-service');
|
|
5
|
+
const { LimitService } = require('@tryghost/limit-service');
|
|
6
6
|
let limitService = new LimitService();
|
|
7
7
|
|
|
8
8
|
const init = () => {
|
|
@@ -47,6 +47,22 @@ const init = () => {
|
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Route guard for a feature a host can switch off, for the routes that exist only to
|
|
52
|
+
* change it. Answers 403 with the host's own wording, which is a different thing to tell a
|
|
53
|
+
* caller than the 404 a labs flag gives: the feature exists, this plan does not include it.
|
|
54
|
+
*/
|
|
55
|
+
const requireFeature = (limitName) =>
|
|
56
|
+
async function requireFeatureMw(req, res, next) {
|
|
57
|
+
try {
|
|
58
|
+
await limitService.errorIfWouldGoOverLimit(limitName);
|
|
59
|
+
next();
|
|
60
|
+
} catch (err) {
|
|
61
|
+
next(err);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
50
65
|
module.exports = limitService;
|
|
51
66
|
|
|
52
67
|
module.exports.init = init;
|
|
68
|
+
module.exports.requireFeature = requireFeature;
|
|
@@ -898,7 +898,7 @@ class MemberWelcomeEmailServiceWrapper {
|
|
|
898
898
|
}
|
|
899
899
|
|
|
900
900
|
if (!this.i18n) {
|
|
901
|
-
const i18nLib = require('@tryghost/i18n');
|
|
901
|
+
const i18nLib = require('@tryghost/i18n').default;
|
|
902
902
|
const events = require('../../lib/common/events');
|
|
903
903
|
|
|
904
904
|
this.i18n = i18nLib(settingsCache.get('locale') || 'en', 'ghost');
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.makeImporter = makeImporter;
|
|
7
7
|
exports.makeExporter = makeExporter;
|
|
8
|
+
const members_metafields_1 = require("../../members-metafields");
|
|
8
9
|
const importer_1 = __importDefault(require("./import/importer"));
|
|
9
10
|
const reader_1 = __importDefault(require("./import/reader"));
|
|
10
11
|
const spool_1 = require("./import/spool");
|
|
@@ -57,8 +58,8 @@ function makeImporter(deps) {
|
|
|
57
58
|
}),
|
|
58
59
|
};
|
|
59
60
|
const metafields = {
|
|
60
|
-
activeFields: async () => deps.metafields.definitions.browse(),
|
|
61
|
-
planWrite: (values) => deps.metafields.values.planWrite(values),
|
|
61
|
+
activeFields: async () => deps.metafields.definitions.browse({}, members_metafields_1.INTERNAL),
|
|
62
|
+
planWrite: (values) => deps.metafields.values.planWrite(values, members_metafields_1.INTERNAL),
|
|
62
63
|
// Every value the import writes came out of the file, whichever column carried it.
|
|
63
64
|
// An import has no id to give until runs are tracked, so it names its kind only.
|
|
64
65
|
applyWrite: (memberId, plan, executor) => deps.metafields.values.applyWrite(memberId, plan, {
|
|
@@ -121,8 +122,8 @@ function makeExporter({ definitions, values, }) {
|
|
|
121
122
|
metafields: {
|
|
122
123
|
// Boot builds the definitions and values services before this one, so they
|
|
123
124
|
// are always present -- no not-initialised state to guard.
|
|
124
|
-
activeDefinitions: async () => definitions.browse(),
|
|
125
|
-
valuesForMembers: (memberIds) => values.getValuesForMembers(memberIds),
|
|
125
|
+
activeDefinitions: async () => definitions.browse({}, members_metafields_1.INTERNAL),
|
|
126
|
+
valuesForMembers: (memberIds) => values.getValuesForMembers(memberIds, members_metafields_1.INTERNAL),
|
|
126
127
|
},
|
|
127
128
|
});
|
|
128
129
|
return (options = {}) => exporter.export(options);
|
|
@@ -1097,7 +1097,7 @@ module.exports = class RouterController {
|
|
|
1097
1097
|
labels: req.body.labels,
|
|
1098
1098
|
name: req.body.name,
|
|
1099
1099
|
reqIp: req.ip ?? undefined,
|
|
1100
|
-
newsletters: await this._validateNewsletters(req.body?.newsletters
|
|
1100
|
+
newsletters: await this._validateNewsletters(req.body?.newsletters),
|
|
1101
1101
|
attribution: await this._memberAttributionService.getAttribution(req.body.urlHistory),
|
|
1102
1102
|
...(giftToken ? { giftToken } : {}),
|
|
1103
1103
|
};
|
|
@@ -1149,10 +1149,15 @@ module.exports = class RouterController {
|
|
|
1149
1149
|
* @returns {Promise<object[] | undefined>} The validated newsletters
|
|
1150
1150
|
*/
|
|
1151
1151
|
async _validateNewsletters(requestedNewsletters) {
|
|
1152
|
-
if (!requestedNewsletters || requestedNewsletters
|
|
1152
|
+
if (!requestedNewsletters || !Array.isArray(requestedNewsletters)) {
|
|
1153
1153
|
return undefined;
|
|
1154
1154
|
}
|
|
1155
1155
|
|
|
1156
|
+
// An explicit empty list means "no newsletters", not "the defaults"
|
|
1157
|
+
if (requestedNewsletters.length === 0) {
|
|
1158
|
+
return [];
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1156
1161
|
if (requestedNewsletters.some((newsletter) => !newsletter.name)) {
|
|
1157
1162
|
return undefined;
|
|
1158
1163
|
}
|
|
@@ -428,6 +428,8 @@ module.exports = class EventRepository {
|
|
|
428
428
|
delete json.postAttribution?.mobiledoc;
|
|
429
429
|
delete json.postAttribution?.lexical;
|
|
430
430
|
delete json.postAttribution?.plaintext;
|
|
431
|
+
delete json.postAttribution?.auto_excerpt;
|
|
432
|
+
delete json.postAttribution?.reading_time;
|
|
431
433
|
const createdWithStatus = json.signupStatusEvent?.to_status ?? null;
|
|
432
434
|
delete json.signupStatusEvent;
|
|
433
435
|
return {
|
|
@@ -488,6 +490,8 @@ module.exports = class EventRepository {
|
|
|
488
490
|
delete json.postAttribution?.mobiledoc;
|
|
489
491
|
delete json.postAttribution?.lexical;
|
|
490
492
|
delete json.postAttribution?.plaintext;
|
|
493
|
+
delete json.postAttribution?.auto_excerpt;
|
|
494
|
+
delete json.postAttribution?.reading_time;
|
|
491
495
|
return {
|
|
492
496
|
type: 'donation_event',
|
|
493
497
|
data: {
|
|
@@ -95,16 +95,17 @@ module.exports = class MemberBREADService {
|
|
|
95
95
|
* size or a delivery address. Their values live in their own table, so they are fetched
|
|
96
96
|
* here rather than loaded alongside the member.
|
|
97
97
|
*
|
|
98
|
-
* Returns null when
|
|
99
|
-
* `metafields` key off the member payload rather than send an empty object: a key
|
|
100
|
-
* an API response cannot be withdrawn without breaking whoever started reading it,
|
|
101
|
-
* most sites have never defined a field, so those sites keep the payload they had
|
|
102
|
-
* this feature existed.
|
|
98
|
+
* Returns null when this audience has no field to be told about, which tells the caller to
|
|
99
|
+
* leave the `metafields` key off the member payload rather than send an empty object: a key
|
|
100
|
+
* added to an API response cannot be withdrawn without breaking whoever started reading it,
|
|
101
|
+
* and most sites have never defined a field, so those sites keep the payload they had
|
|
102
|
+
* before this feature existed.
|
|
103
103
|
* @param {string[]} memberIds
|
|
104
|
+
* @param {import('../../../members-metafields').Audience} audience
|
|
104
105
|
* @returns {Promise<Map<string, Record<string, unknown>> | null>}
|
|
105
106
|
*/
|
|
106
107
|
async fetchMetafieldValues(memberIds, audience) {
|
|
107
|
-
if (!(await this.metafieldDefinitions.
|
|
108
|
+
if (!(await this.metafieldDefinitions.hasAnyReadable(audience))) {
|
|
108
109
|
return null;
|
|
109
110
|
}
|
|
110
111
|
|
|
@@ -385,15 +386,17 @@ module.exports = class MemberBREADService {
|
|
|
385
386
|
/**
|
|
386
387
|
* @param {object} data
|
|
387
388
|
* @param {object} [options]
|
|
388
|
-
* @param {import('../../../members-metafields').Audience | null}
|
|
389
|
+
* @param {import('../../../members-metafields').Audience | null} options.metafieldsFor
|
|
389
390
|
* Who the extra fields a publisher defined are being read for, or null to leave them
|
|
390
391
|
* off entirely. Null is not the same as "nobody may see them": it means this caller
|
|
391
392
|
* never shows them, so fetching them is two database queries whose results are thrown
|
|
392
393
|
* away. Ghost identifies a signed-in reader on every page view of a themed site
|
|
393
394
|
* through this method, and that caller renders a member through a fixed list of
|
|
394
395
|
* fields which has never included these.
|
|
396
|
+
*
|
|
397
|
+
* Defaults to null, so a caller that does not ask gets none of them.
|
|
395
398
|
*/
|
|
396
|
-
async read(data, { metafieldsFor =
|
|
399
|
+
async read(data, { metafieldsFor = null, ...options } = {}) {
|
|
397
400
|
const defaultWithRelated = [
|
|
398
401
|
'labels',
|
|
399
402
|
'stripeSubscriptions',
|
|
@@ -562,7 +565,7 @@ module.exports = class MemberBREADService {
|
|
|
562
565
|
await this.memberRepository.setComplimentarySubscription(model, sharedOptions);
|
|
563
566
|
}
|
|
564
567
|
|
|
565
|
-
return this.read({ id: model.id }, options);
|
|
568
|
+
return this.read({ id: model.id }, { ...options, metafieldsFor: ADMIN });
|
|
566
569
|
}
|
|
567
570
|
|
|
568
571
|
async edit(data, options) {
|
|
@@ -678,7 +681,7 @@ module.exports = class MemberBREADService {
|
|
|
678
681
|
}
|
|
679
682
|
}
|
|
680
683
|
|
|
681
|
-
return this.read({ id: model.id }, options);
|
|
684
|
+
return this.read({ id: model.id }, { ...options, metafieldsFor: ADMIN });
|
|
682
685
|
}
|
|
683
686
|
|
|
684
687
|
/**
|
|
@@ -710,7 +713,7 @@ module.exports = class MemberBREADService {
|
|
|
710
713
|
);
|
|
711
714
|
}
|
|
712
715
|
|
|
713
|
-
return this.read({ id: memberId });
|
|
716
|
+
return this.read({ id: memberId }, { metafieldsFor: ADMIN });
|
|
714
717
|
}
|
|
715
718
|
|
|
716
719
|
/**
|
|
@@ -732,7 +735,7 @@ module.exports = class MemberBREADService {
|
|
|
732
735
|
|
|
733
736
|
await this.memberRepository.saveCommenting(memberId, updated, 'commenting_enabled', context);
|
|
734
737
|
|
|
735
|
-
return this.read({ id: memberId });
|
|
738
|
+
return this.read({ id: memberId }, { metafieldsFor: ADMIN });
|
|
736
739
|
}
|
|
737
740
|
|
|
738
741
|
async logout(options) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const jose = require('node-jose');
|
|
2
1
|
const jwt = require('jsonwebtoken');
|
|
3
2
|
const crypto = require('crypto');
|
|
3
|
+
const { getPublicKeyInfo } = require('../../../../lib/public-jwk');
|
|
4
4
|
|
|
5
5
|
// A token's `scope` declares its purpose. Only identity tokens may act as a
|
|
6
6
|
// member; entitlement tokens are read-only and handed to integrations.
|
|
@@ -9,24 +9,23 @@ const ENTITLEMENT_TOKEN_SCOPE = 'members:entitlements:read';
|
|
|
9
9
|
|
|
10
10
|
module.exports = class TokenService {
|
|
11
11
|
constructor({ privateKey, publicKey, issuer }) {
|
|
12
|
-
this.
|
|
13
|
-
this._keyStoreReady = this._keyStore.add(privateKey, 'pem');
|
|
12
|
+
this._keyReady = getPublicKeyInfo(privateKey);
|
|
14
13
|
this._privateKey = privateKey;
|
|
15
14
|
this._publicKey = publicKey;
|
|
16
15
|
this._issuer = issuer;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
async encodeIdentityToken({ sub }) {
|
|
20
|
-
const
|
|
19
|
+
const { kid } = await this._keyReady;
|
|
21
20
|
return jwt.sign(
|
|
22
21
|
{
|
|
23
22
|
sub,
|
|
24
|
-
kid
|
|
23
|
+
kid,
|
|
25
24
|
scope: IDENTITY_TOKEN_SCOPE,
|
|
26
25
|
},
|
|
27
26
|
this._privateKey,
|
|
28
27
|
{
|
|
29
|
-
keyid:
|
|
28
|
+
keyid: kid,
|
|
30
29
|
algorithm: 'RS512',
|
|
31
30
|
audience: this._issuer,
|
|
32
31
|
expiresIn: '10m',
|
|
@@ -36,12 +35,12 @@ module.exports = class TokenService {
|
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
async encodeEntitlementToken({ sub, memberUuid, paid, activeTierIds = [] }) {
|
|
39
|
-
const
|
|
38
|
+
const { kid } = await this._keyReady;
|
|
40
39
|
|
|
41
40
|
return jwt.sign(
|
|
42
41
|
{
|
|
43
42
|
sub,
|
|
44
|
-
kid
|
|
43
|
+
kid,
|
|
45
44
|
scope: ENTITLEMENT_TOKEN_SCOPE,
|
|
46
45
|
member_uuid: memberUuid,
|
|
47
46
|
paid,
|
|
@@ -50,7 +49,7 @@ module.exports = class TokenService {
|
|
|
50
49
|
},
|
|
51
50
|
this._privateKey,
|
|
52
51
|
{
|
|
53
|
-
keyid:
|
|
52
|
+
keyid: kid,
|
|
54
53
|
algorithm: 'RS512',
|
|
55
54
|
audience: this._issuer,
|
|
56
55
|
expiresIn: '5m',
|
|
@@ -73,7 +72,7 @@ module.exports = class TokenService {
|
|
|
73
72
|
* @returns {Promise<jwt.JwtPayload>}
|
|
74
73
|
*/
|
|
75
74
|
async decodeToken(token) {
|
|
76
|
-
await this.
|
|
75
|
+
await this._keyReady;
|
|
77
76
|
|
|
78
77
|
const result = jwt.verify(token, this._publicKey, {
|
|
79
78
|
algorithms: ['RS512'],
|
|
@@ -92,7 +91,7 @@ module.exports = class TokenService {
|
|
|
92
91
|
}
|
|
93
92
|
|
|
94
93
|
async getPublicKeys() {
|
|
95
|
-
await this.
|
|
96
|
-
return
|
|
94
|
+
const { kid, jwk } = await this._keyReady;
|
|
95
|
+
return { keys: [{ kty: jwk.kty, kid, n: jwk.n, e: jwk.e }] };
|
|
97
96
|
}
|
|
98
97
|
};
|
|
@@ -12,6 +12,7 @@ const onHeaders = require('on-headers');
|
|
|
12
12
|
const tiersService = require('../tiers/service');
|
|
13
13
|
const config = require('../../../shared/config');
|
|
14
14
|
const settingsHelpers = require('../settings-helpers');
|
|
15
|
+
const { timingSafeStringEqual } = require('../../../shared/timing-safe-string-equal');
|
|
15
16
|
|
|
16
17
|
const messages = {
|
|
17
18
|
missingUuid: 'Missing uuid.',
|
|
@@ -237,13 +238,19 @@ const authMemberByUuid = async function authMemberByUuid(req, res, next) {
|
|
|
237
238
|
.createHmac('sha256', settingsHelpers.getMembersValidationKey())
|
|
238
239
|
.update(uuid)
|
|
239
240
|
.digest('hex');
|
|
240
|
-
if (memberHmac
|
|
241
|
+
if (!timingSafeStringEqual(memberHmac, key)) {
|
|
241
242
|
throw new errors.UnauthorizedError({
|
|
242
243
|
message: tpl(messages.invalidKey),
|
|
243
244
|
});
|
|
244
245
|
}
|
|
245
246
|
|
|
246
|
-
|
|
247
|
+
// Nothing reached through this middleware renders a member's extra fields, so
|
|
248
|
+
// they are not fetched. It authenticates by a signed link rather than a session,
|
|
249
|
+
// which makes anything loaded here readable without being signed in.
|
|
250
|
+
const member = await membersService.api.memberBREADService.read(
|
|
251
|
+
{ uuid },
|
|
252
|
+
{ metafieldsFor: null },
|
|
253
|
+
);
|
|
247
254
|
if (!member) {
|
|
248
255
|
throw new errors.UnauthorizedError({
|
|
249
256
|
message: tpl(messages.invalidUuid),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const crypto = require('crypto');
|
|
2
|
+
const { timingSafeStringEqual } = require('../../../shared/timing-safe-string-equal');
|
|
2
3
|
|
|
3
4
|
class RequestIntegrityTokenProvider {
|
|
4
5
|
#themeSecret;
|
|
@@ -45,7 +46,7 @@ class RequestIntegrityTokenProvider {
|
|
|
45
46
|
hmac.update(`${timestamp.toString()}:${nonce}`);
|
|
46
47
|
const expectedHmac = hmac.digest('hex');
|
|
47
48
|
|
|
48
|
-
if (expectedHmac
|
|
49
|
+
if (!timingSafeStringEqual(expectedHmac, hmacDigest)) {
|
|
49
50
|
// HMAC mismatch
|
|
50
51
|
return false;
|
|
51
52
|
}
|