ghost 6.62.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/tryghost-adapter-base-jobs-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/content/themes/source/package.json +2 -2
- package/content/themes/source/partials/post-card.hbs +1 -1
- package/core/boot.js +7 -5
- package/core/built/admin/assets/{about-Dyae_UT6.js → about-C1C3s5-g.js} +1 -1
- package/core/built/admin/assets/accordion-CxGsDKwa.js +1 -0
- package/core/built/admin/assets/{account-migration-CESa0mnX.js → account-migration-CbUhW6gk.js} +1 -1
- package/core/built/admin/assets/activitypub/{account-migration-By69CgCp.js → account-migration-KA6Jjf9L.js} +7 -7
- package/core/built/admin/assets/activitypub/activitypub.js +3 -3
- 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-BJcPMrDd.js → bluesky-sharing-C7nTDMvw.js} +9 -9
- package/core/built/admin/assets/activitypub/{content-formatters-3rTHg3mp.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-DUR4xSkV.js → domain-fZ-X8i4-.js} +9 -9
- package/core/built/admin/assets/activitypub/{edit-profile-BqtfzxCp.js → edit-profile-BqMLQV88.js} +6 -6
- package/core/built/admin/assets/activitypub/{explore-BxuJd-J4.js → explore-B4yPoP8E.js} +10 -10
- package/core/built/admin/assets/activitypub/{feed-BM1TcksA.js → feed-BRC_mvAe.js} +9 -9
- package/core/built/admin/assets/activitypub/{field-Dn7HHx2-.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-CCjkuow2.js → inbox-BW-yvUoN.js} +10 -10
- package/core/built/admin/assets/activitypub/{inbox-d8oJRTf4.js → inbox-CbTTdDQ3.js} +2 -2
- package/core/built/admin/assets/activitypub/{label-1AA_s9Fa.js → label-kPMmYI7l.js} +3 -3
- package/core/built/admin/assets/activitypub/layout-BL4_jtuV.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-CnmxEB8w.js → moderation-CuidJzc0.js} +10 -10
- package/core/built/admin/assets/activitypub/{note-ZKc_Bnba.js → note-CAMRRSqD.js} +7 -7
- package/core/built/admin/assets/activitypub/{notifications-CB2tJZau.js → notifications-BmNlXGgp.js} +9 -9
- package/core/built/admin/assets/activitypub/{onboarding-BsJ9E5qf.js → onboarding-Bqg7fh_L.js} +2 -2
- package/core/built/admin/assets/activitypub/{onboarding-CSUJJIlh.js → onboarding-Dmun9jr_.js} +2 -2
- package/core/built/admin/assets/activitypub/{preferences-0-JZnUkI.js → preferences--oH19wf9.js} +11 -11
- package/core/built/admin/assets/activitypub/{profile-C35cFIhM.js → profile-DH_tQx2D.js} +14 -14
- package/core/built/admin/assets/activitypub/{reply-DYK5vVqb.js → reply-Cap9PxSH.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-BD4vscyc.js → routes-DdyY9uFF.js} +30 -30
- package/core/built/admin/assets/activitypub/{separator-BbQqTm-p.js → separator-CAxxu8VV.js} +3 -3
- package/core/built/admin/assets/activitypub/{settings-BsMROdqh.js → settings-B6EEcVkW.js} +6 -6
- package/core/built/admin/assets/activitypub/{site-O0RL9YCN.js → site-BYps63oh.js} +2 -2
- package/core/built/admin/assets/activitypub/{step-1-BMSx7c_X.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-CLlOZTyt.js → step-3-C-qBbcUo.js} +11 -11
- package/core/built/admin/assets/activitypub/{tabs-Dxk-b9M-.js → tabs-DLhZtVde.js} +6 -6
- package/core/built/admin/assets/activitypub/{topic-filter-5yZH6tId.js → topic-filter-DsUOuu0k.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-CV50qe03.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-Cbvzgjzd.js → use-reply-chain-data-AJi9zkzm.js} +5 -5
- package/core/built/admin/assets/activitypub/{users-BjcoP_HC.js → users-inweyKL5.js} +186 -160
- package/core/built/admin/assets/activitypub/{x-DbQZOLiI.js → x-DR8AT3-4.js} +2 -2
- package/core/built/admin/assets/{add-integration-modal-BlF6rs_f.js → add-integration-modal-BT_onDJy.js} +1 -1
- package/core/built/admin/assets/{add-newsletter-modal-CglVQqah.js → add-newsletter-modal-Cx1kQpiY.js} +1 -1
- package/core/built/admin/assets/{add-recommendation-modal-wz7BsuaG.js → add-recommendation-modal-B5nvAhvr.js} +1 -1
- package/core/built/admin/assets/{analytics-C4HE1gBg.js → analytics-DjoJWPI7.js} +1 -1
- package/core/built/admin/assets/{announcement-bar-modal-Ci4zz8jO.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-Ck-Yteiv.js → api-keys-BoeacM-s.js} +1 -1
- package/core/built/admin/assets/{audience-CtbA54Sn.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-BEtJ_gL_.js → bluesky-sharing-vzh-oPXL.js} +1 -1
- package/core/built/admin/assets/{breadcrumb-zUrZrBtW.js → breadcrumb-CaLk2b7D.js} +1 -1
- package/core/built/admin/assets/{button-eNMKQWXr.js → button-Dvcv1QSR.js} +1 -1
- package/core/built/admin/assets/calendar-Bl9RLcZX.js +1 -0
- package/core/built/admin/assets/{chart-helpers-CfBKt0vT.js → chart-helpers-FHywU0pj.js} +1 -1
- package/core/built/admin/assets/{checkbox-CgOn_tKW.js → checkbox-BtayFtjg.js} +1 -1
- package/core/built/admin/assets/chunk.254.035b85ec456ebbd7336b.js +440 -0
- package/core/built/admin/assets/{chunk.524.a697dee88db67fdf6021.js → chunk.524.e6975095fccdf22d90f8.js} +5 -5
- package/core/built/admin/assets/{chunk.582.5ed5d124cfca9c259b9c.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-K2wI-I5f.js → code-editor-view-C3ZfoF1X.js} +1 -1
- package/core/built/admin/assets/{code-editor-view-BYNoAoNV.js → code-editor-view-CAyRWy1s.js} +1 -1
- package/core/built/admin/assets/{color-picker-Ddw80xX6.js → color-picker-G4kGR7rp.js} +1 -1
- package/core/built/admin/assets/{color-picker-field-D9nUhvA7.js → color-picker-field-DQFVTNnT.js} +1 -1
- package/core/built/admin/assets/{combobox-w9j8PPQT.js → combobox-BnYzgEB4.js} +1 -1
- package/core/built/admin/assets/{command-BfpHORBv.js → command-C_vyTikI.js} +1 -1
- 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-CBM8G0Vj.js → confirmation-context-DwXX_Y5h.js} +1 -1
- package/core/built/admin/assets/{content-api-modal-TXRz3U7S.js → content-api-modal-D2G0nJP6.js} +1 -1
- package/core/built/admin/assets/{context-menu-_QMdd3kp.js → context-menu-DOVB6yaz.js} +1 -1
- package/core/built/admin/assets/{copy-field-6N01S07E.js → copy-field-DCJwh9qf.js} +1 -1
- package/core/built/admin/assets/{create-ghost-browse-value-source-qIBymvvf.js → create-ghost-browse-value-source-5C53jJaX.js} +1 -1
- package/core/built/admin/assets/custom-field-type-option-BAuW0F-E.js +1 -0
- package/core/built/admin/assets/{custom-integration-modal-DmNquxUV.js → custom-integration-modal-AbJGVyKc.js} +1 -1
- package/core/built/admin/assets/{date-range-select-uvz_DtPh.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-BZ1iytEd.js → dirty-confirm-dialog-DVPuGz3U.js} +1 -1
- package/core/built/admin/assets/{disabled-sources-indicator-DMRrxsiJ.js → disabled-sources-indicator-Cy7Zp4c8.js} +1 -1
- package/core/built/admin/assets/{domain-BNYrt0aD.js → domain-Dl61QGuk.js} +1 -1
- package/core/built/admin/assets/{dropzone-D7nFdAe5.js → dropzone-Dtz5Rmjt.js} +4 -4
- 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-Ds6mPEi5.js → embed-signup-form-modal-DGqsORxS.js} +1 -1
- package/core/built/admin/assets/{explore-UY10Egsp.js → explore-nnRr1Fja.js} +1 -1
- package/core/built/admin/assets/feature-flag-overrides-context-DQjdJFAk.js +1 -0
- package/core/built/admin/assets/{feature-image-placeholder-D1iF_8bc.js → feature-image-placeholder-BrIHmPs8.js} +1 -1
- package/core/built/admin/assets/{feed-81C8mJWR.js → feed-BNUcNu-W.js} +1 -1
- package/core/built/admin/assets/feedback-DJ4Zb9rZ.js +1 -0
- package/core/built/admin/assets/{field-Dihp5p18.js → field-C93_Mg6j.js} +1 -1
- package/core/built/admin/assets/filter-sources-CGJb4C5r.js +1 -0
- package/core/built/admin/assets/{filters-DirqNXjH.js → filters--kKP-EC8.js} +1 -1
- package/core/built/admin/assets/filters-DxA_a4FP.js +1 -0
- package/core/built/admin/assets/{first-promoter-modal-CT6MxYZb.js → first-promoter-modal-BYDtrz2S.js} +1 -1
- package/core/built/admin/assets/focus-koenig-editor-on-bottom-click-BbSnGOtK.js +1 -0
- package/core/built/admin/assets/{ghost-8eabfc1ece81b03cf7b90780d31487e8.css → ghost-8fd5bb799356bbefb254210ba7e1236d.css} +1 -1
- package/core/built/admin/assets/{ghost-c2848508292937415f20f5a830eea59e.js → ghost-b4e8a403baba61905cd7560e30b9732d.js} +43 -27
- package/core/built/admin/assets/{ghost-dark-a7bebe2c561f55369dcf29f4c820f7ff.css → ghost-dark-cac0cb2d5bb78e9bd14d8d1c2768ed45.css} +1 -1
- package/core/built/admin/assets/{gift-link-modal-CQVAye17.js → gift-link-modal-B7u5bD4e.js} +1 -1
- package/core/built/admin/assets/{gift-links-DLDS7ljO.js → gift-links-CfLSnst2.js} +1 -1
- package/core/built/admin/assets/growth-Cd1uO9d2.js +1 -0
- package/core/built/admin/assets/growth-aG32xfdE.js +3 -0
- package/core/built/admin/assets/{history-modal-CFd1Hvx6.js → history-modal-Df8lW8h-.js} +1 -1
- package/core/built/admin/assets/hooks-Cy_-oZ4o.js +2 -0
- package/core/built/admin/assets/{html-field-CJBCLTvv.js → html-field-DA4eU7eq.js} +1 -1
- package/core/built/admin/assets/{images-scfkWZiK.js → images-KXmyO3Ss.js} +1 -1
- package/core/built/admin/assets/{inbox-Mcp4DXZN.js → inbox-gJHG7_xd.js} +6 -6
- 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-CMhe2DvY.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-DfheMXs0.js → invite-user-modal-B4CuNcx4.js} +1 -1
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +2 -2
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +2 -2
- package/core/built/admin/assets/{koenig-lexical-DBSqAuiI.js → koenig-lexical-CGXb0F8o.js} +2 -2
- package/core/built/admin/assets/koenig-loader-BeM5rFPX.js +2 -0
- package/core/built/admin/assets/{kpi-card-DBRMfGOW.js → kpi-card-B21aToe8.js} +1 -1
- package/core/built/admin/assets/{kpi-card-DFafD1qq.js → kpi-card-pz6Wv4Ae.js} +1 -1
- package/core/built/admin/assets/{kpi-helpers-Cv8i8hns.js → kpi-helpers-Dq5jelmP.js} +1 -1
- package/core/built/admin/assets/{kpi-tabs-BJItvLYm.js → kpi-tabs-DEZHpKUt.js} +1 -1
- package/core/built/admin/assets/{label-BnSCvffu.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-DDQV6QeG.js → member-custom-fields-TRTHCAz9.js} +1 -1
- 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-AgCIEso4.js → moderation-ZWefD9uH.js} +1 -1
- package/core/built/admin/assets/{multi-select-combobox-BcITkUVr.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-DKzwafuh.js → newsletter-emails-DZH6I-PY.js} +1 -1
- package/core/built/admin/assets/{newsletters-BRBb_uQC.js → newsletters-DOC9KBcX.js} +1 -1
- package/core/built/admin/assets/newsletters-Rq1M3GD-.js +1 -0
- package/core/built/admin/assets/{note-DyGHtS9a.js → note-DIV-Pojr.js} +1 -1
- package/core/built/admin/assets/{notifications-ZgWniKna.js → notifications-s20-H49V.js} +1 -1
- package/core/built/admin/assets/{offers-9J1CSiLy.js → offers--e2nGvkW.js} +1 -1
- package/core/built/admin/assets/{offers-container-modal-B-E8TIWr.js → offers-container-modal-BmG5M5Tv.js} +1 -1
- package/core/built/admin/assets/onboarding-CUuy9unR.js +1 -0
- package/core/built/admin/assets/{onboarding-CzIsre-d.js → onboarding-pXyct0Jm.js} +1 -1
- package/core/built/admin/assets/{onboarding-route-CaavZulg.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-De0VzKBi.js → page-header-DM_KyoFI.js} +1 -1
- package/core/built/admin/assets/{pagemenu-B5KKCpbA.js → pagemenu-vgZVUVKR.js} +1 -1
- 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/{pintura-modal-BZ2J9w3n.js → pintura-modal-DExCF1ii.js} +1 -1
- package/core/built/admin/assets/{portal-frame-B6Hr9wHc.js → portal-frame-Cqanidq4.js} +1 -1
- 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-C5YJLp74.js → preferences--vNubsqD.js} +2 -2
- package/core/built/admin/assets/{preview-modal-BfeFqi5y.js → preview-modal-YYbzlYdO.js} +1 -1
- package/core/built/admin/assets/profile-BllKV3dR.js +1 -0
- package/core/built/admin/assets/radio-group-DL8GI8rt.js +1 -0
- 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-cb0t_TAJ.js → select-v5YbA3Mw.js} +1 -1
- package/core/built/admin/assets/settings-PEsZupw1.js +4 -0
- package/core/built/admin/assets/{settings-breadcrumbs-DLzbRRSt.js → settings-breadcrumbs-NwPnCTC7.js} +1 -1
- package/core/built/admin/assets/{settings-DZqxR0Da.js → settings-u_s1CRkr.js} +1 -1
- package/core/built/admin/assets/{share-modal-D2-Bz1_I.js → share-modal-SskCmVGL.js} +1 -1
- package/core/built/admin/assets/{slack-modal-DYDTUria.js → slack-modal-XxSJiYgo.js} +1 -1
- package/core/built/admin/assets/{sort-button-VVeQjjbu.js → sort-button-Cx1KtINE.js} +1 -1
- package/core/built/admin/assets/{source-icon-Ck5_5Kgq.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-CsaBjeN4.js → step-1-BQYzvBzr.js} +1 -1
- package/core/built/admin/assets/{step-2-D2vnxOOM.js → step-2-xES32xJV.js} +1 -1
- package/core/built/admin/assets/{step-3-wBoLdGEb.js → step-3-DA_XK5kW.js} +2 -2
- package/core/built/admin/assets/{stripe-button-CDgLz0S0.js → stripe-button-CVsLHelt.js} +1 -1
- package/core/built/admin/assets/{stripe-connect-modal-CSjMJetP.js → stripe-connect-modal-ClmLOMGS.js} +1 -1
- package/core/built/admin/assets/style-Wd9nQubI.css +1 -0
- package/core/built/admin/assets/{table-Do6iQ83Q.js → table-BenqVupI.js} +1 -1
- package/core/built/admin/assets/{tabs-D2yWLMp_.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-CtnZBJKl.js → testimonials-modal-9Q6fT06V.js} +1 -1
- 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-ByUJsxwD.js → toggle-group-CviIkyok.js} +1 -1
- package/core/built/admin/assets/{topic-filter-BgC3g5_v.js → topic-filter-I2jCBGxm.js} +1 -1
- package/core/built/admin/assets/{transistor-modal-Drr0SNfo.js → transistor-modal-p53u3W8y.js} +1 -1
- package/core/built/admin/assets/{trend-badge-6ye93YAW.js → trend-badge-CideVzQd.js} +1 -1
- package/core/built/admin/assets/{unsplash-modal-p6AoQoWp.js → unsplash-modal-DY8UcKcE.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data-CWCMAESo.js → use-analytics-data-DAIGcr2f.js} +1 -1
- package/core/built/admin/assets/{use-check-theme-limit-error-Cw3WQHy8.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-DCVG3s9w.js → use-growth-stats-937CUj6j.js} +1 -1
- package/core/built/admin/assets/use-host-limits-D0Dv3tKA.js +1 -0
- package/core/built/admin/assets/{use-limiter-D2WRRx0H.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-BfN1UwzH.js → use-pintura-editor-CaV1mbfO.js} +1 -1
- package/core/built/admin/assets/{use-post-referrers-Czg47m8s.js → use-post-referrers-BCQI7fDg.js} +1 -1
- package/core/built/admin/assets/{use-reply-chain-data-ns0caK8k.js → use-reply-chain-data-CYRhoaxY.js} +1 -1
- package/core/built/admin/assets/{use-router-history-entry-uldn7zJO.js → use-router-history-entry-NOKcd--l.js} +1 -1
- package/core/built/admin/assets/{use-setting-group-DpcuCUDg.js → use-setting-group-bLKMwoBT.js} +1 -1
- package/core/built/admin/assets/{use-settings-navigation-CZjGrhsp.js → use-settings-navigation-B-qrriKD.js} +1 -1
- package/core/built/admin/assets/{use-simple-pagination-DzJWobPR.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-CSnGXzZh.js → use-tinybird-query-CmdbCS9X.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-DTOKRR7e.js → use-tinybird-token-KLne235s.js} +1 -1
- package/core/built/admin/assets/{use-unsaved-changes-guard-CBzs-KPi.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-DFr8lCbS.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-Cg-OeGzC.js → users-DVNWrqg9.js} +1 -1
- package/core/built/admin/assets/{vendor-5753232c7d6ffb3c44e1eb0a02133953.js → vendor-2dd263291938d407802568d3357ec69e.js} +19 -17
- package/core/built/admin/assets/{virtual-list-BW-padMe.js → virtual-list-CZ3RK2Yf.js} +1 -1
- package/core/built/admin/assets/{web-C1v33ehA.js → web-ClEJsCAj.js} +2 -2
- package/core/built/admin/assets/web-X9rdnrtq.js +1 -0
- package/core/built/admin/assets/{zapier-modal-BBFfI6Ml.js → zapier-modal-DfVhV17j.js} +1 -1
- package/core/built/admin/index.html +19 -18
- 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 +8 -0
- package/core/server/api/endpoints/member-metafields-members.js +23 -0
- package/core/server/api/endpoints/member-metafields.js +33 -20
- package/core/server/api/endpoints/members-account.js +42 -0
- 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/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 +16 -2
- 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 +4 -0
- package/core/server/api/endpoints/utils/serializers/output/member-metafields.js +3 -3
- 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/tiers.js +10 -2
- package/core/server/api/endpoints/utils/serializers/output/users.js +0 -10
- package/core/server/data/exporter/table-lists.js +3 -3
- 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/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 +6 -6
- package/core/server/models/user.js +1 -1
- 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/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 -0
- package/core/server/services/email-service/email-controller.js +18 -2
- package/core/server/services/email-service/email-service-wrapper.js +3 -0
- 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/gift-service.js +19 -57
- package/core/server/services/gifts/index.js +0 -2
- 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 +13 -2
- package/core/server/services/members/account-service.js +98 -0
- package/core/server/services/members/api.js +4 -4
- package/core/server/services/members/import-export/export/exporter.js +20 -20
- package/core/server/services/members/import-export/import/completion-email.js +6 -6
- package/core/server/services/members/import-export/import/importer.js +13 -13
- package/core/server/services/members/import-export/index.js +7 -7
- package/core/server/services/members/members-api/members-api.js +26 -6
- 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 +45 -39
- 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 +70 -42
- 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-custom-fields → members-metafields}/codec.js +4 -4
- 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 +17 -23
- package/core/server/services/{members-custom-fields → members-metafields}/filter.js +9 -9
- package/core/server/services/{members-custom-fields → members-metafields}/index.js +16 -7
- package/core/server/services/{members-custom-fields → members-metafields}/key.js +1 -1
- package/core/server/services/{members-custom-fields → members-metafields}/models.js +4 -4
- 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-custom-fields → members-metafields}/serializers.js +6 -6
- package/core/server/services/{members-custom-fields → members-metafields}/values-service.js +32 -22
- package/core/server/services/mentions/mention-sending-service.js +26 -9
- package/core/server/services/mentions/send-webmentions-job.js +18 -0
- package/core/server/services/mentions/service.js +1 -31
- package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +2 -2
- package/core/server/services/stripe/stripe-service.js +4 -4
- package/core/server/services/tier-checkout-config/codec.js +2 -2
- package/core/server/services/tier-checkout-config/index.js +2 -1
- package/core/server/services/tier-checkout-config/models.js +2 -2
- package/core/server/services/tier-checkout-config/queries.js +8 -8
- package/core/server/services/tier-checkout-config/serializers.js +57 -0
- package/core/server/services/tier-checkout-config/service.js +1 -1
- package/core/server/services/tiers/service.js +3 -3
- package/core/server/services/url/router-filter.js +8 -10
- package/core/server/services/users.js +1 -19
- package/core/server/web/api/endpoints/admin/routes.js +1 -0
- 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/labs.js +4 -2
- package/package.json +22 -22
- package/pnpm-lock.yaml +513 -571
- package/pnpm-workspace.yaml +12 -12
- package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
- package/core/built/admin/assets/activitypub/layout-2-0bw6HN.js +0 -1
- package/core/built/admin/assets/automated-emails-D5VVMND9.js +0 -1
- package/core/built/admin/assets/automations-CzKt5fb8.js +0 -1
- package/core/built/admin/assets/chunk.598.7e056fabb47ce7dbd73f.js +0 -366
- package/core/built/admin/assets/comments-BLmCmyCs.js +0 -1
- package/core/built/admin/assets/custom-field-type-option-BddFlJFa.js +0 -1
- package/core/built/admin/assets/design-and-theme-modal-BSmo12Op.js +0 -2
- package/core/built/admin/assets/edit-profile-C5Asm4LA.js +0 -1
- package/core/built/admin/assets/editor-REokrzci.js +0 -8
- package/core/built/admin/assets/filter-sources-BO9xUPj7.js +0 -1
- package/core/built/admin/assets/filters-CRUWecfY.js +0 -1
- package/core/built/admin/assets/growth-BWIu-6xj.js +0 -3
- package/core/built/admin/assets/growth-DU29oxeA.js +0 -1
- package/core/built/admin/assets/hooks-CuEZV2-q.js +0 -2
- package/core/built/admin/assets/index-6MkPdCtr.js +0 -4
- package/core/built/admin/assets/index-Bn7QhcZu.css +0 -2
- package/core/built/admin/assets/index.es-CNnuNH0d.js +0 -1
- package/core/built/admin/assets/koenig-loader-aFQNlJlD.js +0 -2
- package/core/built/admin/assets/label-picker-KVoo91sh.js +0 -1
- package/core/built/admin/assets/layout-Bjv2Ll-5.js +0 -1
- package/core/built/admin/assets/link-helpers-MVDdnFCY.js +0 -1
- package/core/built/admin/assets/member-detail-CdJF6Agw.js +0 -1
- package/core/built/admin/assets/members-DjQbq9Z2.js +0 -4
- package/core/built/admin/assets/navigation-modal-BkT7b1M2.js +0 -1
- package/core/built/admin/assets/newsletter-BMMAuvgq.js +0 -1
- package/core/built/admin/assets/newsletter-detail-modal-0SCJ7Zpm.js +0 -1
- package/core/built/admin/assets/newsletters-DhNigJUh.js +0 -1
- package/core/built/admin/assets/onboarding-qg8Akovm.js +0 -1
- package/core/built/admin/assets/overview-BW8GLeYi.js +0 -1
- package/core/built/admin/assets/overview-BkXZNzaZ.js +0 -1
- package/core/built/admin/assets/pages-jgaFm69d.js +0 -1
- package/core/built/admin/assets/pages-route-CIUAQxtY.js +0 -1
- package/core/built/admin/assets/portal-modal-D4ceei3t.js +0 -1
- package/core/built/admin/assets/post-analytics-header-BYCsT0GP.js +0 -1
- package/core/built/admin/assets/post-analytics-ot7f6pih.js +0 -1
- package/core/built/admin/assets/post-analytics-provider-Bo1gmYaP.js +0 -1
- package/core/built/admin/assets/post-helpers-C5OQMBoi.js +0 -1
- package/core/built/admin/assets/post-share-modal-C-PaYZ_e.js +0 -1
- package/core/built/admin/assets/posts-DuGazgTb.js +0 -1
- package/core/built/admin/assets/posts-list-screen-CBGGgjjj.js +0 -2
- package/core/built/admin/assets/posts-route-D6xmS7Vf.js +0 -1
- package/core/built/admin/assets/profile-B8mx2yAu.js +0 -1
- package/core/built/admin/assets/radio-group-DczlLKOn.js +0 -1
- package/core/built/admin/assets/router-provider-B0gZyiGJ.js +0 -1
- package/core/built/admin/assets/schemas-DppqmpeJ.js +0 -64
- package/core/built/admin/assets/settings-DvfTNdHQ.js +0 -4
- package/core/built/admin/assets/stats-Rjmk5owg.js +0 -1
- package/core/built/admin/assets/stats-view-BGGmkmgv.js +0 -1
- package/core/built/admin/assets/tag-detail-BhXlOsCa.js +0 -2
- package/core/built/admin/assets/tags-ldukRApe.js +0 -1
- package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +0 -1
- package/core/built/admin/assets/tiers-Nd_z4BZY.js +0 -1
- package/core/built/admin/assets/use-filter-params-BIni9taJ.js +0 -1
- package/core/built/admin/assets/use-host-limits-DZtR08oa.js +0 -1
- package/core/built/admin/assets/use-pintura-config-h-J0Lvta.js +0 -1
- package/core/built/admin/assets/use-staff-users-Csipb-O0.js +0 -1
- package/core/built/admin/assets/use-upgrade-route-DhRSo7at.js +0 -1
- package/core/built/admin/assets/user-detail-modal-B_iUClI6.js +0 -1
- package/core/built/admin/assets/web-C4BKzn2T.js +0 -1
- package/core/server/services/email-suppression-list/in-memory-email-suppression-list.js +0 -39
- package/core/server/services/members-custom-fields/bindings-service.js +0 -120
- /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
|
@@ -0,0 +1,98 @@
|
|
|
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.MemberAccountService = void 0;
|
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
const members_metafields_1 = require("../members-metafields");
|
|
9
|
+
/**
|
|
10
|
+
* A member's own account: what they are shown about themselves, and what they may
|
|
11
|
+
* change.
|
|
12
|
+
*
|
|
13
|
+
* Separate from the request handlers that used to hold this, because none of it is
|
|
14
|
+
* a question about HTTP. Which fields a member may set is a fact about members, and
|
|
15
|
+
* the answer is the same whoever is asking.
|
|
16
|
+
*
|
|
17
|
+
* Takes a member id rather than a member. Everything here either writes or reads
|
|
18
|
+
* afresh, and a record loaded before a write is stale by the time the answer is
|
|
19
|
+
* built, so there is nothing a caller could usefully hand over.
|
|
20
|
+
*/
|
|
21
|
+
/** What a member is allowed to change about themselves. */
|
|
22
|
+
const WRITABLE_FIELDS = [
|
|
23
|
+
'name',
|
|
24
|
+
'expertise',
|
|
25
|
+
'subscribed',
|
|
26
|
+
'newsletters',
|
|
27
|
+
'enable_comment_notifications',
|
|
28
|
+
'enable_updates_and_announcements',
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* The relations a write needs loaded to work out what it is changing.
|
|
32
|
+
*
|
|
33
|
+
* Newsletters because the older `subscribed` flag is stored as a list of them, and
|
|
34
|
+
* the subscription chain because changing what a member is entitled to has to
|
|
35
|
+
* reconcile against what they are paying for.
|
|
36
|
+
*/
|
|
37
|
+
const WRITE_RELATIONS = [
|
|
38
|
+
'stripeSubscriptions',
|
|
39
|
+
'stripeSubscriptions.customer',
|
|
40
|
+
'stripeSubscriptions.stripePrice',
|
|
41
|
+
'newsletters',
|
|
42
|
+
];
|
|
43
|
+
class MemberAccountService {
|
|
44
|
+
#memberBREADService;
|
|
45
|
+
#members;
|
|
46
|
+
#emailSuppressionList;
|
|
47
|
+
#metafieldValues;
|
|
48
|
+
constructor({ memberBREADService, members, emailSuppressionList, metafieldValues, }) {
|
|
49
|
+
this.#memberBREADService = memberBREADService;
|
|
50
|
+
this.#members = members;
|
|
51
|
+
this.#emailSuppressionList = emailSuppressionList;
|
|
52
|
+
this.#metafieldValues = metafieldValues;
|
|
53
|
+
}
|
|
54
|
+
/** Everything a member is shown about themselves. */
|
|
55
|
+
async read(memberId) {
|
|
56
|
+
// As the member rather than as staff: how much of the extra fields a publisher
|
|
57
|
+
// defines is answered depends on which side of Ghost is asking.
|
|
58
|
+
return this.#memberBREADService.read({ id: memberId }, { metafieldsFor: members_metafields_1.MEMBERS });
|
|
59
|
+
}
|
|
60
|
+
/** Apply what a member asked to change about themselves, and say what they now hold. */
|
|
61
|
+
async edit(data, memberId) {
|
|
62
|
+
// Worked out before the member is touched, so a value the catalog refuses fails
|
|
63
|
+
// the whole request rather than leaving a member renamed with their answers
|
|
64
|
+
// rejected. The write below reconciles subscriptions with Stripe and sends
|
|
65
|
+
// events, none of which giving up halfway could undo.
|
|
66
|
+
const plannedMetafields = data.metafields === undefined
|
|
67
|
+
? null
|
|
68
|
+
: await this.#metafieldValues.planWrite(this.#metafieldValues.unwrapWire(data.metafields), members_metafields_1.MEMBERS);
|
|
69
|
+
await this.#members.update(lodash_1.default.pick(data, WRITABLE_FIELDS), {
|
|
70
|
+
id: memberId,
|
|
71
|
+
withRelated: WRITE_RELATIONS,
|
|
72
|
+
});
|
|
73
|
+
if (plannedMetafields) {
|
|
74
|
+
// A member is recorded as the author of their own answers, and is the one
|
|
75
|
+
// writer whose changes leave nothing in the staff action log: that log
|
|
76
|
+
// records what staff did.
|
|
77
|
+
await this.#metafieldValues.applyWrite(memberId, plannedMetafields, {
|
|
78
|
+
writtenBy: { type: 'member', id: memberId },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Read back rather than returning what was written: a member is told what
|
|
82
|
+
// Ghost now holds, which is not always what they sent. Setting the older
|
|
83
|
+
// `subscribed` flag, for one, is stored as a list of newsletters.
|
|
84
|
+
return this.read(memberId);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Let Ghost email this member again.
|
|
88
|
+
*
|
|
89
|
+
* Two records rather than one: the address is on a list the email provider also
|
|
90
|
+
* writes to, and the member carries a flag of their own. A member asking to hear
|
|
91
|
+
* from a site again means both.
|
|
92
|
+
*/
|
|
93
|
+
async allowEmail(memberId, email) {
|
|
94
|
+
await this.#emailSuppressionList.removeEmail(email);
|
|
95
|
+
await this.#members.update({ email_disabled: false }, { id: memberId });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.MemberAccountService = MemberAccountService;
|
|
@@ -22,7 +22,7 @@ const emailSuppressionList = require('../email-suppression-list');
|
|
|
22
22
|
const commentsService = require('../comments');
|
|
23
23
|
const emailAddressService = require('../email-address');
|
|
24
24
|
const giftService = require('../gifts');
|
|
25
|
-
const
|
|
25
|
+
const metafieldsService = require('../members-metafields');
|
|
26
26
|
const { t } = require('../i18n');
|
|
27
27
|
const sentry = require('../../../shared/sentry');
|
|
28
28
|
|
|
@@ -271,10 +271,10 @@ function createApiInstance(config) {
|
|
|
271
271
|
giftService,
|
|
272
272
|
// Resolved here rather than passed as the module: the members service needs
|
|
273
273
|
// the values service itself, and reading it at construction is what ties the
|
|
274
|
-
// two together in boot order.
|
|
274
|
+
// two together in boot order. Metafields is initialised in initCore, the
|
|
275
275
|
// members API is built in initServices, so this is always the live instance.
|
|
276
|
-
|
|
277
|
-
|
|
276
|
+
metafieldValues: metafieldsService.values,
|
|
277
|
+
metafieldDefinitions: metafieldsService.definitions,
|
|
278
278
|
});
|
|
279
279
|
|
|
280
280
|
return membersApiInstance;
|
|
@@ -8,7 +8,7 @@ const moment_1 = __importDefault(require("moment"));
|
|
|
8
8
|
const node_stream_1 = require("node:stream");
|
|
9
9
|
const logging = require('@tryghost/logging');
|
|
10
10
|
const errors = require('@tryghost/errors');
|
|
11
|
-
const { csvCellsForFields } = require('@tryghost/
|
|
11
|
+
const { csvCellsForFields } = require('@tryghost/metafield-types/csv');
|
|
12
12
|
// The columns the export reads off the members table, checked against MemberDbRow so the
|
|
13
13
|
// query cannot select a column the row type does not declare.
|
|
14
14
|
const MEMBER_COLUMNS = ['id', 'email', 'name', 'note', 'status', 'created_at'];
|
|
@@ -32,22 +32,22 @@ function toExportCsvRow(row) {
|
|
|
32
32
|
labels: namesToCsv(row.labels),
|
|
33
33
|
tiers: namesToCsv(row.tiers),
|
|
34
34
|
gift_id: row.gift_id || '',
|
|
35
|
-
...row.
|
|
35
|
+
...row.metafield_cells,
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
const BATCH_SIZE = 1000;
|
|
39
39
|
// Streams the matching members as flat rows, each carrying its related data (tiers,
|
|
40
|
-
// labels, subscription, gift, Stripe customer,
|
|
41
|
-
// to turn into CSV lines. The members aggregate and
|
|
40
|
+
// labels, subscription, gift, Stripe customer, metafields) for the output serializer
|
|
41
|
+
// to turn into CSV lines. The members aggregate and metafields are reached only
|
|
42
42
|
// through the ports above, so nothing Bookshelf- or flag-shaped leaks into the export.
|
|
43
43
|
class MembersCSVExporter {
|
|
44
44
|
_knex;
|
|
45
45
|
_members;
|
|
46
|
-
|
|
47
|
-
constructor({ knex, members,
|
|
46
|
+
_metafields;
|
|
47
|
+
constructor({ knex, members, metafields }) {
|
|
48
48
|
this._knex = knex;
|
|
49
49
|
this._members = members;
|
|
50
|
-
this.
|
|
50
|
+
this._metafields = metafields;
|
|
51
51
|
}
|
|
52
52
|
async export(options = {}) {
|
|
53
53
|
const start = Date.now();
|
|
@@ -75,7 +75,7 @@ class MembersCSVExporter {
|
|
|
75
75
|
return processingTransform;
|
|
76
76
|
}
|
|
77
77
|
// products and labels are small, stable tables, read once up front as id->name
|
|
78
|
-
// maps.
|
|
78
|
+
// maps. Metafield definitions are read once too, which fixes the column set for
|
|
79
79
|
// the whole file: archiving a field mid-export cannot leave the header ragged. It
|
|
80
80
|
// can still leave that field's cells empty from the batch after the archive
|
|
81
81
|
// onwards, because the per-batch value read applies its own active filter.
|
|
@@ -94,8 +94,8 @@ class MembersCSVExporter {
|
|
|
94
94
|
return acc;
|
|
95
95
|
}, {}));
|
|
96
96
|
logging.info({ event: { name: 'members-export.reference_data_read' }, durationMs: Date.now() - start }, 'Read the products and labels an export names');
|
|
97
|
-
const
|
|
98
|
-
return { allProducts, allLabels,
|
|
97
|
+
const activeMetafields = await this._metafields.activeDefinitions();
|
|
98
|
+
return { allProducts, allLabels, activeMetafields };
|
|
99
99
|
}
|
|
100
100
|
// Group the member stream into batches so the related-data reads are one query per
|
|
101
101
|
// batch rather than one per member.
|
|
@@ -121,7 +121,7 @@ class MembersCSVExporter {
|
|
|
121
121
|
}
|
|
122
122
|
// Each flattened row is pushed individually so a batch's rows do not pile up in memory.
|
|
123
123
|
createProcessingTransform(reference) {
|
|
124
|
-
const assembleRelatedData = (memberIds) => this.assembleRelatedData(memberIds, reference.
|
|
124
|
+
const assembleRelatedData = (memberIds) => this.assembleRelatedData(memberIds, reference.activeMetafields);
|
|
125
125
|
const flattenBatch = (members, related) => this.flattenBatch(members, related, reference);
|
|
126
126
|
return new node_stream_1.Transform({
|
|
127
127
|
objectMode: true,
|
|
@@ -140,11 +140,11 @@ class MembersCSVExporter {
|
|
|
140
140
|
},
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
|
-
// One query per related table for the whole batch, not one per member.
|
|
143
|
+
// One query per related table for the whole batch, not one per member. Metafield
|
|
144
144
|
// values are read only when there are columns to fill.
|
|
145
|
-
async assembleRelatedData(memberIds,
|
|
145
|
+
async assembleRelatedData(memberIds, activeMetafields) {
|
|
146
146
|
const knex = this._knex;
|
|
147
|
-
const [tiers, labels, stripeCustomers, subscriptions, gifts,
|
|
147
|
+
const [tiers, labels, stripeCustomers, subscriptions, gifts, metafieldValuesMap] = await Promise.all([
|
|
148
148
|
knex('members_products')
|
|
149
149
|
.select('member_id', knex.raw('GROUP_CONCAT(product_id) as tiers'))
|
|
150
150
|
.whereIn('member_id', memberIds)
|
|
@@ -162,8 +162,8 @@ class MembersCSVExporter {
|
|
|
162
162
|
.select('id', 'redeemer_member_id')
|
|
163
163
|
.where('status', 'redeemed')
|
|
164
164
|
.whereIn('redeemer_member_id', memberIds),
|
|
165
|
-
|
|
166
|
-
? this.
|
|
165
|
+
activeMetafields.length > 0
|
|
166
|
+
? this._metafields.valuesForMembers(memberIds)
|
|
167
167
|
: new Map(),
|
|
168
168
|
]);
|
|
169
169
|
return {
|
|
@@ -178,12 +178,12 @@ class MembersCSVExporter {
|
|
|
178
178
|
row.redeemer_member_id,
|
|
179
179
|
row.id,
|
|
180
180
|
])),
|
|
181
|
-
|
|
181
|
+
metafieldValuesMap,
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
184
|
flattenBatch(members, related, reference) {
|
|
185
|
-
const { tiersMap, labelsMap, stripeCustomerMap, subscribedSet, giftIdMap,
|
|
186
|
-
const { allProducts, allLabels,
|
|
185
|
+
const { tiersMap, labelsMap, stripeCustomerMap, subscribedSet, giftIdMap, metafieldValuesMap } = related;
|
|
186
|
+
const { allProducts, allLabels, activeMetafields } = reference;
|
|
187
187
|
return members.map((row) => {
|
|
188
188
|
const tierConcat = tiersMap.get(row.id);
|
|
189
189
|
const tierIds = tierConcat ? tierConcat.split(',') : [];
|
|
@@ -202,7 +202,7 @@ class MembersCSVExporter {
|
|
|
202
202
|
// only knowable from the database. Every member carries a cell for every
|
|
203
203
|
// active field's column, so a member with no values still contributes the
|
|
204
204
|
// full set -- the CSV header is taken from whichever row streams first.
|
|
205
|
-
|
|
205
|
+
metafield_cells: csvCellsForFields(activeMetafields, metafieldValuesMap.get(row.id) || {}),
|
|
206
206
|
};
|
|
207
207
|
});
|
|
208
208
|
}
|
|
@@ -36,7 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.default = buildImportEmail;
|
|
37
37
|
const csv_1 = require("../csv");
|
|
38
38
|
const email_template_1 = __importStar(require("./email-template"));
|
|
39
|
-
const csv_2 = require("@tryghost/
|
|
39
|
+
const csv_2 = require("@tryghost/metafield-types/csv");
|
|
40
40
|
// Turn an ORM validation error into copy a member manager can act on. Presentation
|
|
41
41
|
// only: the API response keeps the raw messages, and just the emailed report is
|
|
42
42
|
// rewritten. Takes one reason at a time, so a rewrite matching to the end of its input
|
|
@@ -55,11 +55,11 @@ function humaniseError(row) {
|
|
|
55
55
|
function stringifyLabels(labels) {
|
|
56
56
|
return labels.map((label) => (typeof label === 'string' ? label : label.name)).join(',');
|
|
57
57
|
}
|
|
58
|
-
function
|
|
59
|
-
return Object.fromEntries(Object.entries(row).filter(([column]) => (0, csv_2.
|
|
58
|
+
function metafieldCells(row) {
|
|
59
|
+
return Object.fromEntries(Object.entries(row).filter(([column]) => (0, csv_2.isMetafieldColumn)(column)));
|
|
60
60
|
}
|
|
61
61
|
// Shape a failed import row into its fixed error-report cells, with the raw ORM message
|
|
62
|
-
// rewritten into copy the member manager can act on.
|
|
62
|
+
// rewritten into copy the member manager can act on. Metafield cells are merged on by
|
|
63
63
|
// buildErrorReport, which owns the dynamic column set.
|
|
64
64
|
function toErrorReportRow(row) {
|
|
65
65
|
return {
|
|
@@ -84,9 +84,9 @@ function toErrorReportRow(row) {
|
|
|
84
84
|
// come from the shaper's keys, so the type stays the single source.
|
|
85
85
|
function buildErrorReport(errors) {
|
|
86
86
|
const memberColumns = Object.keys(toErrorReportRow(errors[0])).filter((column) => column !== 'error');
|
|
87
|
-
const customColumns = [...new Set(errors.flatMap((row) => Object.keys(
|
|
87
|
+
const customColumns = [...new Set(errors.flatMap((row) => Object.keys(metafieldCells(row))))];
|
|
88
88
|
const columns = [...memberColumns, ...customColumns, 'error'];
|
|
89
|
-
const rows = errors.map((row) => ({ ...toErrorReportRow(row), ...
|
|
89
|
+
const rows = errors.map((row) => ({ ...toErrorReportRow(row), ...metafieldCells(row) }));
|
|
90
90
|
return (0, csv_1.serialize)(rows, { columns });
|
|
91
91
|
}
|
|
92
92
|
// The one email an import sends, whatever became of it. What the publisher is told and
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const moment_timezone_1 = __importDefault(require("moment-timezone"));
|
|
7
7
|
const completion_email_1 = __importDefault(require("./completion-email"));
|
|
8
8
|
const csv_1 = require("../csv");
|
|
9
|
-
const csv_2 = require("@tryghost/
|
|
9
|
+
const csv_2 = require("@tryghost/metafield-types/csv");
|
|
10
10
|
const metrics = require('@tryghost/metrics');
|
|
11
11
|
const errors = require('@tryghost/errors');
|
|
12
12
|
const logging = require('@tryghost/logging');
|
|
@@ -17,7 +17,7 @@ const messages = {
|
|
|
17
17
|
giftCannotCombineWithImportTier: 'Cannot specify both gift_id and import_tier.',
|
|
18
18
|
giftCannotCombineWithComplimentary: 'Cannot specify both gift_id and complimentary_plan.',
|
|
19
19
|
giftReassignFailed: 'Failed to reassign gift to member.',
|
|
20
|
-
|
|
20
|
+
metafieldWriteFailed: 'Failed to save the custom field values for this member.',
|
|
21
21
|
};
|
|
22
22
|
// Columns whose presence makes a row slow to import (they reach out to Stripe), so
|
|
23
23
|
// a file carrying any of them is deferred regardless of size. The routing decision
|
|
@@ -50,13 +50,13 @@ class MembersCSVImporter {
|
|
|
50
50
|
_tiers;
|
|
51
51
|
_stripe;
|
|
52
52
|
_gifts;
|
|
53
|
-
|
|
53
|
+
_metafields;
|
|
54
54
|
_email;
|
|
55
55
|
_report;
|
|
56
56
|
_addJob;
|
|
57
57
|
_getTimezone;
|
|
58
58
|
_getInlineThreshold;
|
|
59
|
-
constructor({ knex, readRows, spool, members, tiers, stripe, gifts,
|
|
59
|
+
constructor({ knex, readRows, spool, members, tiers, stripe, gifts, metafields, email, report, addJob, getTimezone, getInlineThreshold, }) {
|
|
60
60
|
this._knex = knex;
|
|
61
61
|
this._readRows = readRows;
|
|
62
62
|
this._spool = spool;
|
|
@@ -64,7 +64,7 @@ class MembersCSVImporter {
|
|
|
64
64
|
this._tiers = tiers;
|
|
65
65
|
this._stripe = stripe;
|
|
66
66
|
this._gifts = gifts;
|
|
67
|
-
this.
|
|
67
|
+
this._metafields = metafields;
|
|
68
68
|
this._email = email;
|
|
69
69
|
this._report = report;
|
|
70
70
|
this._addJob = addJob;
|
|
@@ -166,14 +166,14 @@ class MembersCSVImporter {
|
|
|
166
166
|
return {
|
|
167
167
|
defaultTier: await this._tiers.getDefault(),
|
|
168
168
|
// Empty when the feature is off, so a carried-through column is dropped.
|
|
169
|
-
|
|
169
|
+
activeMetafields: await this._metafields.activeFields(),
|
|
170
170
|
globalLabels: [{ name: labelName }, ...extraLabels],
|
|
171
171
|
};
|
|
172
172
|
}
|
|
173
173
|
// Must not throw: once a row has committed, an import that failed halfway is not one
|
|
174
174
|
// that never ran.
|
|
175
175
|
async writeRows(rows, prepared) {
|
|
176
|
-
const { defaultTier,
|
|
176
|
+
const { defaultTier, activeMetafields } = prepared;
|
|
177
177
|
const tierIdCache = new Map();
|
|
178
178
|
const archivableStripePriceIds = [];
|
|
179
179
|
// Copied per row: the member model stamps ids and trims names onto these in
|
|
@@ -199,12 +199,12 @@ class MembersCSVImporter {
|
|
|
199
199
|
}));
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
|
-
// Validate the row's
|
|
202
|
+
// Validate the row's metafield values before the transaction opens.
|
|
203
203
|
// planWrite only reads, and it throws on an invalid value to fail the row
|
|
204
204
|
// before any member write -- so there is no reason to hold a transaction
|
|
205
205
|
// across it, and doing so would deadlock the single-connection SQLite pool.
|
|
206
|
-
const
|
|
207
|
-
? await namingTheColumn(() => this.
|
|
206
|
+
const metafieldPlan = activeMetafields.length > 0
|
|
207
|
+
? await namingTheColumn(() => this._metafields.planWrite((0, csv_2.fieldValuesFromCsvRow)(activeMetafields, row, csv_1.stripFormulaGuard)))
|
|
208
208
|
: [];
|
|
209
209
|
trx = await this._knex.transaction(undefined, { doNotRejectOnRollback: false });
|
|
210
210
|
const options = { transacting: trx, context: IMPORT_CONTEXT };
|
|
@@ -307,7 +307,7 @@ class MembersCSVImporter {
|
|
|
307
307
|
}
|
|
308
308
|
// On the row's transaction, so the values commit or roll back with the member.
|
|
309
309
|
try {
|
|
310
|
-
await this.
|
|
310
|
+
await this._metafields.applyWrite(member.id, metafieldPlan, trx);
|
|
311
311
|
}
|
|
312
312
|
catch (writeError) {
|
|
313
313
|
// planWrite passed every value before the transaction opened, so a failure
|
|
@@ -315,7 +315,7 @@ class MembersCSVImporter {
|
|
|
315
315
|
// will have written a query into; the publisher gets a sentence instead, in a
|
|
316
316
|
// file they open next to a spreadsheet.
|
|
317
317
|
this._report(writeError);
|
|
318
|
-
throw new errors.DataImportError({ message: tpl(messages.
|
|
318
|
+
throw new errors.DataImportError({ message: tpl(messages.metafieldWriteFailed) });
|
|
319
319
|
}
|
|
320
320
|
await trx.commit();
|
|
321
321
|
imported += 1;
|
|
@@ -327,7 +327,7 @@ class MembersCSVImporter {
|
|
|
327
327
|
.filter((message) => typeof message === 'string');
|
|
328
328
|
const errorMessage = reasons.join('\n');
|
|
329
329
|
// trx is unset if the row failed before the transaction opened (a bad
|
|
330
|
-
//
|
|
330
|
+
// metafield value or gift combination). A rejected rollback must not
|
|
331
331
|
// escape: rows before this one are already committed, and a throw leaving
|
|
332
332
|
// here would be read as an import that never wrote anything.
|
|
333
333
|
if (trx) {
|
|
@@ -56,12 +56,12 @@ function makeImporter(deps) {
|
|
|
56
56
|
transacting: options.transacting,
|
|
57
57
|
}),
|
|
58
58
|
};
|
|
59
|
-
const
|
|
60
|
-
activeFields: async () => deps.
|
|
61
|
-
planWrite: (values) => deps.
|
|
59
|
+
const metafields = {
|
|
60
|
+
activeFields: async () => deps.metafields.definitions.browse(),
|
|
61
|
+
planWrite: (values) => deps.metafields.values.planWrite(values),
|
|
62
62
|
// Every value the import writes came out of the file, whichever column carried it.
|
|
63
63
|
// An import has no id to give until runs are tracked, so it names its kind only.
|
|
64
|
-
applyWrite: (memberId, plan, executor) => deps.
|
|
64
|
+
applyWrite: (memberId, plan, executor) => deps.metafields.values.applyWrite(memberId, plan, {
|
|
65
65
|
writtenBy: { type: 'import', id: null },
|
|
66
66
|
executor,
|
|
67
67
|
}),
|
|
@@ -91,7 +91,7 @@ function makeImporter(deps) {
|
|
|
91
91
|
productRepository: deps.productRepository,
|
|
92
92
|
}),
|
|
93
93
|
gifts,
|
|
94
|
-
|
|
94
|
+
metafields,
|
|
95
95
|
email,
|
|
96
96
|
report,
|
|
97
97
|
addJob: deps.addJob,
|
|
@@ -100,7 +100,7 @@ function makeImporter(deps) {
|
|
|
100
100
|
});
|
|
101
101
|
}
|
|
102
102
|
// Build the members CSV exporter. The same composition root from the other direction:
|
|
103
|
-
// knex and the members id lookup are wired here, and the
|
|
103
|
+
// knex and the members id lookup are wired here, and the metafields definitions and
|
|
104
104
|
// values services are injected (boot builds them before this one).
|
|
105
105
|
function makeExporter({ definitions, values, }) {
|
|
106
106
|
const exporter = new exporter_1.default({
|
|
@@ -118,7 +118,7 @@ function makeExporter({ definitions, values, }) {
|
|
|
118
118
|
return page.data.map((member) => member.id);
|
|
119
119
|
},
|
|
120
120
|
},
|
|
121
|
-
|
|
121
|
+
metafields: {
|
|
122
122
|
// Boot builds the definitions and values services before this one, so they
|
|
123
123
|
// are always present -- no not-initialised state to guard.
|
|
124
124
|
activeDefinitions: async () => definitions.browse(),
|
|
@@ -7,6 +7,8 @@ const PaymentsService = require('./services/payments-service');
|
|
|
7
7
|
const TokenService = require('./services/token-service');
|
|
8
8
|
const GeolocationService = require('./services/geolocation-service');
|
|
9
9
|
const MemberBREADService = require('./services/member-bread-service');
|
|
10
|
+
const metafields = require('../../members-metafields');
|
|
11
|
+
const { MemberAccountService } = require('../account-service');
|
|
10
12
|
const MemberRepository = require('./repositories/member-repository');
|
|
11
13
|
const NextPaymentCalculator = require('./services/next-payment-calculator');
|
|
12
14
|
|
|
@@ -70,8 +72,8 @@ module.exports = function MembersAPI({
|
|
|
70
72
|
commentsService,
|
|
71
73
|
emailAddressService,
|
|
72
74
|
giftService,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
metafieldValues,
|
|
76
|
+
metafieldDefinitions,
|
|
75
77
|
}) {
|
|
76
78
|
const tokenService = new TokenService({
|
|
77
79
|
privateKey,
|
|
@@ -153,8 +155,8 @@ module.exports = function MembersAPI({
|
|
|
153
155
|
nextPaymentCalculator,
|
|
154
156
|
commentsService,
|
|
155
157
|
giftService,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
+
metafieldValues,
|
|
159
|
+
metafieldDefinitions,
|
|
158
160
|
});
|
|
159
161
|
|
|
160
162
|
const geolocationService = new GeolocationService();
|
|
@@ -356,11 +358,27 @@ module.exports = function MembersAPI({
|
|
|
356
358
|
}
|
|
357
359
|
|
|
358
360
|
async function getMemberIdentityData(email) {
|
|
359
|
-
return memberBREADService.read({ email }, {
|
|
361
|
+
return memberBREADService.read({ email }, { metafieldsFor: null });
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const account = new MemberAccountService({
|
|
365
|
+
memberBREADService,
|
|
366
|
+
members: users,
|
|
367
|
+
emailSuppressionList,
|
|
368
|
+
metafieldValues: metafields.values,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
async function getMemberIdentity(transientId) {
|
|
372
|
+
if (!transientId) {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const member = await users.get({ transient_id: transientId });
|
|
377
|
+
return member ? { id: member.id, email: member.get('email') } : null;
|
|
360
378
|
}
|
|
361
379
|
|
|
362
380
|
async function getMemberIdentityDataFromTransientId(transientId) {
|
|
363
|
-
return memberBREADService.read({ transient_id: transientId }, {
|
|
381
|
+
return memberBREADService.read({ transient_id: transientId }, { metafieldsFor: null });
|
|
364
382
|
}
|
|
365
383
|
|
|
366
384
|
async function cycleTransientId(memberId) {
|
|
@@ -500,6 +518,7 @@ module.exports = function MembersAPI({
|
|
|
500
518
|
getMemberIdentityToken,
|
|
501
519
|
getMemberEntitlementToken,
|
|
502
520
|
getMemberIdentityDataFromTransientId,
|
|
521
|
+
getMemberIdentity,
|
|
503
522
|
getMemberIdentityData,
|
|
504
523
|
cycleTransientId,
|
|
505
524
|
setMemberGeolocationFromIp,
|
|
@@ -508,6 +527,7 @@ module.exports = function MembersAPI({
|
|
|
508
527
|
sendEmailWithMagicLink,
|
|
509
528
|
getMagicLink,
|
|
510
529
|
members: users,
|
|
530
|
+
account,
|
|
511
531
|
memberBREADService,
|
|
512
532
|
events: eventRepository,
|
|
513
533
|
productRepository,
|
|
@@ -878,10 +878,10 @@ module.exports = class MemberRepository {
|
|
|
878
878
|
(n) => n.attributes.status === 'archived',
|
|
879
879
|
);
|
|
880
880
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
881
|
+
// bookshelf-relations only touches the join table when the key is present,
|
|
882
|
+
// so an update that does not set newsletters leaves them all attached and
|
|
883
|
+
// has nothing to preserve.
|
|
884
|
+
if (memberData.newsletters && archivedNewsletters.length > 0) {
|
|
885
885
|
archivedNewsletters.forEach((n) => memberData.newsletters.push(n));
|
|
886
886
|
}
|
|
887
887
|
}
|