ghost 6.61.0 → 6.63.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-jobs-0.0.0.tgz +0 -0
- package/components/tryghost-adapter-base-redirects-0.0.0.tgz +0 -0
- package/components/tryghost-adapter-base-route-settings-0.0.0.tgz +0 -0
- 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-checkout-0.0.0.tgz +0 -0
- package/components/tryghost-i18n-0.0.0.tgz +0 -0
- package/components/tryghost-kg-card-factory-5.2.4.tgz +0 -0
- package/components/tryghost-kg-clean-basic-html-4.3.4.tgz +0 -0
- package/components/tryghost-kg-converters-1.2.5.tgz +0 -0
- package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
- package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
- package/components/tryghost-kg-default-transforms-1.3.4.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.0.tgz +0 -0
- package/components/tryghost-kg-markdown-html-renderer-7.2.4.tgz +0 -0
- package/components/tryghost-kg-utils-1.1.4.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/components/tryghost-nql-string-0.0.0.tgz +0 -0
- package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
- package/content/settings/README.md +1 -1
- package/content/themes/casper/.gitignore +28 -0
- package/content/themes/casper/assets/built/casper.js +1 -1
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/css/screen.css +2 -1
- package/content/themes/casper/assets/js/lightbox.js +63 -46
- package/content/themes/casper/package.json +6 -6
- package/content/themes/casper/page.hbs +1 -0
- package/content/themes/casper/post.hbs +1 -0
- package/content/themes/source/.gitignore +28 -0
- package/content/themes/source/assets/built/screen.css +1 -1
- package/content/themes/source/assets/built/source.js +1 -1
- package/content/themes/source/assets/css/screen.css +2 -1
- package/content/themes/source/assets/js/lightbox.js +62 -45
- package/content/themes/source/assets/js/main.js +2 -2
- package/content/themes/source/package.json +4 -4
- package/content/themes/source/partials/feature-image.hbs +1 -0
- package/content/themes/source/partials/post-card.hbs +1 -1
- package/core/boot.js +61 -27
- package/core/built/admin/assets/Combination-B0l4MKVh.js +41 -0
- package/core/built/admin/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
- package/core/built/admin/assets/InterVariable-Italic-FCBEiFp6.woff2 +0 -0
- package/core/built/admin/assets/{about-Bve7IJS2.js → about-C1C3s5-g.js} +1 -1
- package/core/built/admin/assets/accordion-CxGsDKwa.js +1 -0
- package/core/built/admin/assets/account-migration-CbUhW6gk.js +1 -0
- package/core/built/admin/assets/activitypub/{account-migration-C-aej4x_.js → account-migration-KA6Jjf9L.js} +16 -16
- package/core/built/admin/assets/activitypub/activitypub.js +9 -9
- package/core/built/admin/assets/activitypub/{avatar-DLPL3Abs.js → avatar-DVJF5bxP.js} +2 -2
- package/core/built/admin/assets/activitypub/{avatar-flipboard-C9iDY-QV.js → avatar-flipboard-csQaNeYK.js} +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-BXkA5mqV.js → bluesky-sharing-C7nTDMvw.js} +37 -37
- package/core/built/admin/assets/activitypub/{content-formatters-CHcyMFk4.js → content-formatters-CLcjaBwV.js} +4 -4
- package/core/built/admin/assets/activitypub/{copy-DIAOQoCZ.js → copy-DcOh8kXw.js} +2 -2
- package/core/built/admin/assets/activitypub/{domain-B3ihkPde.js → domain-fZ-X8i4-.js} +121 -121
- package/core/built/admin/assets/activitypub/{edit-profile-DsZM3rTX.js → edit-profile-BqMLQV88.js} +40 -40
- package/core/built/admin/assets/activitypub/{explore-BodNrZgR.js → explore-B4yPoP8E.js} +27 -27
- package/core/built/admin/assets/activitypub/{feed-PwH1iJ84.js → feed-BRC_mvAe.js} +51 -51
- package/core/built/admin/assets/activitypub/{field-D06-kmOJ.js → field-COacNgOt.js} +3 -3
- package/core/built/admin/assets/activitypub/{hash-Bm3WxYN4.js → hash-C7u-irQQ.js} +2 -2
- package/core/built/admin/assets/activitypub/inbox-BW-yvUoN.js +1284 -0
- package/core/built/admin/assets/activitypub/{inbox-d8oJRTf4.js → inbox-CbTTdDQ3.js} +2 -2
- package/core/built/admin/assets/activitypub/label-kPMmYI7l.js +16 -0
- package/core/built/admin/assets/activitypub/layout-BL4_jtuV.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-D1Yapsod.js → moderation-CuidJzc0.js} +91 -91
- package/core/built/admin/assets/activitypub/{note-C5zjqq5C.js → note-CAMRRSqD.js} +24 -24
- package/core/built/admin/assets/activitypub/{notifications-B9p8eCHD.js → notifications-BmNlXGgp.js} +51 -51
- package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-Bqg7fh_L.js} +2 -2
- package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-Dmun9jr_.js} +2 -2
- package/core/built/admin/assets/activitypub/{preferences-BCqUdC3v.js → preferences--oH19wf9.js} +1519 -1519
- package/core/built/admin/assets/activitypub/{profile-BRCWoFem.js → profile-DH_tQx2D.js} +185 -185
- package/core/built/admin/assets/activitypub/{reply-DYK5vVqb.js → reply-Cap9PxSH.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-BSXT992i.js → routes-DdyY9uFF.js} +744 -735
- package/core/built/admin/assets/activitypub/{separator-BbQqTm-p.js → separator-CAxxu8VV.js} +3 -3
- package/core/built/admin/assets/activitypub/settings-B6EEcVkW.js +315 -0
- package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-BYps63oh.js} +2 -2
- package/core/built/admin/assets/activitypub/{step-1-B-YfsVeO.js → step-1-CKjR2KAm.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-2-DtPQzlTH.js → step-2-B6PKfOUQ.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-3-D6BFMXL_.js → step-3-C-qBbcUo.js} +11 -11
- package/core/built/admin/assets/activitypub/{tabs-GpNecvfB.js → tabs-DLhZtVde.js} +306 -306
- package/core/built/admin/assets/activitypub/{topic-filter-BPDeQQys.js → topic-filter-DsUOuu0k.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-BoVOxXkV.js → use-activity-pub-queries-CX9snsLs.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Bmk5h4lW.js → use-navigate-with-base-path-DsJTGDSS.js} +988 -959
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-wVBX7swM.js → use-reply-chain-data-AJi9zkzm.js} +30 -30
- package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-inweyKL5.js} +192 -164
- package/core/built/admin/assets/activitypub/{x-DbQZOLiI.js → x-DR8AT3-4.js} +2 -2
- package/core/built/admin/assets/add-integration-modal-BT_onDJy.js +1 -0
- package/core/built/admin/assets/add-newsletter-modal-Cx1kQpiY.js +1 -0
- package/core/built/admin/assets/add-recommendation-modal-B5nvAhvr.js +1 -0
- package/core/built/admin/assets/analytics-DjoJWPI7.js +1 -0
- package/core/built/admin/assets/{announcement-bar-modal-DM3cYOpo.js → announcement-bar-modal-Dwd0EGFP.js} +1 -1
- package/core/built/admin/assets/{api-keys-3-0vJC3Y.js → api-keys-BGPzLHzA.js} +1 -1
- package/core/built/admin/assets/{api-keys-BLm2NDBh.js → api-keys-BoeacM-s.js} +1 -1
- package/core/built/admin/assets/{audience-9mwU5TW6.js → audience-ceV3XVHq.js} +1 -1
- package/core/built/admin/assets/automated-emails-BLesE41L.js +1 -0
- package/core/built/admin/assets/{automations-sAcJ1334.js → automations-BN4u3GR8.js} +1 -1
- package/core/built/admin/assets/automations-C-ZTUwW3.js +1 -0
- package/core/built/admin/assets/bluesky-sharing-vzh-oPXL.js +1 -0
- package/core/built/admin/assets/{breadcrumb-DLiqCyFc.js → breadcrumb-CaLk2b7D.js} +1 -1
- package/core/built/admin/assets/{button-B2jcu6bk.js → button-Dvcv1QSR.js} +1 -1
- package/core/built/admin/assets/calendar-Bl9RLcZX.js +1 -0
- package/core/built/admin/assets/{chart-helpers-Fo3bUL3K.js → chart-helpers-FHywU0pj.js} +1 -1
- package/core/built/admin/assets/{checkbox-BfKktMph.js → checkbox-BtayFtjg.js} +1 -1
- package/core/built/admin/assets/chunk.254.035b85ec456ebbd7336b.js +440 -0
- package/core/built/admin/assets/{chunk.524.60ca4692d91c6022042f.js → chunk.524.e6975095fccdf22d90f8.js} +5 -5
- package/core/built/admin/assets/{chunk.582.525c7617c2d9e94c940a.js → chunk.582.98b485f9b2802f540897.js} +6 -6
- package/core/built/admin/assets/{chunk.492.f24d855d7e3f3aad261c.js → chunk.901.4ccc639821020230bcca.js} +9949 -7921
- package/core/built/admin/assets/{code-editor-view-DCQJxsfU.js → code-editor-view-C3ZfoF1X.js} +1 -1
- package/core/built/admin/assets/{code-editor-view-CYVu4EW6.js → code-editor-view-CAyRWy1s.js} +1 -1
- package/core/built/admin/assets/color-picker-G4kGR7rp.js +3 -0
- package/core/built/admin/assets/color-picker-field-DQFVTNnT.js +1 -0
- package/core/built/admin/assets/combobox-BnYzgEB4.js +1 -0
- package/core/built/admin/assets/command-C_vyTikI.js +1 -0
- package/core/built/admin/assets/comments-aBrxfnZf.js +1 -0
- package/core/built/admin/assets/{config-DOMQDZGZ.js → config-kSHvwdTG.js} +1 -1
- package/core/built/admin/assets/confirmation-context-DwXX_Y5h.js +1 -0
- package/core/built/admin/assets/{content-api-modal-CyQEC3fr.js → content-api-modal-D2G0nJP6.js} +1 -1
- package/core/built/admin/assets/context-menu-DOVB6yaz.js +1 -0
- package/core/built/admin/assets/{copy-field-B3M1s78L.js → copy-field-DCJwh9qf.js} +1 -1
- package/core/built/admin/assets/create-ghost-browse-value-source-5C53jJaX.js +1 -0
- package/core/built/admin/assets/custom-field-type-option-BAuW0F-E.js +1 -0
- package/core/built/admin/assets/custom-integration-modal-AbJGVyKc.js +1 -0
- package/core/built/admin/assets/{date-range-select-DD2RKkgB.js → date-range-select-BY3K-ukj.js} +1 -1
- package/core/built/admin/assets/design-and-theme-modal-BvEy4_pC.js +2 -0
- package/core/built/admin/assets/dirty-confirm-dialog-DVPuGz3U.js +1 -0
- package/core/built/admin/assets/{disabled-sources-indicator-Cvy47bE2.js → disabled-sources-indicator-Cy7Zp4c8.js} +1 -1
- package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
- package/core/built/admin/assets/domain-Dl61QGuk.js +1 -0
- package/core/built/admin/assets/dropzone-Dtz5Rmjt.js +5 -0
- package/core/built/admin/assets/edit-profile-DNJSMDwm.js +1 -0
- package/core/built/admin/assets/editor-DbAen9zf.js +8 -0
- package/core/built/admin/assets/editor-screen-BFWThIai.js +26 -0
- package/core/built/admin/assets/email-sending-status-context-CWDOD1FN.js +1 -0
- package/core/built/admin/assets/email-sending-status-provider-DCPkDICt.js +1 -0
- package/core/built/admin/assets/emails-vFMk4yYl.js +1 -0
- package/core/built/admin/assets/{embed-signup-form-modal-DeBMLxlL.js → embed-signup-form-modal-DGqsORxS.js} +1 -1
- package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
- package/core/built/admin/assets/explore-nnRr1Fja.js +1 -0
- package/core/built/admin/assets/feature-flag-overrides-context-DQjdJFAk.js +1 -0
- package/core/built/admin/assets/feature-image-placeholder-BrIHmPs8.js +1 -0
- package/core/built/admin/assets/feed-BNUcNu-W.js +1 -0
- package/core/built/admin/assets/feedback-DJ4Zb9rZ.js +1 -0
- package/core/built/admin/assets/{field-Cj8lmDOo.js → field-C93_Mg6j.js} +1 -1
- package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
- package/core/built/admin/assets/filter-sources-CGJb4C5r.js +1 -0
- package/core/built/admin/assets/filters--kKP-EC8.js +1 -0
- package/core/built/admin/assets/filters-DxA_a4FP.js +1 -0
- package/core/built/admin/assets/first-promoter-modal-BYDtrz2S.js +1 -0
- package/core/built/admin/assets/focus-koenig-editor-on-bottom-click-BbSnGOtK.js +1 -0
- package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8fd5bb799356bbefb254210ba7e1236d.css} +1 -1
- package/core/built/admin/assets/{ghost-3894eedcc6968f658578c0abfe942aab.js → ghost-b4e8a403baba61905cd7560e30b9732d.js} +63 -44
- package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-cac0cb2d5bb78e9bd14d8d1c2768ed45.css} +1 -1
- package/core/built/admin/assets/gift-link-modal-B7u5bD4e.js +1 -0
- package/core/built/admin/assets/{gift-links-DLDS7ljO.js → gift-links-CfLSnst2.js} +1 -1
- package/core/built/admin/assets/{growth-D6mhcx3q.js → growth-Cd1uO9d2.js} +1 -1
- package/core/built/admin/assets/growth-aG32xfdE.js +3 -0
- package/core/built/admin/assets/history-modal-Df8lW8h-.js +1 -0
- package/core/built/admin/assets/hooks-Cy_-oZ4o.js +2 -0
- package/core/built/admin/assets/{html-field-C8qVGGC1.js → html-field-DA4eU7eq.js} +1 -1
- package/core/built/admin/assets/{images-h8VZEQ9k.js → images-KXmyO3Ss.js} +1 -1
- package/core/built/admin/assets/{inbox-BYd1M06Q.js → inbox-gJHG7_xd.js} +14 -14
- package/core/built/admin/assets/index-BHHXtR5C.css +2 -0
- package/core/built/admin/assets/index-CgMCwsxN.js +4 -0
- package/core/built/admin/assets/index.es-CY6-yuw9.js +1 -0
- package/core/built/admin/assets/{input-group-D8sCXRF5.js → input-group-BE8rM2y1.js} +1 -1
- package/core/built/admin/assets/{integrations-Bjbu86Z0.js → integrations-B4kuRBFY.js} +1 -1
- package/core/built/admin/assets/invite-user-modal-B4CuNcx4.js +1 -0
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
- package/core/built/admin/assets/koenig-lexical/style.css +1 -1
- package/core/built/admin/assets/{koenig-lexical-_-IsVI7E.js → koenig-lexical-CGXb0F8o.js} +3 -3
- package/core/built/admin/assets/koenig-loader-BeM5rFPX.js +2 -0
- package/core/built/admin/assets/{kpi-card-DZQk_0W8.js → kpi-card-B21aToe8.js} +1 -1
- package/core/built/admin/assets/{kpi-card-DW_2y3ug.js → kpi-card-pz6Wv4Ae.js} +1 -1
- package/core/built/admin/assets/{kpi-helpers-PueTKuA6.js → kpi-helpers-Dq5jelmP.js} +1 -1
- package/core/built/admin/assets/{kpi-tabs-CojDs-Qz.js → kpi-tabs-DEZHpKUt.js} +1 -1
- package/core/built/admin/assets/{label-DjbT91GM.js → label-OLCzze8N.js} +1 -1
- package/core/built/admin/assets/label-picker-BigOvMPV.js +1 -0
- package/core/built/admin/assets/{labels-CH3Kn8RV.js → labels-Dr0SgUQD.js} +1 -1
- package/core/built/admin/assets/layout-DUTL8SH5.js +1 -0
- package/core/built/admin/assets/lib-7QPTI0FS.js +1 -0
- package/core/built/admin/assets/link-helpers-BRAg9SCj.js +1 -0
- package/core/built/admin/assets/links-BDHPTlyj.js +1 -0
- package/core/built/admin/assets/member-custom-fields-TRTHCAz9.js +1 -0
- package/core/built/admin/assets/member-detail-b6dRwc3C.js +1 -0
- package/core/built/admin/assets/members-Czt5lJSc.js +4 -0
- package/core/built/admin/assets/moderation-ZWefD9uH.js +1 -0
- package/core/built/admin/assets/{multi-select-combobox-B6LiRzDO.js → multi-select-combobox-CT13MTo-.js} +1 -1
- package/core/built/admin/assets/navigation-modal-C8FEhBK5.js +1 -0
- package/core/built/admin/assets/newsletter-5VYW4RyJ.js +1 -0
- package/core/built/admin/assets/newsletter-detail-modal-ChjC0ZqH.js +1 -0
- package/core/built/admin/assets/{newsletter-emails-CFeLlt4z.js → newsletter-emails-DZH6I-PY.js} +1 -1
- package/core/built/admin/assets/newsletters-DOC9KBcX.js +1 -0
- package/core/built/admin/assets/newsletters-Rq1M3GD-.js +1 -0
- package/core/built/admin/assets/note-DIV-Pojr.js +1 -0
- package/core/built/admin/assets/notifications-s20-H49V.js +1 -0
- package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
- package/core/built/admin/assets/{offers-9J1CSiLy.js → offers--e2nGvkW.js} +1 -1
- package/core/built/admin/assets/offers-container-modal-BmG5M5Tv.js +1 -0
- package/core/built/admin/assets/onboarding-CUuy9unR.js +1 -0
- package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-pXyct0Jm.js} +1 -1
- package/core/built/admin/assets/{onboarding-route-Dmc4IPm3.js → onboarding-route-CK4pcXoR.js} +1 -1
- package/core/built/admin/assets/overview-CaPsciMs.js +1 -0
- package/core/built/admin/assets/overview-a8GfcsKX.js +1 -0
- package/core/built/admin/assets/{page-header-BR_nbIPp.js → page-header-DM_KyoFI.js} +1 -1
- package/core/built/admin/assets/pagemenu-vgZVUVKR.js +1 -0
- package/core/built/admin/assets/pages-CjDY2CBI.js +1 -0
- package/core/built/admin/assets/pages-route-BzKZYdV5.js +1 -0
- package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
- package/core/built/admin/assets/{pintura-modal-BR9hEvS8.js → pintura-modal-DExCF1ii.js} +1 -1
- package/core/built/admin/assets/portal-frame-Cqanidq4.js +1 -0
- package/core/built/admin/assets/portal-modal-oinBgA27.js +1 -0
- package/core/built/admin/assets/post-analytics-C5oJ1dWV.js +1 -0
- package/core/built/admin/assets/post-analytics-header-OATo3X_r.js +1 -0
- package/core/built/admin/assets/post-analytics-provider-tOpIVGT5.js +1 -0
- package/core/built/admin/assets/post-helpers-C88JBa4D.js +1 -0
- package/core/built/admin/assets/post-share-modal-DvhC1XgV.js +1 -0
- package/core/built/admin/assets/post-utils-DKF4mfuo.js +1 -0
- package/core/built/admin/assets/posts-list-screen-o4ZjbgS3.js +2 -0
- package/core/built/admin/assets/posts-pCPrhQeR.js +1 -0
- package/core/built/admin/assets/posts-route-9F--xdIb.js +1 -0
- package/core/built/admin/assets/preferences--vNubsqD.js +5 -0
- package/core/built/admin/assets/{preview-modal-C-BL-F9k.js → preview-modal-YYbzlYdO.js} +1 -1
- package/core/built/admin/assets/profile-BllKV3dR.js +1 -0
- package/core/built/admin/assets/{radio-group-Bgz60i81.js → radio-group-DL8GI8rt.js} +1 -1
- package/core/built/admin/assets/{referrers-CnhCMWCs.js → referrers-D8oHPmDB.js} +1 -1
- package/core/built/admin/assets/router-provider-BSvTXgZY.js +1 -0
- package/core/built/admin/assets/schemas-BoYdB6YU.js +64 -0
- package/core/built/admin/assets/select-v5YbA3Mw.js +1 -0
- package/core/built/admin/assets/settings-PEsZupw1.js +4 -0
- package/core/built/admin/assets/{settings-breadcrumbs-CyP_9zTo.js → settings-breadcrumbs-NwPnCTC7.js} +1 -1
- package/core/built/admin/assets/settings-u_s1CRkr.js +1 -0
- package/core/built/admin/assets/share-modal-SskCmVGL.js +1 -0
- package/core/built/admin/assets/slack-modal-XxSJiYgo.js +1 -0
- package/core/built/admin/assets/{sort-button-Cc-Z96sA.js → sort-button-Cx1KtINE.js} +1 -1
- package/core/built/admin/assets/{source-icon-v6PUnmyM.js → source-icon-Bdp9Im_5.js} +1 -1
- package/core/built/admin/assets/stats-D9PDLS3x.js +1 -0
- package/core/built/admin/assets/stats-view-W2g6Jsd-.js +1 -0
- package/core/built/admin/assets/{step-1-DSRp2vBj.js → step-1-BQYzvBzr.js} +1 -1
- package/core/built/admin/assets/{step-2-COqv2g0u.js → step-2-xES32xJV.js} +1 -1
- package/core/built/admin/assets/{step-3-6W1NMVQc.js → step-3-DA_XK5kW.js} +2 -2
- package/core/built/admin/assets/{stripe-button-D2K42Uty.js → stripe-button-CVsLHelt.js} +1 -1
- package/core/built/admin/assets/stripe-connect-modal-ClmLOMGS.js +1 -0
- package/core/built/admin/assets/style-Wd9nQubI.css +1 -0
- package/core/built/admin/assets/{table-B2pIKjVh.js → table-BenqVupI.js} +1 -1
- package/core/built/admin/assets/{tabs-SaW_UT-Q.js → tabs-eBBlxPp8.js} +1 -1
- package/core/built/admin/assets/tag-detail-Ce8Se2qd.js +2 -0
- package/core/built/admin/assets/tag-picker-C3UR-uJ-.js +1 -0
- package/core/built/admin/assets/tags-B-kJxCs7.js +1 -0
- package/core/built/admin/assets/{tags-zTFiKRpb.js → tags-ChfdwJyS.js} +1 -1
- package/core/built/admin/assets/testimonials-modal-9Q6fT06V.js +1 -0
- package/core/built/admin/assets/tier-detail-modal-CDyYdqK7.js +1 -0
- package/core/built/admin/assets/tiers-BCpIOGQr.js +1 -0
- package/core/built/admin/assets/{toggle-group-EM9WpESu.js → toggle-group-CviIkyok.js} +1 -1
- package/core/built/admin/assets/{topic-filter-DY4gNHn2.js → topic-filter-I2jCBGxm.js} +1 -1
- package/core/built/admin/assets/{transistor-modal-CpyPG-MH.js → transistor-modal-p53u3W8y.js} +1 -1
- package/core/built/admin/assets/{trend-badge-ByMkuAuH.js → trend-badge-CideVzQd.js} +1 -1
- package/core/built/admin/assets/{unsplash-modal-Cv2Q6GtY.js → unsplash-modal-DY8UcKcE.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data-CHvjMYuT.js → use-analytics-data-DAIGcr2f.js} +1 -1
- package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
- package/core/built/admin/assets/{use-check-theme-limit-error-Qv4SVXqw.js → use-check-theme-limit-error-DRUjK4YM.js} +1 -1
- package/core/built/admin/assets/use-filter-params-JkZhIS8L.js +1 -0
- package/core/built/admin/assets/{use-filterable-api-CzXcpUh8.js → use-filterable-api-BVEVMrhZ.js} +1 -1
- package/core/built/admin/assets/use-growth-stats-937CUj6j.js +1 -0
- package/core/built/admin/assets/use-host-limits-D0Dv3tKA.js +1 -0
- package/core/built/admin/assets/{use-limiter-cwJvsNBo.js → use-limiter-CohWfzvK.js} +1 -1
- package/core/built/admin/assets/{use-navigate-with-base-path-BHPA228f.js → use-navigate-with-base-path-BkxcPj5l.js} +1 -1
- package/core/built/admin/assets/use-pintura-config-xgytjU35.js +1 -0
- package/core/built/admin/assets/{use-pintura-editor-BDBXWUYq.js → use-pintura-editor-CaV1mbfO.js} +1 -1
- package/core/built/admin/assets/{use-post-referrers-DbY-mzci.js → use-post-referrers-BCQI7fDg.js} +1 -1
- package/core/built/admin/assets/use-reply-chain-data-CYRhoaxY.js +1 -0
- package/core/built/admin/assets/{use-router-history-entry-Bg6BhBQQ.js → use-router-history-entry-NOKcd--l.js} +1 -1
- package/core/built/admin/assets/{use-setting-group-VM7FQwMY.js → use-setting-group-bLKMwoBT.js} +1 -1
- package/core/built/admin/assets/use-settings-navigation-B-qrriKD.js +1 -0
- package/core/built/admin/assets/{use-simple-pagination-Dum6Irbs.js → use-simple-pagination-CNPd6Rf6.js} +1 -1
- package/core/built/admin/assets/use-staff-users-pRIMIyiW.js +1 -0
- package/core/built/admin/assets/use-tinybird-query-CmdbCS9X.js +1 -0
- package/core/built/admin/assets/use-tinybird-token-KLne235s.js +1 -0
- package/core/built/admin/assets/{use-unsaved-changes-guard-BAy0RANR.js → use-unsaved-changes-guard-7-ug0JdH.js} +1 -1
- package/core/built/admin/assets/use-upgrade-route-Dm_qqKr0.js +1 -0
- package/core/built/admin/assets/{use-url-input-Df5QzNa7.js → use-url-input-fvp-TpPx.js} +1 -1
- package/core/built/admin/assets/user-detail-modal-D3KlGYv-.js +1 -0
- package/core/built/admin/assets/users-DVNWrqg9.js +1 -0
- package/core/built/admin/assets/{vendor-5753232c7d6ffb3c44e1eb0a02133953.js → vendor-2dd263291938d407802568d3357ec69e.js} +19 -17
- package/core/built/admin/assets/{virtual-list-DEx8WgiO.js → virtual-list-CZ3RK2Yf.js} +1 -1
- package/core/built/admin/assets/web-ClEJsCAj.js +2 -0
- package/core/built/admin/assets/web-X9rdnrtq.js +1 -0
- package/core/built/admin/assets/{zapier-modal-Cw3BTBUu.js → zapier-modal-DfVhV17j.js} +1 -1
- package/core/built/admin/index.html +23 -27
- package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
- package/core/frontend/helpers/cancel_link.js +2 -2
- package/core/frontend/helpers/pagination.js +2 -2
- package/core/frontend/helpers/social_accounts.js +2 -2
- package/core/frontend/public/ghost.css +1 -1
- package/core/frontend/public/ghost.min.css +1 -1
- package/core/frontend/services/sitemap/user-map-generator.js +9 -2
- package/core/server/adapters/jobs/InMemoryJobsBackend.js +74 -29
- package/core/server/api/endpoints/authentication.js +1 -2
- package/core/server/api/endpoints/authors-public.js +15 -5
- package/core/server/api/endpoints/emails.js +13 -0
- package/core/server/api/endpoints/index.js +10 -2
- package/core/server/api/endpoints/mail.js +1 -1
- package/core/server/api/endpoints/member-metafields-members.js +23 -0
- package/core/server/api/endpoints/member-metafields.js +102 -0
- package/core/server/api/endpoints/members-account.js +42 -0
- package/core/server/api/endpoints/members.js +4 -4
- package/core/server/api/endpoints/newsletters-public.js +10 -1
- package/core/server/api/endpoints/pages-public.js +15 -5
- package/core/server/api/endpoints/posts-public.js +15 -5
- package/core/server/api/endpoints/posts.js +3 -3
- package/core/server/api/endpoints/tags-public.js +22 -3
- package/core/server/api/endpoints/tiers-checkout-config.js +2 -2
- package/core/server/api/endpoints/tiers-public.js +38 -1
- package/core/server/api/endpoints/users.js +2 -2
- package/core/server/api/endpoints/utils/api-filter-utils.js +170 -3
- package/core/server/api/endpoints/utils/public-cache-keys.js +3 -0
- package/core/server/api/endpoints/utils/serializers/input/authors.js +2 -0
- package/core/server/api/endpoints/utils/serializers/input/members.js +20 -9
- package/core/server/api/endpoints/utils/serializers/input/pages.js +2 -0
- package/core/server/api/endpoints/utils/serializers/input/posts.js +2 -0
- package/core/server/api/endpoints/utils/serializers/input/tags.js +2 -0
- package/core/server/api/endpoints/utils/serializers/output/emails.js +7 -0
- package/core/server/api/endpoints/utils/serializers/output/index.js +6 -2
- package/core/server/api/endpoints/utils/serializers/output/member-metafields.js +18 -0
- package/core/server/api/endpoints/utils/serializers/output/members-account.js +19 -0
- package/core/server/api/endpoints/utils/serializers/output/members-csv-transform.js +1 -1
- package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
- package/core/server/api/endpoints/utils/serializers/output/tiers.js +10 -2
- package/core/server/api/endpoints/utils/serializers/output/users.js +0 -10
- package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
- package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
- package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
- package/core/server/data/exporter/table-lists.js +3 -3
- package/core/server/data/importer/importers/data/data-importer.js +3 -3
- package/core/server/data/migrations/utils/migrations.js +1 -1
- package/core/server/data/migrations/versions/6.53/2026-07-15-20-22-53-add-members-custom-field-values.js +1 -1
- package/core/server/data/migrations/versions/6.57/2026-08-04-18-00-00-store-custom-field-values-as-leaf-rows.js +10 -1
- package/core/server/data/migrations/versions/6.63/2026-09-03-10-07-03-rename-custom-field-tables-to-metafields.js +169 -0
- package/core/server/data/migrations/versions/6.63/2026-09-03-11-03-31-remove-member-custom-field-read-permissions.js +30 -0
- package/core/server/data/schema/fixtures/fixtures.json +0 -11
- package/core/server/data/schema/lib/default-index-name.js +8 -11
- package/core/server/data/schema/schema.js +18 -18
- package/core/server/data/seeders/README.md +48 -0
- package/core/server/data/tinybird/pipes/mv_hits.pipe +86 -50
- package/core/server/lib/db-types/count.js +16 -0
- package/core/server/lib/image/image-size.js +24 -0
- package/core/server/lib/package-json/parse.js +2 -2
- package/core/server/lib/validate-password.js +81 -120
- package/core/server/models/action.js +4 -4
- package/core/server/models/base/plugins/filtered-collection.js +16 -0
- package/core/server/models/member.js +10 -21
- package/core/server/models/post.js +2 -2
- package/core/server/models/relations/authors.js +2 -16
- package/core/server/models/user.js +10 -3
- package/core/server/services/auth/passwordreset.js +13 -0
- package/core/server/services/automations/automations-api.js +1 -1
- package/core/server/services/automations/database-automations-repository.js +11 -4
- package/core/server/services/comments/comments-controller.js +30 -9
- package/core/server/services/comments/comments-service.js +55 -5
- package/core/server/services/content-import/csv/formula.js +12 -0
- package/core/server/services/content-import/csv/index.js +6 -1
- package/core/server/services/content-import/csv/parse.js +27 -6
- package/core/server/services/content-import/csv/serialize.js +13 -0
- package/core/server/services/content-import/import/completion-email.js +164 -0
- package/core/server/services/content-import/import/errors-file.js +36 -0
- package/core/server/services/content-import/import/importer.js +160 -53
- package/core/server/services/content-import/import/local-media-url.js +63 -0
- package/core/server/services/content-import/import/media.js +254 -0
- package/core/server/services/content-import/import/post-data.js +0 -1
- package/core/server/services/content-import/import/post-link.js +11 -0
- package/core/server/services/content-import/import/post-repository.js +25 -3
- package/core/server/services/content-import/import/reader.js +9 -2
- package/core/server/services/content-import/import/report.js +34 -0
- package/core/server/services/content-import/import/row.js +0 -2
- package/core/server/services/content-import/import/schema.js +1 -0
- package/core/server/services/content-import/import/staged-file.js +29 -0
- package/core/server/services/content-import/import/store.js +25 -2
- package/core/server/services/content-import/index.js +52 -6
- package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
- package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
- package/core/server/services/custom-redirects/redirects-service.js +1 -1
- package/core/server/services/custom-redirects/validation.js +1 -1
- package/core/server/services/email-address/email-address-parser.js +30 -38
- package/core/server/services/email-address/email-address-service.js +37 -4
- package/core/server/services/email-analytics/index.js +2 -7
- package/core/server/services/email-service/CONTEXT.md +37 -0
- package/core/server/services/email-service/README.md +42 -0
- package/core/server/services/email-service/batch-sending-service.js +2 -4
- package/core/server/services/email-service/email-controller.js +18 -2
- package/core/server/services/email-service/email-renderer.js +14 -4
- package/core/server/services/email-service/email-service-wrapper.js +3 -9
- package/core/server/services/email-service/mailgun-email-provider.js +20 -9
- package/core/server/services/email-service/sending-status-schema.js +21 -0
- package/core/server/services/email-service/sending-status-serializers.js +33 -0
- package/core/server/services/email-service/sending-status-service.js +47 -0
- package/core/server/services/email-service/sending-status.js +111 -0
- package/core/server/services/email-suppression-list/email-suppression-list.js +0 -33
- package/core/server/services/email-suppression-list/mailgun-email-suppression-list.js +6 -7
- package/core/server/services/gifts/README.md +2 -2
- package/core/server/services/gifts/constants.js +1 -1
- package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
- package/core/server/services/gifts/gift-email-service.js +0 -1
- package/core/server/services/gifts/gift-service.js +19 -57
- package/core/server/services/gifts/index.js +3 -5
- package/core/server/services/gifts/jobs/index.js +4 -4
- package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
- package/core/server/services/invitations/accept.js +4 -2
- package/core/server/services/jobs/job-service.js +0 -9
- package/core/server/services/jobs-service/index.js +8 -0
- package/core/server/services/jobs-service/jobs-service.js +52 -3
- package/core/server/services/jobs-service/register-job-handlers.js +32 -11
- package/core/server/services/mail/ghost-mailer.js +4 -4
- package/core/server/services/member-welcome-emails/service.js +7 -7
- package/core/server/services/members/account-service.js +98 -0
- package/core/server/services/members/api.js +4 -3
- package/core/server/services/members/import-export/csv/parse.js +0 -7
- package/core/server/services/members/import-export/export/exporter.js +20 -20
- package/core/server/services/members/import-export/import/completion-email.js +8 -11
- package/core/server/services/members/import-export/import/importer.js +13 -13
- package/core/server/services/members/import-export/import/row.js +0 -3
- package/core/server/services/members/import-export/index.js +10 -17
- package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
- package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
- package/core/server/services/members/jobs/index.js +48 -24
- package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
- package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
- package/core/server/services/members/members-api/members-api.js +26 -8
- package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
- package/core/server/services/members/members-api/repositories/member-repository.js +4 -4
- package/core/server/services/members/members-api/services/member-bread-service.js +62 -84
- package/core/server/services/members/members-api/services/payments-service.js +1 -1
- package/core/server/services/members/members-ssr.js +18 -0
- package/core/server/services/members/middleware.js +95 -81
- package/core/server/services/members/service.js +71 -47
- package/core/server/services/members/utils.js +9 -0
- package/core/server/services/members-metafields/access.js +28 -0
- package/core/server/services/{members-custom-fields → members-metafields}/actions.js +5 -5
- package/core/server/services/members-metafields/bindings-service.js +147 -0
- package/core/server/services/members-metafields/codec.js +14 -0
- package/core/server/services/{members-custom-fields → members-metafields}/config.js +1 -1
- package/core/server/services/{members-custom-fields → members-metafields}/definitions-service.js +68 -22
- package/core/server/services/members-metafields/filter.js +181 -0
- package/core/server/services/{members-custom-fields → members-metafields}/index.js +16 -7
- package/core/server/services/{members-custom-fields → members-metafields}/key.js +2 -1
- package/core/server/services/{members-custom-fields → members-metafields}/models.js +5 -5
- package/core/server/services/members-metafields/namespaces.js +34 -0
- package/core/server/services/{members-custom-fields → members-metafields}/queries.js +1 -1
- package/core/server/services/{members-custom-fields → members-metafields}/schema.js +16 -12
- package/core/server/services/members-metafields/serializers.js +22 -0
- package/core/server/services/{members-custom-fields → members-metafields}/values-service.js +80 -48
- package/core/server/services/mentions/mention-controller.js +23 -21
- package/core/server/services/mentions/mention-sending-service.js +26 -9
- package/core/server/services/mentions/process-webmention-job.js +16 -0
- package/core/server/services/mentions/send-webmentions-job.js +18 -0
- package/core/server/services/mentions/service.js +7 -33
- package/core/server/services/route-settings/validation-errors.js +1 -1
- package/core/server/services/route-settings/yaml-parser.js +1 -1
- package/core/server/services/settings/settings-service.js +1 -8
- package/core/server/services/settings-helpers/settings-helpers.js +4 -6
- package/core/server/services/slack-ping/slack-ping-service.js +1 -1
- package/core/server/services/staff/staff-service-emails.js +2 -2
- package/core/server/services/stripe/config.js +14 -8
- package/core/server/services/stripe/service.js +10 -1
- package/core/server/services/stripe/services/checkout/completed-session.js +2 -2
- package/core/server/services/stripe/services/checkout/session-options.js +18 -15
- package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +28 -7
- package/core/server/services/stripe/stripe-api.js +2 -0
- package/core/server/services/stripe/stripe-service.js +24 -14
- package/core/server/services/stripe/webhook-controller.js +10 -0
- package/core/server/services/tier-checkout-config/codec.js +11 -7
- package/core/server/services/tier-checkout-config/index.js +2 -1
- package/core/server/services/tier-checkout-config/models.js +11 -5
- package/core/server/services/tier-checkout-config/queries.js +12 -12
- package/core/server/services/tier-checkout-config/serializers.js +73 -10
- package/core/server/services/tier-checkout-config/service.js +14 -13
- package/core/server/services/tiers/service.js +3 -3
- package/core/server/services/update-check/index.js +13 -13
- package/core/server/services/update-check/jobs/update-check-job.js +7 -0
- package/core/server/services/update-check/update-check-service.js +2 -2
- package/core/server/services/url/router-filter.js +8 -10
- package/core/server/services/users.js +1 -19
- package/core/server/web/admin/controller.js +1 -1
- package/core/server/web/api/endpoints/admin/routes.js +20 -16
- package/core/server/web/members/account/index.js +2 -0
- package/core/server/web/members/account/routes.js +46 -0
- package/core/server/web/members/app.js +4 -18
- package/core/shared/config/defaults.json +1 -1
- package/core/shared/config/env/config.testing-mysql.json +1 -1
- package/core/shared/labs.js +7 -2
- package/package.json +42 -41
- package/pnpm-lock.yaml +1159 -582
- package/pnpm-workspace.yaml +18 -15
- package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
- package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
- package/core/built/admin/assets/Combination-5fYEzgbs.js +0 -41
- package/core/built/admin/assets/account-migration-DRhAehfw.js +0 -1
- package/core/built/admin/assets/activitypub/inbox-BluD2ucT.js +0 -1284
- package/core/built/admin/assets/activitypub/label-FHSh6ZAw.js +0 -16
- package/core/built/admin/assets/activitypub/layout-Cq4NG0Xr.js +0 -1
- package/core/built/admin/assets/activitypub/settings-DQDkr06X.js +0 -315
- package/core/built/admin/assets/add-integration-modal-BC0jExDZ.js +0 -1
- package/core/built/admin/assets/add-newsletter-modal-DchTkA7l.js +0 -1
- package/core/built/admin/assets/add-recommendation-modal-DMvaJZKp.js +0 -1
- package/core/built/admin/assets/alert-dialog-QhXzdHfc.js +0 -1
- package/core/built/admin/assets/analytics-No1DDY3A.js +0 -1
- package/core/built/admin/assets/automated-emails-te1D5kq-.js +0 -1
- package/core/built/admin/assets/automations-DpUNUdcZ.js +0 -1
- package/core/built/admin/assets/bluesky-sharing-Cjrv_f62.js +0 -1
- package/core/built/admin/assets/chunk.896.435fe0637944d4a69810.js +0 -366
- package/core/built/admin/assets/color-picker-BTY_NdEm.js +0 -3
- package/core/built/admin/assets/color-picker-field-CPlkzOH0.js +0 -1
- package/core/built/admin/assets/combobox-DrMtv_4P.js +0 -1
- package/core/built/admin/assets/command-ZdgYJpoI.js +0 -1
- package/core/built/admin/assets/comments-kidj60-h.js +0 -1
- package/core/built/admin/assets/confirmation-context-BhbmQQEl.js +0 -1
- package/core/built/admin/assets/custom-field-type-option-CsGIZk1J.js +0 -10
- package/core/built/admin/assets/custom-integration-modal-BY37O_9X.js +0 -1
- package/core/built/admin/assets/design-and-theme-modal-DUSKM4uC.js +0 -22
- package/core/built/admin/assets/dialog-B44iRwlc.js +0 -1
- package/core/built/admin/assets/dirty-confirm-dialog-BxgQgQ6H.js +0 -1
- package/core/built/admin/assets/dist-Cy8tfrp_.js +0 -1
- package/core/built/admin/assets/domain-Ca6KhoQt.js +0 -1
- package/core/built/admin/assets/dropzone-Bb-5zQTk.js +0 -5
- package/core/built/admin/assets/edit-profile-BdupLlus.js +0 -1
- package/core/built/admin/assets/editor-BP883Lpn.js +0 -8
- package/core/built/admin/assets/explore-FB-CimXw.js +0 -1
- package/core/built/admin/assets/feed-C1GxsmI2.js +0 -1
- package/core/built/admin/assets/filter-sources-D5n5bFA2.js +0 -1
- package/core/built/admin/assets/filters-DJEzkMUK.js +0 -1
- package/core/built/admin/assets/filters-MZXvdH5D.js +0 -1
- package/core/built/admin/assets/first-promoter-modal-CGTGLCr5.js +0 -1
- package/core/built/admin/assets/gift-link-modal-B6v0tnRN.js +0 -1
- package/core/built/admin/assets/growth-BGAJD1rs.js +0 -3
- package/core/built/admin/assets/history-modal-iKwUY3XR.js +0 -1
- package/core/built/admin/assets/hooks-CuEZV2-q.js +0 -2
- package/core/built/admin/assets/index-DjQe-e5s.js +0 -4
- package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
- package/core/built/admin/assets/index.es-VihPwfeH.js +0 -1
- package/core/built/admin/assets/input--W-rCTrX.js +0 -1
- package/core/built/admin/assets/invite-user-modal-MdImLCaJ.js +0 -1
- package/core/built/admin/assets/koenig-loader-DYZpm6El.js +0 -2
- package/core/built/admin/assets/label-picker-cB51xl1r.js +0 -1
- package/core/built/admin/assets/layout-c_B_1hax.js +0 -1
- package/core/built/admin/assets/link-helpers-MVDdnFCY.js +0 -1
- package/core/built/admin/assets/loading-indicator-BpFWTVgh.js +0 -1
- package/core/built/admin/assets/member-custom-fields-qs0dIkxM.js +0 -1
- package/core/built/admin/assets/member-detail-B6uec2a6.js +0 -1
- package/core/built/admin/assets/members-BQF3CqhI.js +0 -2
- package/core/built/admin/assets/moderation-DY4wF1Q3.js +0 -1
- package/core/built/admin/assets/navigation-modal-DX-gNF3X.js +0 -1
- package/core/built/admin/assets/newsletter-CyQA7m3m.js +0 -1
- package/core/built/admin/assets/newsletter-detail-modal-BDrptuxn.js +0 -1
- package/core/built/admin/assets/newsletters-DXuNmC42.js +0 -1
- package/core/built/admin/assets/newsletters-DhNigJUh.js +0 -1
- package/core/built/admin/assets/note-Cgo2LCJ6.js +0 -1
- package/core/built/admin/assets/notifications-BC50AMku.js +0 -1
- package/core/built/admin/assets/offers-container-modal-DWycIMzT.js +0 -1
- package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
- package/core/built/admin/assets/overview-CVbFtn-k.js +0 -1
- package/core/built/admin/assets/overview-YKj7SZaK.js +0 -1
- package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
- package/core/built/admin/assets/popover-CCy0h5rq.js +0 -1
- package/core/built/admin/assets/portal-frame-dc4XKr0e.js +0 -1
- package/core/built/admin/assets/portal-modal-BvvdF_B9.js +0 -1
- package/core/built/admin/assets/post-analytics-DX470WRG.js +0 -1
- package/core/built/admin/assets/post-analytics-header-CXpJmdDv.js +0 -1
- package/core/built/admin/assets/post-analytics-provider-CLfKGWZy.js +0 -1
- package/core/built/admin/assets/post-helpers-C5OQMBoi.js +0 -1
- package/core/built/admin/assets/post-share-modal-Cl0NXRJr.js +0 -1
- package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
- package/core/built/admin/assets/preferences-DO0UUWFp.js +0 -5
- package/core/built/admin/assets/profile-CxT-0l4d.js +0 -1
- package/core/built/admin/assets/router-provider-B0gZyiGJ.js +0 -1
- package/core/built/admin/assets/schemas-4UPic-oD.js +0 -64
- package/core/built/admin/assets/select-DuDUFdPq.js +0 -1
- package/core/built/admin/assets/settings-BjCii7BM.js +0 -1
- package/core/built/admin/assets/settings-b8kNzZSQ.js +0 -4
- package/core/built/admin/assets/share-modal-BV70mr9k.js +0 -1
- package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
- package/core/built/admin/assets/slack-modal-Be2_KK-z.js +0 -1
- package/core/built/admin/assets/stats-C4reGh9O.js +0 -1
- package/core/built/admin/assets/stats-view-DP9pQ62k.js +0 -1
- package/core/built/admin/assets/stripe-connect-modal-Z-UT_BGc.js +0 -1
- package/core/built/admin/assets/tag-detail-Dc0nTOtU.js +0 -2
- package/core/built/admin/assets/tags-BLaXBwnb.js +0 -1
- package/core/built/admin/assets/testimonials-modal-sFwRnNLh.js +0 -1
- package/core/built/admin/assets/tier-detail-modal-BCFpWwUS.js +0 -1
- package/core/built/admin/assets/tiers-Nd_z4BZY.js +0 -1
- package/core/built/admin/assets/use-filter-params-CAvfDvf1.js +0 -1
- package/core/built/admin/assets/use-growth-stats-D6mZXGhK.js +0 -1
- package/core/built/admin/assets/use-host-limits-DZtR08oa.js +0 -1
- package/core/built/admin/assets/use-pintura-config-CzTfnufz.js +0 -1
- package/core/built/admin/assets/use-reply-chain-data-BeQwz8oF.js +0 -1
- package/core/built/admin/assets/use-settings-navigation-BbrSUVcf.js +0 -1
- package/core/built/admin/assets/use-staff-users-cZg4ugOF.js +0 -1
- package/core/built/admin/assets/use-tinybird-query-B1IMyAcv.js +0 -39
- package/core/built/admin/assets/use-tinybird-token-Bow0Zwn8.js +0 -1
- package/core/built/admin/assets/use-upgrade-route-DhRSo7at.js +0 -1
- package/core/built/admin/assets/user-detail-modal-yipSoQfv.js +0 -1
- package/core/built/admin/assets/users-5msE1WMs.js +0 -1
- package/core/built/admin/assets/web-CKcXAu86.js +0 -1
- package/core/built/admin/assets/web-DR4TqM3E.js +0 -2
- package/core/server/api/endpoints/member-custom-fields.js +0 -90
- package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +0 -20
- package/core/server/services/email-suppression-list/in-memory-email-suppression-list.js +0 -39
- package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
- package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
- package/core/server/services/members-custom-fields/bindings-service.js +0 -119
- package/core/server/services/members-custom-fields/codec.js +0 -15
- package/core/server/services/members-custom-fields/filter.js +0 -199
- package/core/server/services/members-custom-fields/serializers.js +0 -24
- package/core/server/services/stripe/services/checkout/allowed-countries.js +0 -267
- package/core/server/services/stripe/services/checkout/field-ports.js +0 -34
- package/core/server/services/tier-checkout-config/destinations.js +0 -17
- package/core/server/services/update-check/run-update-check.js +0 -63
- /package/core/built/admin/assets/{chunk.492.f24d855d7e3f3aad261c.js.LICENSE.txt → chunk.901.4ccc639821020230bcca.js.LICENSE.txt} +0 -0
- /package/core/server/services/{members-custom-fields → members-metafields}/storage.js +0 -0
|
@@ -6,7 +6,7 @@ const limitService = require('../services/limits');
|
|
|
6
6
|
const tpl = require('@tryghost/tpl');
|
|
7
7
|
const errors = require('@tryghost/errors');
|
|
8
8
|
const security = require('@tryghost/security');
|
|
9
|
-
const validatePassword = require('../lib/validate-password');
|
|
9
|
+
const { validatePassword } = require('../lib/validate-password');
|
|
10
10
|
const permissions = require('../services/permissions');
|
|
11
11
|
const urlUtils = require('../../shared/url-utils').default;
|
|
12
12
|
const { setIsRoles } = require('./role-utils');
|
|
@@ -43,8 +43,13 @@ const messages = {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* inactive
|
|
47
|
-
*
|
|
46
|
+
* `inactive`: suspended staff, who cannot sign in or reset their password.
|
|
47
|
+
* Also used for the initial owner before site setup is complete.
|
|
48
|
+
* `locked`: users whose password was randomized by an import or authentication
|
|
49
|
+
* reset. They must reset their password to regain access.
|
|
50
|
+
*
|
|
51
|
+
* Both statuses prevent normal sign-in, so they are grouped here. This is not
|
|
52
|
+
* a suspension check: isInactive() checks only the literal `inactive` status.
|
|
48
53
|
*/
|
|
49
54
|
const inactiveStates = ['inactive', 'locked'];
|
|
50
55
|
|
|
@@ -212,6 +217,8 @@ User = ghostBookshelf.Model.extend(
|
|
|
212
217
|
return this.save(update, { ...options, patch: true });
|
|
213
218
|
},
|
|
214
219
|
|
|
220
|
+
// Checks the literal status, not membership in inactiveStates: locked users
|
|
221
|
+
// must remain eligible for password resets.
|
|
215
222
|
isInactive: function isInactive() {
|
|
216
223
|
return this.get('status') === 'inactive';
|
|
217
224
|
},
|
|
@@ -11,6 +11,7 @@ const mail = require('../mail');
|
|
|
11
11
|
|
|
12
12
|
const messages = {
|
|
13
13
|
userNotFound: 'User not found.',
|
|
14
|
+
userSuspended: 'This account has been suspended.',
|
|
14
15
|
resetPassword: 'Reset Password',
|
|
15
16
|
expired: {
|
|
16
17
|
message: 'Cannot reset password.',
|
|
@@ -46,6 +47,14 @@ function generateToken(email, settingsAPI, transaction) {
|
|
|
46
47
|
throw new errors.NotFoundError({ message: tpl(messages.userNotFound) });
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
// Prevent suspended users from generating a reset token. This same check must appear
|
|
51
|
+
// below in doReset() to account for password reset tokens that were generated prior
|
|
52
|
+
// to suspension since they have a 24-hour lifetime.
|
|
53
|
+
// Locked users must still be able to recover access by resetting their password.
|
|
54
|
+
if (user.isInactive()) {
|
|
55
|
+
throw new errors.NoPermissionError({ message: tpl(messages.userSuspended) });
|
|
56
|
+
}
|
|
57
|
+
|
|
49
58
|
token = security.tokens.resetToken.generateHash({
|
|
50
59
|
expires: moment().add(1, 'days').valueOf(),
|
|
51
60
|
email: email,
|
|
@@ -128,6 +137,10 @@ function doReset(options, tokenParts, settingsAPI) {
|
|
|
128
137
|
}
|
|
129
138
|
}
|
|
130
139
|
|
|
140
|
+
if (user.isInactive()) {
|
|
141
|
+
throw new errors.NoPermissionError({ message: tpl(messages.userSuspended) });
|
|
142
|
+
}
|
|
143
|
+
|
|
131
144
|
const updatedUser = await models.User.changePassword(
|
|
132
145
|
{
|
|
133
146
|
oldPassword: oldPassword,
|
|
@@ -78,7 +78,7 @@ const repository = (0, database_automations_repository_1.createDatabaseAutomatio
|
|
|
78
78
|
fakeWaitHoursMultiplier: (0, fake_wait_hours_multiplier_1.parseFakeWaitHoursMultiplier)(config.get('automations:fakeWaitHoursMultiplier')),
|
|
79
79
|
});
|
|
80
80
|
async function browse() {
|
|
81
|
-
return await repository.browse();
|
|
81
|
+
return await repository.browse({ includeStats: true });
|
|
82
82
|
}
|
|
83
83
|
async function read(automationId) {
|
|
84
84
|
const automation = await repository.getById(automationId);
|
|
@@ -35,14 +35,16 @@ const messages = {
|
|
|
35
35
|
const DEFAULT_EMAIL_DESIGN_SETTING_REFERENCE = constants_1.DEFAULT_EMAIL_DESIGN_SETTING_SLUG;
|
|
36
36
|
function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier, }) {
|
|
37
37
|
return {
|
|
38
|
-
async browse() {
|
|
38
|
+
async browse({ includeStats }) {
|
|
39
39
|
return await knex.transaction(async (trx) => {
|
|
40
40
|
await ensureDefaultAutomations(trx);
|
|
41
|
-
const
|
|
41
|
+
const data = includeStats
|
|
42
|
+
? (await loadAutomationsWithStats(trx)).map((row) => buildAutomationBrowseResult(row))
|
|
43
|
+
: (await loadAutomations(trx)).map((row) => buildAutomationSummary(row));
|
|
42
44
|
return {
|
|
43
|
-
data
|
|
45
|
+
data,
|
|
44
46
|
meta: {
|
|
45
|
-
pagination: buildPagination(
|
|
47
|
+
pagination: buildPagination(data.length),
|
|
46
48
|
},
|
|
47
49
|
};
|
|
48
50
|
});
|
|
@@ -671,6 +673,11 @@ async function loadAutomationBySlug(trx, slug) {
|
|
|
671
673
|
return row ?? null;
|
|
672
674
|
}
|
|
673
675
|
async function loadAutomations(trx) {
|
|
676
|
+
return await trx('automations')
|
|
677
|
+
.select('id', 'slug', 'name', 'status', 'created_at', 'updated_at')
|
|
678
|
+
.orderBy('name');
|
|
679
|
+
}
|
|
680
|
+
async function loadAutomationsWithStats(trx) {
|
|
674
681
|
const inProgressRuns = trx('automation_run_steps')
|
|
675
682
|
.distinct('automation_run_id')
|
|
676
683
|
.where('status', 'pending')
|
|
@@ -14,6 +14,7 @@ const messages = {
|
|
|
14
14
|
cannotDestroyComments: 'You cannot destroy comments.',
|
|
15
15
|
memberNotFound: 'Unable to find member',
|
|
16
16
|
unsupportedReportCountFilter: 'Unsupported count.reports filter',
|
|
17
|
+
errorParsingFilter: 'Error parsing filter',
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
module.exports = class CommentsController {
|
|
@@ -26,6 +27,16 @@ module.exports = class CommentsController {
|
|
|
26
27
|
this.stats = stats;
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
#getPostIdFromFilter(query) {
|
|
31
|
+
if (typeof query.post_id === 'string') {
|
|
32
|
+
return query.post_id;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Only equality conditions required by an AND can scope a legacy browse.
|
|
36
|
+
// Choosing an ID from an OR or an exclusion would authorize the wrong posts.
|
|
37
|
+
return query.$and?.map((part) => this.#getPostIdFromFilter(part)).find(Boolean);
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
#withPostFilter(options) {
|
|
30
41
|
const nextOptions = { ...options };
|
|
31
42
|
|
|
@@ -138,7 +149,17 @@ module.exports = class CommentsController {
|
|
|
138
149
|
* @param {Frame} frame
|
|
139
150
|
*/
|
|
140
151
|
async browse(frame) {
|
|
141
|
-
|
|
152
|
+
const options = { ...frame.options };
|
|
153
|
+
if (!options.post_id && options.filter) {
|
|
154
|
+
let query;
|
|
155
|
+
try {
|
|
156
|
+
query = nql(options.filter).parse();
|
|
157
|
+
} catch (err) {
|
|
158
|
+
throw new errors.BadRequestError({ message: tpl(messages.errorParsingFilter), err });
|
|
159
|
+
}
|
|
160
|
+
options.post_id = this.#getPostIdFromFilter(query);
|
|
161
|
+
}
|
|
162
|
+
return await this.service.getComments(this.#withPostFilter(options));
|
|
142
163
|
}
|
|
143
164
|
|
|
144
165
|
async adminBrowse(frame) {
|
|
@@ -345,14 +366,14 @@ module.exports = class CommentsController {
|
|
|
345
366
|
async like(frame) {
|
|
346
367
|
this.#checkMember(frame);
|
|
347
368
|
|
|
369
|
+
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
370
|
+
|
|
348
371
|
const result = await this.service.likeComment(
|
|
349
372
|
frame.options.id,
|
|
350
373
|
frame.options?.context?.member,
|
|
351
374
|
frame.options,
|
|
352
375
|
);
|
|
353
376
|
|
|
354
|
-
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
355
|
-
|
|
356
377
|
this.setCacheInvalidationHeaders(comment, frame);
|
|
357
378
|
|
|
358
379
|
return result;
|
|
@@ -364,14 +385,14 @@ module.exports = class CommentsController {
|
|
|
364
385
|
async unlike(frame) {
|
|
365
386
|
this.#checkMember(frame);
|
|
366
387
|
|
|
388
|
+
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
389
|
+
|
|
367
390
|
const result = await this.service.unlikeComment(
|
|
368
391
|
frame.options.id,
|
|
369
392
|
frame.options?.context?.member,
|
|
370
393
|
frame.options,
|
|
371
394
|
);
|
|
372
395
|
|
|
373
|
-
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
374
|
-
|
|
375
396
|
this.setCacheInvalidationHeaders(comment, frame);
|
|
376
397
|
|
|
377
398
|
return result;
|
|
@@ -420,14 +441,14 @@ module.exports = class CommentsController {
|
|
|
420
441
|
async dislike(frame) {
|
|
421
442
|
this.#checkMember(frame);
|
|
422
443
|
|
|
444
|
+
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
445
|
+
|
|
423
446
|
const result = await this.service.dislikeComment(
|
|
424
447
|
frame.options.id,
|
|
425
448
|
frame.options?.context?.member,
|
|
426
449
|
frame.options,
|
|
427
450
|
);
|
|
428
451
|
|
|
429
|
-
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
430
|
-
|
|
431
452
|
this.setCacheInvalidationHeaders(comment, frame);
|
|
432
453
|
|
|
433
454
|
return result;
|
|
@@ -439,14 +460,14 @@ module.exports = class CommentsController {
|
|
|
439
460
|
async undislike(frame) {
|
|
440
461
|
this.#checkMember(frame);
|
|
441
462
|
|
|
463
|
+
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
464
|
+
|
|
442
465
|
const result = await this.service.undislikeComment(
|
|
443
466
|
frame.options.id,
|
|
444
467
|
frame.options?.context?.member,
|
|
445
468
|
frame.options,
|
|
446
469
|
);
|
|
447
470
|
|
|
448
|
-
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
449
|
-
|
|
450
471
|
this.setCacheInvalidationHeaders(comment, frame);
|
|
451
472
|
|
|
452
473
|
return result;
|
|
@@ -13,7 +13,9 @@ const messages = {
|
|
|
13
13
|
alreadyDisliked: 'This comment was disliked already',
|
|
14
14
|
replyToReply: 'Can not reply to a reply',
|
|
15
15
|
commentsNotEnabled: 'Comments are not enabled for this site.',
|
|
16
|
+
postIdRequired: 'A post ID is required to read comments.',
|
|
16
17
|
cannotCommentOnPost: 'You do not have permission to comment on this post.',
|
|
18
|
+
cannotReadComment: 'You do not have permission to read comments on this post',
|
|
17
19
|
cannotEditComment: 'You do not have permission to edit comments',
|
|
18
20
|
cannotPinReply: 'Replies cannot be pinned',
|
|
19
21
|
cannotPinDeletedComment: 'Deleted comments cannot be pinned',
|
|
@@ -39,7 +41,7 @@ const COMMENT_STATUSES_IN_REPLY_TO = [COMMENT_STATUS_PUBLISHED, COMMENT_STATUS_H
|
|
|
39
41
|
// new `comment.get(...)` call has one obvious place to register its column.
|
|
40
42
|
const REPLY_PARENT_REQUIRED_COLUMNS = ['parent_id', 'post_id'];
|
|
41
43
|
const IN_REPLY_TO_REQUIRED_COLUMNS = ['parent_id'];
|
|
42
|
-
const OWNERSHIP_REQUIRED_COLUMNS = ['member_id'];
|
|
44
|
+
const OWNERSHIP_REQUIRED_COLUMNS = ['member_id', 'post_id'];
|
|
43
45
|
const REPORT_REQUIRED_COLUMNS = ['post_id', 'member_id', 'html', 'created_at'];
|
|
44
46
|
|
|
45
47
|
function getColumnList(columns) {
|
|
@@ -167,11 +169,14 @@ class CommentsService {
|
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
/** @private */
|
|
170
|
-
checkPostAccess(postModel, memberModel) {
|
|
171
|
-
const access = this.contentGating.checkPostAccess(
|
|
172
|
+
checkPostAccess(postModel, memberModel, { action = 'comment' } = {}) {
|
|
173
|
+
const access = this.contentGating.checkPostAccess(
|
|
174
|
+
postModel.toJSON(),
|
|
175
|
+
memberModel ? memberModel.toJSON() : null,
|
|
176
|
+
);
|
|
172
177
|
if (access === this.contentGating.BLOCK_ACCESS) {
|
|
173
178
|
throw new errors.NoPermissionError({
|
|
174
|
-
message: tpl(messages.cannotCommentOnPost),
|
|
179
|
+
message: tpl(action === 'read' ? messages.cannotReadComment : messages.cannotCommentOnPost),
|
|
175
180
|
});
|
|
176
181
|
}
|
|
177
182
|
}
|
|
@@ -189,6 +194,32 @@ class CommentsService {
|
|
|
189
194
|
});
|
|
190
195
|
}
|
|
191
196
|
|
|
197
|
+
async #checkPostAccessForRead(postId, options) {
|
|
198
|
+
if (options.isAdmin) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!postId) {
|
|
203
|
+
throw new errors.ValidationError({ message: tpl(messages.postIdRequired) });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const postModel = await this.models.Post.findOne(
|
|
207
|
+
{ id: postId },
|
|
208
|
+
{ require: true, transacting: options.transacting, withRelated: ['tiers'] },
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
let memberModel = null;
|
|
212
|
+
const memberId = options.context?.member?.id;
|
|
213
|
+
if (memberId) {
|
|
214
|
+
memberModel = await this.models.Member.findOne(
|
|
215
|
+
{ id: memberId },
|
|
216
|
+
{ require: true, transacting: options.transacting, withRelated: ['products'] },
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.checkPostAccess(postModel, memberModel, { action: 'read' });
|
|
221
|
+
}
|
|
222
|
+
|
|
192
223
|
/**
|
|
193
224
|
* Primary comment lookup: a single keyed fetch with the allowed statuses
|
|
194
225
|
* applied in the query (`WHERE id = ? AND status IN (...)`), optionally locked
|
|
@@ -520,6 +551,7 @@ class CommentsService {
|
|
|
520
551
|
*/
|
|
521
552
|
async getComments(options) {
|
|
522
553
|
this.checkEnabled();
|
|
554
|
+
await this.#checkPostAccessForRead(options.post_id, options);
|
|
523
555
|
const page = await this.models.Comment.findPage(
|
|
524
556
|
withPinnedSelect({ ...options, parentId: null, pinnedFirst: true }),
|
|
525
557
|
);
|
|
@@ -659,6 +691,17 @@ class CommentsService {
|
|
|
659
691
|
*/
|
|
660
692
|
async getReplies(id, options, { includeHidden = false } = {}) {
|
|
661
693
|
this.checkEnabled();
|
|
694
|
+
|
|
695
|
+
const parentComment = await this.#fetchCommentByID(id, options, {
|
|
696
|
+
requiredColumns: ['post_id'],
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
if (!parentComment) {
|
|
700
|
+
throw new errors.NotFoundError({ message: tpl(messages.commentNotFound) });
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
await this.#checkPostAccessForRead(parentComment.get('post_id'), options);
|
|
704
|
+
|
|
662
705
|
const page = await this.models.Comment.findPage(
|
|
663
706
|
withPinnedSelect({ ...options, parentId: id }, { includeHidden }),
|
|
664
707
|
);
|
|
@@ -740,7 +783,9 @@ class CommentsService {
|
|
|
740
783
|
async getCommentByID(id, options = {}) {
|
|
741
784
|
this.checkEnabled();
|
|
742
785
|
|
|
743
|
-
|
|
786
|
+
const model = await this.#getReadableCommentByID(id, options, ['post_id']);
|
|
787
|
+
await this.#checkPostAccessForRead(model.get('post_id'), options);
|
|
788
|
+
return model;
|
|
744
789
|
}
|
|
745
790
|
|
|
746
791
|
/**
|
|
@@ -908,6 +953,9 @@ class CommentsService {
|
|
|
908
953
|
});
|
|
909
954
|
}
|
|
910
955
|
|
|
956
|
+
// Mutation responses include replies, so they require the same post access as reads.
|
|
957
|
+
await this.#checkPostAccessForRead(existingComment.get('post_id'), options);
|
|
958
|
+
|
|
911
959
|
const model = await this.models.Comment.edit(
|
|
912
960
|
{
|
|
913
961
|
status: COMMENT_STATUS_DELETED,
|
|
@@ -943,6 +991,8 @@ class CommentsService {
|
|
|
943
991
|
});
|
|
944
992
|
}
|
|
945
993
|
|
|
994
|
+
await this.#checkPostAccessForRead(existingComment.get('post_id'), options);
|
|
995
|
+
|
|
946
996
|
if (!comment) {
|
|
947
997
|
return existingComment;
|
|
948
998
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripFormulaGuard = stripFormulaGuard;
|
|
4
|
+
const FORMULA_TRIGGERS = ['=', '+', '-', '@', '\t', '\r'];
|
|
5
|
+
// Report files prefix formula-shaped cells with an apostrophe. Remove exactly
|
|
6
|
+
// that guard during re-import so repeated fixes do not change publisher data.
|
|
7
|
+
function stripFormulaGuard(cell) {
|
|
8
|
+
if (cell.charAt(0) === "'" && FORMULA_TRIGGERS.includes(cell.charAt(1))) {
|
|
9
|
+
return cell.slice(1);
|
|
10
|
+
}
|
|
11
|
+
return cell;
|
|
12
|
+
}
|
|
@@ -3,6 +3,11 @@ 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.parse = void 0;
|
|
6
|
+
exports.stripFormulaGuard = exports.serialize = exports.parseWithSource = exports.parse = void 0;
|
|
7
7
|
var parse_1 = require("./parse");
|
|
8
8
|
Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return __importDefault(parse_1).default; } });
|
|
9
|
+
Object.defineProperty(exports, "parseWithSource", { enumerable: true, get: function () { return parse_1.parseWithSource; } });
|
|
10
|
+
var serialize_1 = require("./serialize");
|
|
11
|
+
Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return __importDefault(serialize_1).default; } });
|
|
12
|
+
var formula_1 = require("./formula");
|
|
13
|
+
Object.defineProperty(exports, "stripFormulaGuard", { enumerable: true, get: function () { return formula_1.stripFormulaGuard; } });
|
|
@@ -4,8 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.default = parse;
|
|
7
|
+
exports.parseWithSource = parseWithSource;
|
|
7
8
|
const papaparse_1 = __importDefault(require("papaparse"));
|
|
8
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const formula_1 = require("./formula");
|
|
9
11
|
const errors = require('@tryghost/errors');
|
|
10
12
|
// A column named after an Object.prototype member is unsafe as a key.
|
|
11
13
|
function isSafeColumnName(name) {
|
|
@@ -17,44 +19,63 @@ function isSafeColumnName(name) {
|
|
|
17
19
|
function isFatal(error) {
|
|
18
20
|
return error.type === 'Quotes';
|
|
19
21
|
}
|
|
22
|
+
function isEmptyRow(row) {
|
|
23
|
+
return !Object.values(row).some((value) => {
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return value.some((cell) => typeof cell === 'string' && cell.trim().length > 0);
|
|
26
|
+
}
|
|
27
|
+
return value.trim().length > 0;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
20
30
|
// headerMapping renames headers to the columns they emit under; unmapped columns
|
|
21
31
|
// carry through, and one mapped to an empty target is dropped.
|
|
22
32
|
async function parse(path, headerMapping) {
|
|
33
|
+
const parsed = await parseWithSource(path, headerMapping);
|
|
34
|
+
return parsed.rows.map(({ data }) => data);
|
|
35
|
+
}
|
|
36
|
+
async function parseWithSource(path, headerMapping) {
|
|
23
37
|
// Buffered rather than streamed: files are bounded by the interim row cap, and
|
|
24
38
|
// papaparse's stream mode drops results.errors, which is what catches a
|
|
25
39
|
// malformed quoted field before it imports as garbage.
|
|
26
40
|
const content = (await fs_extra_1.default.readFile(path, 'utf8')).replace(/^\ufeff/, '');
|
|
27
41
|
const parsed = papaparse_1.default.parse(content, {
|
|
28
42
|
header: true,
|
|
29
|
-
|
|
43
|
+
// Empty records stay in the parser output long enough to contribute to the
|
|
44
|
+
// publisher-visible spreadsheet line number, then are dropped below.
|
|
45
|
+
skipEmptyLines: false,
|
|
30
46
|
});
|
|
31
47
|
const fatal = parsed.errors.find(isFatal);
|
|
32
48
|
if (fatal) {
|
|
33
49
|
throw new errors.ValidationError({ message: `${fatal.code}: ${fatal.message}` });
|
|
34
50
|
}
|
|
35
51
|
const rows = [];
|
|
36
|
-
for (const parsedRow of parsed.data) {
|
|
52
|
+
for (const [index, parsedRow] of parsed.data.entries()) {
|
|
53
|
+
if (isEmptyRow(parsedRow)) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
37
56
|
const row = {};
|
|
57
|
+
const source = Object.create(null);
|
|
38
58
|
for (const [header, value] of Object.entries(parsedRow)) {
|
|
39
59
|
// non-string values are papaparse's __parsed_extra overflow from ragged rows
|
|
40
60
|
if (typeof value !== 'string') {
|
|
41
61
|
continue;
|
|
42
62
|
}
|
|
63
|
+
source[header] = value;
|
|
43
64
|
// hasOwn: a prototype-named header must not match an inherited method on the mapping
|
|
44
65
|
if (headerMapping && Object.hasOwn(headerMapping, header)) {
|
|
45
66
|
if (!headerMapping[header]) {
|
|
46
67
|
continue;
|
|
47
68
|
}
|
|
48
|
-
row[headerMapping[header]] = value;
|
|
69
|
+
row[headerMapping[header]] = (0, formula_1.stripFormulaGuard)(value);
|
|
49
70
|
}
|
|
50
71
|
else if (isSafeColumnName(header)) {
|
|
51
|
-
row[header] = value;
|
|
72
|
+
row[header] = (0, formula_1.stripFormulaGuard)(value);
|
|
52
73
|
}
|
|
53
74
|
}
|
|
54
75
|
if (!Object.keys(row).length) {
|
|
55
76
|
continue;
|
|
56
77
|
}
|
|
57
|
-
rows.push(row);
|
|
78
|
+
rows.push({ data: row, source, line: index + 2 });
|
|
58
79
|
}
|
|
59
|
-
return rows;
|
|
80
|
+
return { columns: parsed.meta.fields ?? [], rows };
|
|
60
81
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = serialize;
|
|
7
|
+
const papaparse_1 = __importDefault(require("papaparse"));
|
|
8
|
+
// Import reports are opened in spreadsheets, so formula-shaped cells must never
|
|
9
|
+
// be emitted verbatim. Papa Parse prefixes them with an apostrophe when this
|
|
10
|
+
// option is enabled.
|
|
11
|
+
function serialize(rows, { columns, header = true } = {}) {
|
|
12
|
+
return papaparse_1.default.unparse(rows, { columns, header, escapeFormulae: true });
|
|
13
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = buildCompletionEmail;
|
|
7
|
+
const report_1 = __importDefault(require("./report"));
|
|
8
|
+
const errors_file_1 = __importDefault(require("./errors-file"));
|
|
9
|
+
const { slugify } = require('@tryghost/string');
|
|
10
|
+
const IMPORTED_POST_PREVIEW_LIMIT = 10;
|
|
11
|
+
function escapeHTML(value) {
|
|
12
|
+
return value
|
|
13
|
+
.replace(/&/g, '&')
|
|
14
|
+
.replace(/</g, '<')
|
|
15
|
+
.replace(/>/g, '>')
|
|
16
|
+
.replace(/"/g, '"')
|
|
17
|
+
.replace(/'/g, ''');
|
|
18
|
+
}
|
|
19
|
+
function countsFor(run) {
|
|
20
|
+
const counts = {
|
|
21
|
+
created: 0,
|
|
22
|
+
updated: 0,
|
|
23
|
+
skipped: 0,
|
|
24
|
+
failed: 0,
|
|
25
|
+
warningRows: 0,
|
|
26
|
+
};
|
|
27
|
+
for (const row of run.rows) {
|
|
28
|
+
counts[row.status] += 1;
|
|
29
|
+
if (row.warnings?.length) {
|
|
30
|
+
counts.warningRows += 1;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return counts;
|
|
34
|
+
}
|
|
35
|
+
function headingFor(run, counts) {
|
|
36
|
+
if (run.status === 'failed') {
|
|
37
|
+
return 'Your content import could not be completed';
|
|
38
|
+
}
|
|
39
|
+
if (counts.failed > 0 && counts.created + counts.updated === 0) {
|
|
40
|
+
return 'Your content import was unsuccessful';
|
|
41
|
+
}
|
|
42
|
+
return 'Your content import is complete';
|
|
43
|
+
}
|
|
44
|
+
function formatNumber(value) {
|
|
45
|
+
return value.toLocaleString();
|
|
46
|
+
}
|
|
47
|
+
function summaryItems(counts, hasErrorsFile) {
|
|
48
|
+
const items = [
|
|
49
|
+
['Created', counts.created],
|
|
50
|
+
['Updated', counts.updated],
|
|
51
|
+
['Skipped', counts.skipped],
|
|
52
|
+
['Failed', counts.failed],
|
|
53
|
+
];
|
|
54
|
+
return items
|
|
55
|
+
.map(([label, count]) => {
|
|
56
|
+
const attachmentCopy = label === 'Failed' && hasErrorsFile ? ' (see attached errors.csv)' : '';
|
|
57
|
+
return `<li style="margin-bottom: 6px;"><strong>${label}:</strong> ${formatNumber(count)}${attachmentCopy}</li>`;
|
|
58
|
+
})
|
|
59
|
+
.join('');
|
|
60
|
+
}
|
|
61
|
+
function importTagSlug(runId) {
|
|
62
|
+
// Internal tag slugs replace the leading # with "hash-" in the model layer.
|
|
63
|
+
return slugify(`#Import Run ${runId}`.replace(/^#/, 'hash-'));
|
|
64
|
+
}
|
|
65
|
+
function importedPostLinks(run, adminUrl) {
|
|
66
|
+
const importedRows = run.rows.filter((row) => row.status === 'created' || row.status === 'updated');
|
|
67
|
+
if (!importedRows.length) {
|
|
68
|
+
return '';
|
|
69
|
+
}
|
|
70
|
+
const rows = importedRows.filter((row) => row.url);
|
|
71
|
+
const previewRows = rows.slice(0, IMPORTED_POST_PREVIEW_LIMIT);
|
|
72
|
+
const hasPages = importedRows.some((row) => row.postType === 'page');
|
|
73
|
+
const hasPosts = importedRows.some((row) => row.postType !== 'page');
|
|
74
|
+
const links = previewRows
|
|
75
|
+
.map((row) => {
|
|
76
|
+
const title = escapeHTML(row.title || `Row ${row.line}`);
|
|
77
|
+
return `<li style="margin-bottom: 6px;"><a href="${escapeHTML(row.url)}" style="color: #3A464C;">${title}</a></li>`;
|
|
78
|
+
})
|
|
79
|
+
.join('');
|
|
80
|
+
const remaining = importedRows.length - previewRows.length;
|
|
81
|
+
const remainingCopy = remaining
|
|
82
|
+
? `<p style="font-size: 16px; line-height: 25px; color: #3A464C;">Including ${formatNumber(remaining)} more.</p>`
|
|
83
|
+
: '';
|
|
84
|
+
const tag = encodeURIComponent(importTagSlug(run.id));
|
|
85
|
+
const postsUrl = escapeHTML(new URL(`#/posts?tag=${tag}`, adminUrl).href);
|
|
86
|
+
const pagesUrl = escapeHTML(new URL(`#/pages?tag=${tag}`, adminUrl).href);
|
|
87
|
+
let heading = 'Imported posts';
|
|
88
|
+
if (hasPages) {
|
|
89
|
+
heading = hasPosts ? 'Imported posts and pages' : 'Imported pages';
|
|
90
|
+
}
|
|
91
|
+
const filteredLinks = [
|
|
92
|
+
hasPosts ? `<a href="${postsUrl}" style="color: #3A464C;">View imported posts</a>` : '',
|
|
93
|
+
hasPages ? `<a href="${pagesUrl}" style="color: #3A464C;">View imported pages</a>` : '',
|
|
94
|
+
]
|
|
95
|
+
.filter(Boolean)
|
|
96
|
+
.join(' · ');
|
|
97
|
+
const preview = links
|
|
98
|
+
? `<ul style="font-size: 16px; line-height: 25px; color: #3A464C; padding-left: 24px;">${links}</ul>`
|
|
99
|
+
: '';
|
|
100
|
+
return `<h2 style="color: #15212A; font-size: 18px; line-height: 24px; margin: 32px 0 12px;">${heading}</h2>
|
|
101
|
+
${preview}
|
|
102
|
+
${remainingCopy}
|
|
103
|
+
<p style="font-size: 16px; line-height: 25px; color: #3A464C;">${filteredLinks}</p>`;
|
|
104
|
+
}
|
|
105
|
+
function renderCompletionEmail(run, recipient, adminUrl, hasErrorsFile) {
|
|
106
|
+
const counts = countsFor(run);
|
|
107
|
+
const heading = headingFor(run, counts);
|
|
108
|
+
const warningCopy = counts.warningRows
|
|
109
|
+
? `<p style="font-size: 16px; line-height: 25px; color: #3A464C;"><strong>${formatNumber(counts.warningRows)}</strong> ${counts.warningRows === 1 ? 'post has' : 'posts have'} warnings.</p>`
|
|
110
|
+
: '';
|
|
111
|
+
const failureCopy = run.status === 'failed'
|
|
112
|
+
? '<p style="font-size: 16px; line-height: 25px; color: #3A464C;">Something went wrong on our end before the import could finish. There is nothing wrong with your file, and it is safe to try again.</p>'
|
|
113
|
+
: '';
|
|
114
|
+
const escapedRecipient = escapeHTML(recipient);
|
|
115
|
+
return `<!doctype html>
|
|
116
|
+
<html>
|
|
117
|
+
<head>
|
|
118
|
+
<meta name="viewport" content="width=device-width">
|
|
119
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
120
|
+
<title>${heading}</title>
|
|
121
|
+
</head>
|
|
122
|
+
<body style="background-color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; color: #3A464C; margin: 0; padding: 0;">
|
|
123
|
+
<div style="box-sizing: border-box; margin: 0 auto; max-width: 540px; padding: 40px 20px;">
|
|
124
|
+
<img src="https://static.ghost.org/v4.0.0/images/ghost-orb-4.png" width="60" height="60" alt="Ghost" style="display: block; margin: 0 auto 40px;" />
|
|
125
|
+
<h1 style="color: #15212A; font-size: 21px; line-height: 25px; margin: 0 0 24px;">${heading}</h1>
|
|
126
|
+
${failureCopy}
|
|
127
|
+
<p style="font-size: 16px; line-height: 25px; color: #3A464C;">The import processed ${formatNumber(run.total)} ${run.total === 1 ? 'row' : 'rows'}:</p>
|
|
128
|
+
<ul style="font-size: 16px; line-height: 25px; color: #3A464C; padding-left: 24px;">${summaryItems(counts, hasErrorsFile)}</ul>
|
|
129
|
+
${warningCopy}
|
|
130
|
+
${importedPostLinks(run, adminUrl)}
|
|
131
|
+
<p style="color: #738A94; font-size: 11px; line-height: 18px; margin-top: 64px;">This email was sent to <a href="mailto:${escapedRecipient}" style="color: #738A94;">${escapedRecipient}</a>.</p>
|
|
132
|
+
</div>
|
|
133
|
+
</body>
|
|
134
|
+
</html>`;
|
|
135
|
+
}
|
|
136
|
+
function buildCompletionEmail(run, recipient, adminUrl) {
|
|
137
|
+
const counts = countsFor(run);
|
|
138
|
+
const report = (0, report_1.default)(run);
|
|
139
|
+
const errorsFile = (0, errors_file_1.default)(run);
|
|
140
|
+
const attachments = [];
|
|
141
|
+
if (report) {
|
|
142
|
+
attachments.push({
|
|
143
|
+
filename: 'report.csv',
|
|
144
|
+
content: report,
|
|
145
|
+
contentType: 'text/csv',
|
|
146
|
+
contentDisposition: 'attachment',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (errorsFile) {
|
|
150
|
+
attachments.push({
|
|
151
|
+
filename: 'errors.csv',
|
|
152
|
+
content: errorsFile,
|
|
153
|
+
contentType: 'text/csv',
|
|
154
|
+
contentDisposition: 'attachment',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
to: recipient,
|
|
159
|
+
subject: headingFor(run, counts),
|
|
160
|
+
html: renderCompletionEmail(run, recipient, adminUrl, Boolean(errorsFile)),
|
|
161
|
+
forceTextContent: true,
|
|
162
|
+
attachments,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = buildErrorsFile;
|
|
4
|
+
const csv_1 = require("../csv");
|
|
5
|
+
const ANNOTATION_NAMES = ['import_status', 'import_reason', 'import_media_failures'];
|
|
6
|
+
function isActionable(row) {
|
|
7
|
+
return Boolean(row.source) && row.status === 'failed';
|
|
8
|
+
}
|
|
9
|
+
function uniqueColumnName(preferred, used) {
|
|
10
|
+
let candidate = preferred;
|
|
11
|
+
let suffix = 2;
|
|
12
|
+
while (used.has(candidate)) {
|
|
13
|
+
candidate = `${preferred}_${suffix}`;
|
|
14
|
+
suffix += 1;
|
|
15
|
+
}
|
|
16
|
+
used.add(candidate);
|
|
17
|
+
return candidate;
|
|
18
|
+
}
|
|
19
|
+
function buildErrorsFile(run) {
|
|
20
|
+
const rows = run.rows.filter(isActionable);
|
|
21
|
+
if (!rows.length) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const usedColumns = new Set(run.sourceColumns);
|
|
25
|
+
const [outcomeColumn, reasonColumn, mediaFailuresColumn] = ANNOTATION_NAMES.map((name) => uniqueColumnName(name, usedColumns));
|
|
26
|
+
const columns = [outcomeColumn, reasonColumn, mediaFailuresColumn, ...run.sourceColumns];
|
|
27
|
+
return (0, csv_1.serialize)(rows.map((row) => {
|
|
28
|
+
const sourceCells = Object.fromEntries(run.sourceColumns.map((column) => [column, row.source?.[column] ?? '']));
|
|
29
|
+
return {
|
|
30
|
+
...sourceCells,
|
|
31
|
+
[outcomeColumn]: row.status,
|
|
32
|
+
[reasonColumn]: row.reason ?? '',
|
|
33
|
+
[mediaFailuresColumn]: row.mediaFailures?.length ? JSON.stringify(row.mediaFailures) : '',
|
|
34
|
+
};
|
|
35
|
+
}), { columns });
|
|
36
|
+
}
|