ghost 6.61.0 → 6.62.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-custom-field-types-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-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/core/boot.js +54 -22
- 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-Dyae_UT6.js} +1 -1
- package/core/built/admin/assets/account-migration-CESa0mnX.js +1 -0
- package/core/built/admin/assets/activitypub/{account-migration-C-aej4x_.js → account-migration-By69CgCp.js} +16 -16
- package/core/built/admin/assets/activitypub/activitypub.js +9 -9
- package/core/built/admin/assets/activitypub/{bluesky-sharing-BXkA5mqV.js → bluesky-sharing-BJcPMrDd.js} +36 -36
- package/core/built/admin/assets/activitypub/{content-formatters-CHcyMFk4.js → content-formatters-3rTHg3mp.js} +3 -3
- package/core/built/admin/assets/activitypub/{domain-B3ihkPde.js → domain-DUR4xSkV.js} +121 -121
- package/core/built/admin/assets/activitypub/{edit-profile-DsZM3rTX.js → edit-profile-BqtfzxCp.js} +40 -40
- package/core/built/admin/assets/activitypub/{explore-BodNrZgR.js → explore-BxuJd-J4.js} +26 -26
- package/core/built/admin/assets/activitypub/{feed-PwH1iJ84.js → feed-BM1TcksA.js} +48 -48
- package/core/built/admin/assets/activitypub/{field-D06-kmOJ.js → field-Dn7HHx2-.js} +2 -2
- package/core/built/admin/assets/activitypub/inbox-CCjkuow2.js +1284 -0
- package/core/built/admin/assets/activitypub/label-1AA_s9Fa.js +16 -0
- package/core/built/admin/assets/activitypub/layout-2-0bw6HN.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-D1Yapsod.js → moderation-CnmxEB8w.js} +91 -91
- package/core/built/admin/assets/activitypub/{note-C5zjqq5C.js → note-ZKc_Bnba.js} +23 -23
- package/core/built/admin/assets/activitypub/{notifications-B9p8eCHD.js → notifications-CB2tJZau.js} +48 -48
- package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-BsJ9E5qf.js} +2 -2
- package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-CSUJJIlh.js} +2 -2
- package/core/built/admin/assets/activitypub/{preferences-BCqUdC3v.js → preferences-0-JZnUkI.js} +1519 -1519
- package/core/built/admin/assets/activitypub/{profile-BRCWoFem.js → profile-C35cFIhM.js} +183 -183
- package/core/built/admin/assets/activitypub/{routes-BSXT992i.js → routes-BD4vscyc.js} +740 -731
- package/core/built/admin/assets/activitypub/settings-BsMROdqh.js +315 -0
- package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-O0RL9YCN.js} +2 -2
- package/core/built/admin/assets/activitypub/{step-1-B-YfsVeO.js → step-1-BMSx7c_X.js} +4 -4
- package/core/built/admin/assets/activitypub/{step-3-D6BFMXL_.js → step-3-CLlOZTyt.js} +3 -3
- package/core/built/admin/assets/activitypub/{tabs-GpNecvfB.js → tabs-Dxk-b9M-.js} +306 -306
- package/core/built/admin/assets/activitypub/{topic-filter-BPDeQQys.js → topic-filter-5yZH6tId.js} +2 -2
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-BoVOxXkV.js → use-activity-pub-queries-CV50qe03.js} +2 -2
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-wVBX7swM.js → use-reply-chain-data-Cbvzgjzd.js} +30 -30
- package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-BjcoP_HC.js} +7 -5
- package/core/built/admin/assets/add-integration-modal-BlF6rs_f.js +1 -0
- package/core/built/admin/assets/add-newsletter-modal-CglVQqah.js +1 -0
- package/core/built/admin/assets/add-recommendation-modal-wz7BsuaG.js +1 -0
- package/core/built/admin/assets/analytics-C4HE1gBg.js +1 -0
- package/core/built/admin/assets/{announcement-bar-modal-DM3cYOpo.js → announcement-bar-modal-Ci4zz8jO.js} +1 -1
- package/core/built/admin/assets/{api-keys-BLm2NDBh.js → api-keys-Ck-Yteiv.js} +1 -1
- package/core/built/admin/assets/{audience-9mwU5TW6.js → audience-CtbA54Sn.js} +1 -1
- package/core/built/admin/assets/{automated-emails-te1D5kq-.js → automated-emails-D5VVMND9.js} +1 -1
- package/core/built/admin/assets/automations-CzKt5fb8.js +1 -0
- package/core/built/admin/assets/bluesky-sharing-BEtJ_gL_.js +1 -0
- package/core/built/admin/assets/{breadcrumb-DLiqCyFc.js → breadcrumb-zUrZrBtW.js} +1 -1
- package/core/built/admin/assets/{button-B2jcu6bk.js → button-eNMKQWXr.js} +1 -1
- package/core/built/admin/assets/{chart-helpers-Fo3bUL3K.js → chart-helpers-CfBKt0vT.js} +1 -1
- package/core/built/admin/assets/{checkbox-BfKktMph.js → checkbox-CgOn_tKW.js} +1 -1
- package/core/built/admin/assets/{chunk.524.60ca4692d91c6022042f.js → chunk.524.a697dee88db67fdf6021.js} +4 -4
- package/core/built/admin/assets/{chunk.582.525c7617c2d9e94c940a.js → chunk.582.5ed5d124cfca9c259b9c.js} +6 -6
- package/core/built/admin/assets/{chunk.896.435fe0637944d4a69810.js → chunk.598.7e056fabb47ce7dbd73f.js} +14 -14
- package/core/built/admin/assets/{code-editor-view-CYVu4EW6.js → code-editor-view-BYNoAoNV.js} +1 -1
- package/core/built/admin/assets/{code-editor-view-DCQJxsfU.js → code-editor-view-K2wI-I5f.js} +1 -1
- package/core/built/admin/assets/color-picker-Ddw80xX6.js +3 -0
- package/core/built/admin/assets/color-picker-field-D9nUhvA7.js +1 -0
- package/core/built/admin/assets/combobox-w9j8PPQT.js +1 -0
- package/core/built/admin/assets/command-BfpHORBv.js +1 -0
- package/core/built/admin/assets/comments-BLmCmyCs.js +1 -0
- package/core/built/admin/assets/confirmation-context-CBM8G0Vj.js +1 -0
- package/core/built/admin/assets/{content-api-modal-CyQEC3fr.js → content-api-modal-TXRz3U7S.js} +1 -1
- package/core/built/admin/assets/context-menu-_QMdd3kp.js +1 -0
- package/core/built/admin/assets/{copy-field-B3M1s78L.js → copy-field-6N01S07E.js} +1 -1
- package/core/built/admin/assets/create-ghost-browse-value-source-qIBymvvf.js +1 -0
- package/core/built/admin/assets/custom-field-type-option-BddFlJFa.js +1 -0
- package/core/built/admin/assets/custom-integration-modal-DmNquxUV.js +1 -0
- package/core/built/admin/assets/{date-range-select-DD2RKkgB.js → date-range-select-uvz_DtPh.js} +1 -1
- package/core/built/admin/assets/design-and-theme-modal-BSmo12Op.js +2 -0
- package/core/built/admin/assets/dirty-confirm-dialog-BZ1iytEd.js +1 -0
- package/core/built/admin/assets/{disabled-sources-indicator-Cvy47bE2.js → disabled-sources-indicator-DMRrxsiJ.js} +1 -1
- package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
- package/core/built/admin/assets/domain-BNYrt0aD.js +1 -0
- package/core/built/admin/assets/dropzone-D7nFdAe5.js +5 -0
- package/core/built/admin/assets/edit-profile-C5Asm4LA.js +1 -0
- package/core/built/admin/assets/editor-REokrzci.js +8 -0
- package/core/built/admin/assets/{embed-signup-form-modal-DeBMLxlL.js → embed-signup-form-modal-Ds6mPEi5.js} +1 -1
- package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
- package/core/built/admin/assets/explore-UY10Egsp.js +1 -0
- package/core/built/admin/assets/feature-image-placeholder-D1iF_8bc.js +1 -0
- package/core/built/admin/assets/feed-81C8mJWR.js +1 -0
- package/core/built/admin/assets/{field-Cj8lmDOo.js → field-Dihp5p18.js} +1 -1
- package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
- package/core/built/admin/assets/filter-sources-BO9xUPj7.js +1 -0
- package/core/built/admin/assets/filters-CRUWecfY.js +1 -0
- package/core/built/admin/assets/filters-DirqNXjH.js +1 -0
- package/core/built/admin/assets/first-promoter-modal-CT6MxYZb.js +1 -0
- package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8eabfc1ece81b03cf7b90780d31487e8.css} +1 -1
- package/core/built/admin/assets/{ghost-3894eedcc6968f658578c0abfe942aab.js → ghost-c2848508292937415f20f5a830eea59e.js} +31 -28
- package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-a7bebe2c561f55369dcf29f4c820f7ff.css} +1 -1
- package/core/built/admin/assets/gift-link-modal-CQVAye17.js +1 -0
- package/core/built/admin/assets/growth-BWIu-6xj.js +3 -0
- package/core/built/admin/assets/growth-DU29oxeA.js +1 -0
- package/core/built/admin/assets/history-modal-CFd1Hvx6.js +1 -0
- package/core/built/admin/assets/{html-field-C8qVGGC1.js → html-field-CJBCLTvv.js} +1 -1
- package/core/built/admin/assets/{images-h8VZEQ9k.js → images-scfkWZiK.js} +1 -1
- package/core/built/admin/assets/{inbox-BYd1M06Q.js → inbox-Mcp4DXZN.js} +14 -14
- package/core/built/admin/assets/index-6MkPdCtr.js +4 -0
- package/core/built/admin/assets/index-Bn7QhcZu.css +2 -0
- package/core/built/admin/assets/index.es-CNnuNH0d.js +1 -0
- package/core/built/admin/assets/{input-group-D8sCXRF5.js → input-group-CMhe2DvY.js} +1 -1
- package/core/built/admin/assets/invite-user-modal-DfheMXs0.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-DBSqAuiI.js} +3 -3
- package/core/built/admin/assets/koenig-loader-aFQNlJlD.js +2 -0
- package/core/built/admin/assets/{kpi-card-DZQk_0W8.js → kpi-card-DBRMfGOW.js} +1 -1
- package/core/built/admin/assets/{kpi-card-DW_2y3ug.js → kpi-card-DFafD1qq.js} +1 -1
- package/core/built/admin/assets/{kpi-helpers-PueTKuA6.js → kpi-helpers-Cv8i8hns.js} +1 -1
- package/core/built/admin/assets/{kpi-tabs-CojDs-Qz.js → kpi-tabs-BJItvLYm.js} +1 -1
- package/core/built/admin/assets/{label-DjbT91GM.js → label-BnSCvffu.js} +1 -1
- package/core/built/admin/assets/label-picker-KVoo91sh.js +1 -0
- package/core/built/admin/assets/layout-Bjv2Ll-5.js +1 -0
- package/core/built/admin/assets/member-custom-fields-DDQV6QeG.js +1 -0
- package/core/built/admin/assets/member-detail-CdJF6Agw.js +1 -0
- package/core/built/admin/assets/members-DjQbq9Z2.js +4 -0
- package/core/built/admin/assets/moderation-AgCIEso4.js +1 -0
- package/core/built/admin/assets/{multi-select-combobox-B6LiRzDO.js → multi-select-combobox-BcITkUVr.js} +1 -1
- package/core/built/admin/assets/navigation-modal-BkT7b1M2.js +1 -0
- package/core/built/admin/assets/newsletter-BMMAuvgq.js +1 -0
- package/core/built/admin/assets/newsletter-detail-modal-0SCJ7Zpm.js +1 -0
- package/core/built/admin/assets/{newsletter-emails-CFeLlt4z.js → newsletter-emails-DKzwafuh.js} +1 -1
- package/core/built/admin/assets/newsletters-BRBb_uQC.js +1 -0
- package/core/built/admin/assets/note-DyGHtS9a.js +1 -0
- package/core/built/admin/assets/notifications-ZgWniKna.js +1 -0
- package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
- package/core/built/admin/assets/offers-container-modal-B-E8TIWr.js +1 -0
- package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-CzIsre-d.js} +1 -1
- package/core/built/admin/assets/onboarding-qg8Akovm.js +1 -0
- package/core/built/admin/assets/{onboarding-route-Dmc4IPm3.js → onboarding-route-CaavZulg.js} +1 -1
- package/core/built/admin/assets/overview-BW8GLeYi.js +1 -0
- package/core/built/admin/assets/overview-BkXZNzaZ.js +1 -0
- package/core/built/admin/assets/{page-header-BR_nbIPp.js → page-header-De0VzKBi.js} +1 -1
- package/core/built/admin/assets/pagemenu-B5KKCpbA.js +1 -0
- package/core/built/admin/assets/pages-jgaFm69d.js +1 -0
- package/core/built/admin/assets/pages-route-CIUAQxtY.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-BZ2J9w3n.js} +1 -1
- package/core/built/admin/assets/portal-frame-B6Hr9wHc.js +1 -0
- package/core/built/admin/assets/portal-modal-D4ceei3t.js +1 -0
- package/core/built/admin/assets/post-analytics-header-BYCsT0GP.js +1 -0
- package/core/built/admin/assets/post-analytics-ot7f6pih.js +1 -0
- package/core/built/admin/assets/{post-analytics-provider-CLfKGWZy.js → post-analytics-provider-Bo1gmYaP.js} +1 -1
- package/core/built/admin/assets/{post-share-modal-Cl0NXRJr.js → post-share-modal-C-PaYZ_e.js} +1 -1
- package/core/built/admin/assets/posts-DuGazgTb.js +1 -0
- package/core/built/admin/assets/posts-list-screen-CBGGgjjj.js +2 -0
- package/core/built/admin/assets/posts-route-D6xmS7Vf.js +1 -0
- package/core/built/admin/assets/preferences-C5YJLp74.js +5 -0
- package/core/built/admin/assets/{preview-modal-C-BL-F9k.js → preview-modal-BfeFqi5y.js} +1 -1
- package/core/built/admin/assets/profile-B8mx2yAu.js +1 -0
- package/core/built/admin/assets/radio-group-DczlLKOn.js +1 -0
- package/core/built/admin/assets/{schemas-4UPic-oD.js → schemas-DppqmpeJ.js} +1 -1
- package/core/built/admin/assets/select-cb0t_TAJ.js +1 -0
- package/core/built/admin/assets/settings-DZqxR0Da.js +1 -0
- package/core/built/admin/assets/settings-DvfTNdHQ.js +4 -0
- package/core/built/admin/assets/{settings-breadcrumbs-CyP_9zTo.js → settings-breadcrumbs-DLzbRRSt.js} +1 -1
- package/core/built/admin/assets/share-modal-D2-Bz1_I.js +1 -0
- package/core/built/admin/assets/slack-modal-DYDTUria.js +1 -0
- package/core/built/admin/assets/{sort-button-Cc-Z96sA.js → sort-button-VVeQjjbu.js} +1 -1
- package/core/built/admin/assets/{source-icon-v6PUnmyM.js → source-icon-Ck5_5Kgq.js} +1 -1
- package/core/built/admin/assets/stats-Rjmk5owg.js +1 -0
- package/core/built/admin/assets/stats-view-BGGmkmgv.js +1 -0
- package/core/built/admin/assets/{step-1-DSRp2vBj.js → step-1-CsaBjeN4.js} +1 -1
- package/core/built/admin/assets/{step-2-COqv2g0u.js → step-2-D2vnxOOM.js} +1 -1
- package/core/built/admin/assets/{step-3-6W1NMVQc.js → step-3-wBoLdGEb.js} +2 -2
- package/core/built/admin/assets/{stripe-button-D2K42Uty.js → stripe-button-CDgLz0S0.js} +1 -1
- package/core/built/admin/assets/stripe-connect-modal-CSjMJetP.js +1 -0
- package/core/built/admin/assets/{table-B2pIKjVh.js → table-Do6iQ83Q.js} +1 -1
- package/core/built/admin/assets/{tabs-SaW_UT-Q.js → tabs-D2yWLMp_.js} +1 -1
- package/core/built/admin/assets/tag-detail-BhXlOsCa.js +2 -0
- package/core/built/admin/assets/tags-ldukRApe.js +1 -0
- package/core/built/admin/assets/testimonials-modal-CtnZBJKl.js +1 -0
- package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +1 -0
- package/core/built/admin/assets/{toggle-group-EM9WpESu.js → toggle-group-ByUJsxwD.js} +1 -1
- package/core/built/admin/assets/{topic-filter-DY4gNHn2.js → topic-filter-BgC3g5_v.js} +1 -1
- package/core/built/admin/assets/{transistor-modal-CpyPG-MH.js → transistor-modal-Drr0SNfo.js} +1 -1
- package/core/built/admin/assets/{trend-badge-ByMkuAuH.js → trend-badge-6ye93YAW.js} +1 -1
- package/core/built/admin/assets/{unsplash-modal-Cv2Q6GtY.js → unsplash-modal-p6AoQoWp.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data-CHvjMYuT.js → use-analytics-data-CWCMAESo.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-Cw3WQHy8.js} +1 -1
- package/core/built/admin/assets/use-filter-params-BIni9taJ.js +1 -0
- package/core/built/admin/assets/use-growth-stats-DCVG3s9w.js +1 -0
- package/core/built/admin/assets/{use-limiter-cwJvsNBo.js → use-limiter-D2WRRx0H.js} +1 -1
- package/core/built/admin/assets/{use-pintura-config-CzTfnufz.js → use-pintura-config-h-J0Lvta.js} +1 -1
- package/core/built/admin/assets/{use-pintura-editor-BDBXWUYq.js → use-pintura-editor-BfN1UwzH.js} +1 -1
- package/core/built/admin/assets/use-post-referrers-Czg47m8s.js +1 -0
- package/core/built/admin/assets/use-reply-chain-data-ns0caK8k.js +1 -0
- package/core/built/admin/assets/{use-router-history-entry-Bg6BhBQQ.js → use-router-history-entry-uldn7zJO.js} +1 -1
- package/core/built/admin/assets/{use-setting-group-VM7FQwMY.js → use-setting-group-DpcuCUDg.js} +1 -1
- package/core/built/admin/assets/use-settings-navigation-CZjGrhsp.js +1 -0
- package/core/built/admin/assets/{use-simple-pagination-Dum6Irbs.js → use-simple-pagination-DzJWobPR.js} +1 -1
- package/core/built/admin/assets/{use-staff-users-cZg4ugOF.js → use-staff-users-Csipb-O0.js} +1 -1
- package/core/built/admin/assets/use-tinybird-query-CSnGXzZh.js +1 -0
- package/core/built/admin/assets/use-tinybird-token-DTOKRR7e.js +1 -0
- package/core/built/admin/assets/{use-unsaved-changes-guard-BAy0RANR.js → use-unsaved-changes-guard-CBzs-KPi.js} +1 -1
- package/core/built/admin/assets/{use-url-input-Df5QzNa7.js → use-url-input-DFr8lCbS.js} +1 -1
- package/core/built/admin/assets/user-detail-modal-B_iUClI6.js +1 -0
- package/core/built/admin/assets/users-Cg-OeGzC.js +1 -0
- package/core/built/admin/assets/{virtual-list-DEx8WgiO.js → virtual-list-BW-padMe.js} +1 -1
- package/core/built/admin/assets/web-C1v33ehA.js +2 -0
- package/core/built/admin/assets/web-C4BKzn2T.js +1 -0
- package/core/built/admin/assets/{zapier-modal-Cw3BTBUu.js → zapier-modal-BBFfI6Ml.js} +1 -1
- package/core/built/admin/index.html +17 -22
- 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/api/endpoints/index.js +2 -2
- package/core/server/api/endpoints/mail.js +1 -1
- package/core/server/api/endpoints/{member-custom-fields.js → member-metafields.js} +27 -28
- package/core/server/api/endpoints/members.js +4 -4
- package/core/server/api/endpoints/posts.js +3 -3
- package/core/server/api/endpoints/utils/serializers/input/members.js +4 -7
- package/core/server/api/endpoints/utils/serializers/output/index.js +2 -2
- package/core/server/api/endpoints/utils/serializers/output/{member-custom-fields.js → member-metafields.js} +2 -4
- package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
- 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/importer/importers/data/data-importer.js +3 -3
- package/core/server/data/migrations/utils/migrations.js +1 -1
- package/core/server/lib/image/image-size.js +24 -0
- package/core/server/lib/package-json/parse.js +2 -2
- package/core/server/models/member.js +6 -17
- package/core/server/models/post.js +2 -2
- package/core/server/models/relations/authors.js +2 -16
- package/core/server/models/user.js +9 -2
- package/core/server/services/auth/passwordreset.js +13 -0
- 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/batch-sending-service.js +0 -4
- package/core/server/services/email-service/email-renderer.js +14 -4
- package/core/server/services/email-service/email-service-wrapper.js +0 -9
- package/core/server/services/email-service/mailgun-email-provider.js +20 -9
- 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/index.js +3 -3
- 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/register-job-handlers.js +21 -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/api.js +1 -0
- package/core/server/services/members/import-export/csv/parse.js +0 -7
- package/core/server/services/members/import-export/import/completion-email.js +2 -5
- package/core/server/services/members/import-export/import/row.js +0 -3
- package/core/server/services/members/import-export/index.js +4 -11
- 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 +4 -6
- package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
- package/core/server/services/members/members-api/services/member-bread-service.js +34 -62
- package/core/server/services/members/members-api/services/payments-service.js +1 -1
- package/core/server/services/members/service.js +1 -5
- package/core/server/services/members-custom-fields/bindings-service.js +2 -1
- package/core/server/services/members-custom-fields/codec.js +3 -4
- package/core/server/services/members-custom-fields/definitions-service.js +62 -10
- package/core/server/services/members-custom-fields/filter.js +75 -93
- package/core/server/services/members-custom-fields/key.js +2 -1
- package/core/server/services/members-custom-fields/models.js +1 -1
- package/core/server/services/members-custom-fields/serializers.js +3 -5
- package/core/server/services/members-custom-fields/values-service.js +50 -28
- package/core/server/services/mentions/mention-controller.js +23 -21
- package/core/server/services/mentions/process-webmention-job.js +16 -0
- package/core/server/services/mentions/service.js +8 -4
- 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 +26 -5
- package/core/server/services/stripe/stripe-api.js +2 -0
- package/core/server/services/stripe/stripe-service.js +20 -10
- package/core/server/services/stripe/webhook-controller.js +10 -0
- package/core/server/services/tier-checkout-config/codec.js +9 -5
- package/core/server/services/tier-checkout-config/models.js +9 -3
- package/core/server/services/tier-checkout-config/queries.js +4 -4
- package/core/server/services/tier-checkout-config/serializers.js +16 -10
- package/core/server/services/tier-checkout-config/service.js +13 -12
- 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/web/admin/controller.js +1 -1
- package/core/server/web/api/endpoints/admin/routes.js +19 -16
- package/core/shared/config/env/config.testing-mysql.json +1 -1
- package/core/shared/labs.js +5 -2
- package/package.json +24 -23
- package/pnpm-lock.yaml +704 -69
- package/pnpm-workspace.yaml +8 -5
- 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/automations-DpUNUdcZ.js +0 -1
- package/core/built/admin/assets/bluesky-sharing-Cjrv_f62.js +0 -1
- 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/growth-D6mhcx3q.js +0 -1
- package/core/built/admin/assets/history-modal-iKwUY3XR.js +0 -1
- 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/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/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/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/radio-group-Bgz60i81.js +0 -1
- 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/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-post-referrers-DbY-mzci.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-tinybird-query-B1IMyAcv.js +0 -39
- package/core/built/admin/assets/use-tinybird-token-Bow0Zwn8.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/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/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
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ObjectId = require('bson-objectid').default;
|
|
4
|
+
const { chunk: chunkArray } = require('lodash');
|
|
5
|
+
const moment = require('moment');
|
|
6
|
+
// Removes expired comped entries from the members_products table, moves the
|
|
7
|
+
// affected members from comped to free and records a comped->free status
|
|
8
|
+
// event for each of them. The three writes commit or roll back together, so a
|
|
9
|
+
// failed run leaves the source rows in place and a repeat run redoes the whole
|
|
10
|
+
// unit of work instead of finishing a half-applied one.
|
|
11
|
+
async function cleanExpiredComped({ db, models, events, logging, sentry, }) {
|
|
12
|
+
const startedAt = Date.now();
|
|
13
|
+
const { deletedSubscriptionCount, updatedMemberCount, updatedMembers, now } = await db.knex.transaction(async (trx) => {
|
|
14
|
+
const expiredCompedRows = await trx('members_products')
|
|
15
|
+
// we need to be careful about the type here. .format() is the only
|
|
16
|
+
// thing that works across SQLite and MySQL: an ISO cutoff compares
|
|
17
|
+
// lexically against SQLite's 'YYYY-MM-DD HH:mm:ss' text and its 'T'
|
|
18
|
+
// sorts above ' ', wrongly matching same-UTC-day expiries
|
|
19
|
+
.where('expiry_at', '<', moment.utc().startOf('day').format('YYYY-MM-DD HH:mm:ss'))
|
|
20
|
+
.select('*');
|
|
21
|
+
if (!expiredCompedRows.length) {
|
|
22
|
+
return {
|
|
23
|
+
deletedSubscriptionCount: 0,
|
|
24
|
+
updatedMemberCount: 0,
|
|
25
|
+
updatedMembers: [],
|
|
26
|
+
now: new Date(),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const rowIds = expiredCompedRows.map((d) => d.id);
|
|
30
|
+
const memberIds = expiredCompedRows.map((d) => d.member_id);
|
|
31
|
+
// Only members still in the comped status change; anyone already paid,
|
|
32
|
+
// free or deleted is left untouched. The rows are locked for the rest
|
|
33
|
+
// of the transaction so a concurrent status change cannot slip between
|
|
34
|
+
// this read and the update below (forUpdate is a no-op on SQLite,
|
|
35
|
+
// where the single-writer transaction already guarantees this). The
|
|
36
|
+
// members rows are locked BEFORE the members_products delete so this
|
|
37
|
+
// transaction acquires locks in the same members -> members_products
|
|
38
|
+
// order as the member-edit flows (Bookshelf edit, linkSubscription);
|
|
39
|
+
// the reverse order could deadlock against them.
|
|
40
|
+
const compedMembers = await trx('members')
|
|
41
|
+
.whereIn('id', memberIds)
|
|
42
|
+
.andWhere('status', 'comped')
|
|
43
|
+
.forUpdate();
|
|
44
|
+
const deletedCount = await trx('members_products').whereIn('id', rowIds).del();
|
|
45
|
+
const updateMemberIds = compedMembers.map((d) => d.id);
|
|
46
|
+
const updatedAt = new Date();
|
|
47
|
+
const updatedCount = await trx('members').whereIn('id', updateMemberIds).update({
|
|
48
|
+
status: 'free',
|
|
49
|
+
updated_at: updatedAt,
|
|
50
|
+
});
|
|
51
|
+
const statusEvents = compedMembers.map((member) => {
|
|
52
|
+
return {
|
|
53
|
+
id: ObjectId().toHexString(),
|
|
54
|
+
member_id: member.id,
|
|
55
|
+
from_status: member.status,
|
|
56
|
+
to_status: 'free',
|
|
57
|
+
created_at: updatedAt,
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
// SQLite >= 3.32.0 can support 32766 host parameters
|
|
61
|
+
// each row uses 5 variables so ⌊32766/5⌋ = 6553
|
|
62
|
+
const chunkSize = 6553;
|
|
63
|
+
for (const chunk of chunkArray(statusEvents, chunkSize)) {
|
|
64
|
+
await trx('members_status_events').insert(chunk);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
deletedSubscriptionCount: deletedCount,
|
|
68
|
+
updatedMemberCount: updatedCount,
|
|
69
|
+
updatedMembers: compedMembers,
|
|
70
|
+
now: updatedAt,
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
// Emitted after the commit so listeners never observe state that could
|
|
74
|
+
// still roll back. A failed emission is logged and skipped rather than
|
|
75
|
+
// failing the job: the database changes are already durable and the
|
|
76
|
+
// emitted_event_count below makes the shortfall visible.
|
|
77
|
+
let emittedEventCount = 0;
|
|
78
|
+
for (const member of updatedMembers) {
|
|
79
|
+
const emitted = await emitMemberEditedEvent({ member, now, models, events, logging, sentry });
|
|
80
|
+
if (emitted) {
|
|
81
|
+
emittedEventCount += 1;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
logging.info({
|
|
85
|
+
system: {
|
|
86
|
+
event: 'clean_expired_comped.completed',
|
|
87
|
+
deleted_subscription_count: deletedSubscriptionCount,
|
|
88
|
+
updated_member_count: updatedMemberCount,
|
|
89
|
+
emitted_event_count: emittedEventCount,
|
|
90
|
+
duration_ms: Date.now() - startedAt,
|
|
91
|
+
},
|
|
92
|
+
}, `[Background Job] clean-expired-comped removed ${deletedSubscriptionCount} expired subscriptions and updated ${updatedMemberCount} members`);
|
|
93
|
+
return { deletedSubscriptionCount, updatedMemberCount, emittedEventCount };
|
|
94
|
+
}
|
|
95
|
+
// Emits member.edited in the shape its listeners (webhooks in particular)
|
|
96
|
+
// expect: a freshly loaded model whose _previousAttributes carry the
|
|
97
|
+
// pre-cleanup status and _changed the comped->free transition, with an
|
|
98
|
+
// internal context.
|
|
99
|
+
async function emitMemberEditedEvent({ member, now, models, events, logging, sentry, }) {
|
|
100
|
+
try {
|
|
101
|
+
const model = await models.Member.findOne({ id: member.id }, { require: true, context: { internal: true } });
|
|
102
|
+
model._previousAttributes = normalizeDates({
|
|
103
|
+
...model.attributes,
|
|
104
|
+
status: member.status,
|
|
105
|
+
updated_at: member.updated_at,
|
|
106
|
+
});
|
|
107
|
+
model._changed = normalizeDates({
|
|
108
|
+
status: 'free',
|
|
109
|
+
updated_at: now,
|
|
110
|
+
});
|
|
111
|
+
events.emit('member.edited', model, { context: { internal: true } });
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (isNotFoundError(err)) {
|
|
116
|
+
logging.warn(`Could not emit member.edited for expired comped member: Member ${member.id} was not found`);
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
logging.error(err);
|
|
120
|
+
sentry.captureException(err);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function normalizeDates(attributes) {
|
|
125
|
+
const normalized = { ...attributes };
|
|
126
|
+
for (const [key, value] of Object.entries(normalized)) {
|
|
127
|
+
if (key.endsWith('_at') && value && !(value instanceof Date)) {
|
|
128
|
+
normalized[key] = moment.utc(value).toDate();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return normalized;
|
|
132
|
+
}
|
|
133
|
+
function isNotFoundError(err) {
|
|
134
|
+
if (!err || typeof err !== 'object') {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
const errorType = 'errorType' in err ? err.errorType : undefined;
|
|
138
|
+
const name = 'name' in err ? err.name : undefined;
|
|
139
|
+
const message = 'message' in err ? err.message : undefined;
|
|
140
|
+
return (errorType === 'NotFoundError' ||
|
|
141
|
+
name === 'NotFoundError' ||
|
|
142
|
+
message === 'NotFound' ||
|
|
143
|
+
message === 'EmptyResponse');
|
|
144
|
+
}
|
|
145
|
+
exports.default = cleanExpiredComped;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
1
|
const logging = require('@tryghost/logging');
|
|
3
|
-
const
|
|
2
|
+
const errors = require('@tryghost/errors');
|
|
4
3
|
const CleanTokensJob = require('./clean-tokens-job').default;
|
|
4
|
+
const CleanExpiredCompedJob = require('./clean-expired-comped-job').default;
|
|
5
|
+
const cleanTokensTask = require('./clean-tokens-task').default;
|
|
6
|
+
const cleanExpiredCompedTask = require('./clean-expired-comped-task').default;
|
|
5
7
|
|
|
6
8
|
let hasScheduled = {
|
|
7
9
|
expiredComped: false,
|
|
8
10
|
tokens: false,
|
|
9
11
|
};
|
|
10
12
|
|
|
13
|
+
let tasks;
|
|
14
|
+
|
|
11
15
|
function alreadyScheduledOrTest(key) {
|
|
12
16
|
return hasScheduled[key] || process.env.NODE_ENV.startsWith('test');
|
|
13
17
|
}
|
|
@@ -19,43 +23,63 @@ function randomDailyCron(maxHour = 24) {
|
|
|
19
23
|
return `${s} ${m} ${h} * * *`;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
function
|
|
23
|
-
if (
|
|
24
|
-
|
|
26
|
+
function getTasks() {
|
|
27
|
+
if (!tasks) {
|
|
28
|
+
throw new errors.IncorrectUsageError({
|
|
29
|
+
message: 'Member jobs used before init(). Call init() from boot first.',
|
|
30
|
+
});
|
|
25
31
|
}
|
|
32
|
+
return tasks;
|
|
33
|
+
}
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
module.exports = {
|
|
36
|
+
// Composition root for the member cleanup tasks. Idempotent because tests
|
|
37
|
+
// may boot more than once per process.
|
|
38
|
+
init() {
|
|
39
|
+
if (tasks) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
30
42
|
|
|
31
|
-
|
|
43
|
+
const db = require('../../../data/db');
|
|
44
|
+
const models = require('../../../models');
|
|
45
|
+
const events = require('../../../lib/common/events');
|
|
46
|
+
const sentry = require('../../../../shared/sentry');
|
|
32
47
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
48
|
+
tasks = {
|
|
49
|
+
cleanTokens: () => cleanTokensTask({ db, logging }),
|
|
50
|
+
cleanExpiredComped: () => cleanExpiredCompedTask({ db, models, events, logging, sentry }),
|
|
51
|
+
};
|
|
52
|
+
},
|
|
39
53
|
|
|
40
|
-
|
|
54
|
+
cleanTokens() {
|
|
55
|
+
return getTasks().cleanTokens();
|
|
56
|
+
},
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
58
|
+
cleanExpiredComped() {
|
|
59
|
+
return getTasks().cleanExpiredComped();
|
|
60
|
+
},
|
|
44
61
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
62
|
+
async scheduleExpiredCompCleanupJob(jobsService) {
|
|
63
|
+
if (alreadyScheduledOrTest('expiredComped')) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Keep the legacy off-peak window: a random time between 00:00 and 05:59
|
|
68
|
+
const cron = randomDailyCron(6);
|
|
69
|
+
logging.info(`[Background Job] clean-expired-comped scheduled at ${cron}`);
|
|
70
|
+
await jobsService.scheduleRecurring(new CleanExpiredCompedJob(), { cron });
|
|
71
|
+
|
|
72
|
+
hasScheduled.expiredComped = true;
|
|
48
73
|
},
|
|
49
74
|
|
|
50
|
-
async scheduleTokenCleanupJob() {
|
|
75
|
+
async scheduleTokenCleanupJob(jobsService) {
|
|
51
76
|
if (alreadyScheduledOrTest('tokens')) {
|
|
52
77
|
return;
|
|
53
78
|
}
|
|
54
79
|
|
|
55
|
-
const classBasedJobs = require('../../jobs-service').getInstance();
|
|
56
80
|
const cron = randomDailyCron();
|
|
57
81
|
logging.info(`[Background Job] clean-tokens scheduled at ${cron}`);
|
|
58
|
-
await
|
|
82
|
+
await jobsService.scheduleRecurring(new CleanTokensJob(), { cron });
|
|
59
83
|
|
|
60
84
|
hasScheduled.tokens = true;
|
|
61
85
|
},
|
|
@@ -146,6 +146,17 @@ module.exports = class MemberController {
|
|
|
146
146
|
|
|
147
147
|
if (tierId && cadence) {
|
|
148
148
|
const tier = await this._tiersService.api.read(tierId);
|
|
149
|
+
|
|
150
|
+
if (!tier) {
|
|
151
|
+
res.writeHead(404);
|
|
152
|
+
return res.end('Not Found.');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (tier.status !== 'active') {
|
|
156
|
+
res.writeHead(403);
|
|
157
|
+
return res.end('Tier is archived.');
|
|
158
|
+
}
|
|
159
|
+
|
|
149
160
|
const stripePrice = await this._paymentsService.getPriceForTierCadence(tier, cadence);
|
|
150
161
|
|
|
151
162
|
await this._memberRepository.updateSubscription({
|
|
@@ -140,7 +140,6 @@ module.exports = class RouterController {
|
|
|
140
140
|
* @param {any} deps.offersAPI
|
|
141
141
|
* @param {any} deps.paymentsService
|
|
142
142
|
* @param {any} deps.memberRepository
|
|
143
|
-
* @param {any} deps.StripePrice
|
|
144
143
|
* @param {() => boolean} deps.allowSelfSignup
|
|
145
144
|
* @param {any} deps.magicLinkService
|
|
146
145
|
* @param {import('../../../stripe/stripe-api')} deps.stripeAPIService
|
|
@@ -160,7 +159,6 @@ module.exports = class RouterController {
|
|
|
160
159
|
paymentsService,
|
|
161
160
|
tiersService,
|
|
162
161
|
memberRepository,
|
|
163
|
-
StripePrice,
|
|
164
162
|
allowSelfSignup,
|
|
165
163
|
magicLinkService,
|
|
166
164
|
stripeAPIService,
|
|
@@ -180,7 +178,6 @@ module.exports = class RouterController {
|
|
|
180
178
|
this._paymentsService = paymentsService;
|
|
181
179
|
this._tiersService = tiersService;
|
|
182
180
|
this._memberRepository = memberRepository;
|
|
183
|
-
this._StripePrice = StripePrice;
|
|
184
181
|
this._allowSelfSignup = allowSelfSignup;
|
|
185
182
|
this._magicLinkService = magicLinkService;
|
|
186
183
|
this._stripeAPIService = stripeAPIService;
|
|
@@ -602,11 +599,11 @@ module.exports = class RouterController {
|
|
|
602
599
|
if (member) {
|
|
603
600
|
options.successUrl = this._generateSuccessUrl(options.successUrl, tier.welcomePageURL);
|
|
604
601
|
|
|
605
|
-
|
|
602
|
+
// Existing paid members must manage their subscription instead of creating another.
|
|
603
|
+
// Other members must prove ownership of the provided email before checking out.
|
|
604
|
+
const restrictCheckout = member.get('status') === 'paid' || !options.isAuthenticated;
|
|
606
605
|
|
|
607
606
|
if (restrictCheckout) {
|
|
608
|
-
// This member is already subscribed to a paid tier
|
|
609
|
-
// We don't want to create a duplicate subscription
|
|
610
607
|
if (!options.isAuthenticated && options.email) {
|
|
611
608
|
try {
|
|
612
609
|
await this._sendEmailWithMagicLink({ email: options.email, requestedType: 'signin' });
|
|
@@ -41,7 +41,6 @@ module.exports = function MembersAPI({
|
|
|
41
41
|
MemberProductEvent,
|
|
42
42
|
MemberEmailChangeEvent,
|
|
43
43
|
MemberCreatedEvent,
|
|
44
|
-
SubscriptionCreatedEvent,
|
|
45
44
|
MemberLinkClickEvent,
|
|
46
45
|
EmailSpamComplaintEvent,
|
|
47
46
|
Offer,
|
|
@@ -72,6 +71,7 @@ module.exports = function MembersAPI({
|
|
|
72
71
|
emailAddressService,
|
|
73
72
|
giftService,
|
|
74
73
|
customFieldValues,
|
|
74
|
+
customFieldDefinitions,
|
|
75
75
|
}) {
|
|
76
76
|
const tokenService = new TokenService({
|
|
77
77
|
privateKey,
|
|
@@ -119,7 +119,6 @@ module.exports = function MembersAPI({
|
|
|
119
119
|
MemberStatusEvent,
|
|
120
120
|
MemberLoginEvent,
|
|
121
121
|
MemberCreatedEvent,
|
|
122
|
-
SubscriptionCreatedEvent,
|
|
123
122
|
MemberLinkClickEvent,
|
|
124
123
|
MemberFeedback,
|
|
125
124
|
EmailSpamComplaintEvent,
|
|
@@ -147,7 +146,6 @@ module.exports = function MembersAPI({
|
|
|
147
146
|
});
|
|
148
147
|
},
|
|
149
148
|
},
|
|
150
|
-
labsService,
|
|
151
149
|
stripeService: stripeAPIService,
|
|
152
150
|
memberAttributionService,
|
|
153
151
|
emailSuppressionList,
|
|
@@ -156,6 +154,7 @@ module.exports = function MembersAPI({
|
|
|
156
154
|
commentsService,
|
|
157
155
|
giftService,
|
|
158
156
|
customFieldValues,
|
|
157
|
+
customFieldDefinitions,
|
|
159
158
|
});
|
|
160
159
|
|
|
161
160
|
const geolocationService = new GeolocationService();
|
|
@@ -202,7 +201,6 @@ module.exports = function MembersAPI({
|
|
|
202
201
|
paymentsService,
|
|
203
202
|
tiersService,
|
|
204
203
|
memberRepository,
|
|
205
|
-
StripePrice,
|
|
206
204
|
allowSelfSignup,
|
|
207
205
|
magicLinkService,
|
|
208
206
|
stripeAPIService,
|
|
@@ -358,11 +356,11 @@ module.exports = function MembersAPI({
|
|
|
358
356
|
}
|
|
359
357
|
|
|
360
358
|
async function getMemberIdentityData(email) {
|
|
361
|
-
return memberBREADService.read({ email });
|
|
359
|
+
return memberBREADService.read({ email }, { withCustomFields: false });
|
|
362
360
|
}
|
|
363
361
|
|
|
364
362
|
async function getMemberIdentityDataFromTransientId(transientId) {
|
|
365
|
-
return memberBREADService.read({ transient_id: transientId });
|
|
363
|
+
return memberBREADService.read({ transient_id: transientId }, { withCustomFields: false });
|
|
366
364
|
}
|
|
367
365
|
|
|
368
366
|
async function cycleTransientId(memberId) {
|
|
@@ -34,13 +34,11 @@ module.exports = class EventRepository {
|
|
|
34
34
|
MemberStatusEvent,
|
|
35
35
|
MemberLoginEvent,
|
|
36
36
|
MemberCreatedEvent,
|
|
37
|
-
SubscriptionCreatedEvent,
|
|
38
37
|
MemberPaidSubscriptionEvent,
|
|
39
38
|
MemberLinkClickEvent,
|
|
40
39
|
MemberFeedback,
|
|
41
40
|
EmailSpamComplaintEvent,
|
|
42
41
|
Comment,
|
|
43
|
-
labsService,
|
|
44
42
|
memberAttributionService,
|
|
45
43
|
urlService,
|
|
46
44
|
MemberEmailChangeEvent,
|
|
@@ -55,10 +53,8 @@ module.exports = class EventRepository {
|
|
|
55
53
|
this._MemberLoginEvent = MemberLoginEvent;
|
|
56
54
|
this._EmailRecipient = EmailRecipient;
|
|
57
55
|
this._Comment = Comment;
|
|
58
|
-
this._labsService = labsService;
|
|
59
56
|
this._urlService = urlService;
|
|
60
57
|
this._MemberCreatedEvent = MemberCreatedEvent;
|
|
61
|
-
this._SubscriptionCreatedEvent = SubscriptionCreatedEvent;
|
|
62
58
|
this._MemberLinkClickEvent = MemberLinkClickEvent;
|
|
63
59
|
this._MemberFeedback = MemberFeedback;
|
|
64
60
|
this._EmailSpamComplaintEvent = EmailSpamComplaintEvent;
|
|
@@ -16,11 +16,6 @@ const messages = {
|
|
|
16
16
|
// Stored in the action's `context.action_name`; Admin maps it to a display label.
|
|
17
17
|
const CUSTOM_FIELDS_EDITED_ACTION = 'custom_fields_edited';
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
* @typedef {object} ILabsService
|
|
21
|
-
* @prop {(key: string) => boolean} isSet
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
19
|
/**
|
|
25
20
|
* @typedef {object} IEmailService
|
|
26
21
|
* @prop {(data: {email: string, requestedType: string}) => Promise<any>} sendEmailWithMagicLink
|
|
@@ -45,7 +40,6 @@ module.exports = class MemberBREADService {
|
|
|
45
40
|
* @param {object} deps
|
|
46
41
|
* @param {import('../repositories/member-repository')} deps.memberRepository
|
|
47
42
|
* @param {import('../../../offers/application/offers-api')} deps.offersAPI
|
|
48
|
-
* @param {ILabsService} deps.labsService
|
|
49
43
|
* @param {IEmailService} deps.emailService
|
|
50
44
|
* @param {IStripeService} deps.stripeService
|
|
51
45
|
* @param {import('../../../member-attribution/member-attribution-service')} deps.memberAttributionService
|
|
@@ -54,10 +48,10 @@ module.exports = class MemberBREADService {
|
|
|
54
48
|
* @param {import('./next-payment-calculator')} deps.nextPaymentCalculator
|
|
55
49
|
* @param {IGiftsModule} deps.giftService
|
|
56
50
|
* @param {import('../../../members-custom-fields/values-service').CustomFieldValuesService} deps.customFieldValues Required: boot builds it before the members service
|
|
51
|
+
* @param {import('../../../members-custom-fields/definitions-service').CustomFieldDefinitionsService} deps.customFieldDefinitions Required: boot builds it before the members service
|
|
57
52
|
*/
|
|
58
53
|
constructor({
|
|
59
54
|
memberRepository,
|
|
60
|
-
labsService,
|
|
61
55
|
emailService,
|
|
62
56
|
stripeService,
|
|
63
57
|
offersAPI,
|
|
@@ -68,13 +62,12 @@ module.exports = class MemberBREADService {
|
|
|
68
62
|
commentsService,
|
|
69
63
|
giftService,
|
|
70
64
|
customFieldValues,
|
|
65
|
+
customFieldDefinitions,
|
|
71
66
|
}) {
|
|
72
67
|
this.offersAPI = offersAPI;
|
|
73
68
|
/** @private */
|
|
74
69
|
this.memberRepository = memberRepository;
|
|
75
70
|
/** @private */
|
|
76
|
-
this.labsService = labsService;
|
|
77
|
-
/** @private */
|
|
78
71
|
this.emailService = emailService;
|
|
79
72
|
/** @private */
|
|
80
73
|
this.stripeService = stripeService;
|
|
@@ -92,31 +85,25 @@ module.exports = class MemberBREADService {
|
|
|
92
85
|
this.giftService = giftService;
|
|
93
86
|
/** @private */
|
|
94
87
|
this.customFieldValues = customFieldValues;
|
|
88
|
+
/** @private */
|
|
89
|
+
this.customFieldDefinitions = customFieldDefinitions;
|
|
95
90
|
}
|
|
96
91
|
|
|
97
92
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* `custom_fields` key entirely, keeping a pre-feature member payload identical.
|
|
102
|
-
*
|
|
103
|
-
* A read gets values on the flag alone, with no opt-in include: a member's
|
|
104
|
-
* custom fields are their own data, like labels and tiers, which a read
|
|
105
|
-
* already returns unasked. `include` is for things that are expensive or
|
|
106
|
-
* aggregate (email_recipients, counts), and one flat lookup on a read that
|
|
107
|
-
* already issues a dozen queries is neither. The flag, not an include, is what
|
|
108
|
-
* protects consumers that predate the feature — an include would outlive it
|
|
109
|
-
* and become permanent API surface.
|
|
93
|
+
* Metafields are extra fields a publisher can define on member records, such as a shoe
|
|
94
|
+
* size or a delivery address. Their values live in their own table, so they are fetched
|
|
95
|
+
* here rather than loaded alongside the member.
|
|
110
96
|
*
|
|
111
|
-
*
|
|
112
|
-
* `
|
|
113
|
-
*
|
|
114
|
-
*
|
|
97
|
+
* Returns null when the site has defined no fields, which tells the caller to leave the
|
|
98
|
+
* `metafields` key off the member payload rather than send an empty object: a key added to
|
|
99
|
+
* an API response cannot be withdrawn without breaking whoever started reading it, and
|
|
100
|
+
* most sites have never defined a field, so those sites keep the payload they had before
|
|
101
|
+
* this feature existed.
|
|
115
102
|
* @param {string[]} memberIds
|
|
116
103
|
* @returns {Promise<Map<string, Record<string, unknown>> | null>}
|
|
117
104
|
*/
|
|
118
105
|
async fetchCustomFieldValues(memberIds) {
|
|
119
|
-
if (!this.
|
|
106
|
+
if (!(await this.customFieldDefinitions.hasAnyActive())) {
|
|
120
107
|
return null;
|
|
121
108
|
}
|
|
122
109
|
|
|
@@ -394,7 +381,16 @@ module.exports = class MemberBREADService {
|
|
|
394
381
|
}
|
|
395
382
|
}
|
|
396
383
|
|
|
397
|
-
|
|
384
|
+
/**
|
|
385
|
+
* @param {object} data
|
|
386
|
+
* @param {object} [options]
|
|
387
|
+
* @param {boolean} [options.withCustomFields] Pass false to leave custom field values
|
|
388
|
+
* off the result. Ghost calls this method to identify a signed-in reader on every page
|
|
389
|
+
* view of a themed site, and that caller renders the member through a fixed list of
|
|
390
|
+
* fields that has never included custom ones. Fetching them there costs two database
|
|
391
|
+
* queries per page view whose results are then thrown away.
|
|
392
|
+
*/
|
|
393
|
+
async read(data, { withCustomFields = true, ...options } = {}) {
|
|
398
394
|
const defaultWithRelated = [
|
|
399
395
|
'labels',
|
|
400
396
|
'stripeSubscriptions',
|
|
@@ -455,43 +451,25 @@ module.exports = class MemberBREADService {
|
|
|
455
451
|
const unsubscribeUrl = this.settingsHelpers.createUnsubscribeUrl(member.uuid);
|
|
456
452
|
member.unsubscribe_url = unsubscribeUrl;
|
|
457
453
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
454
|
+
if (withCustomFields) {
|
|
455
|
+
const customFields = await this.fetchCustomFieldValues([member.id]);
|
|
456
|
+
if (customFields) {
|
|
457
|
+
member.metafields = customFields.get(member.id) ?? {};
|
|
458
|
+
}
|
|
461
459
|
}
|
|
462
460
|
|
|
463
461
|
return member;
|
|
464
462
|
}
|
|
465
463
|
|
|
466
|
-
/**
|
|
467
|
-
* @private
|
|
468
|
-
* The write-side flag gate, paired with `fetchCustomFieldValues` on the read
|
|
469
|
-
* side. The schema declares `custom_fields` for every site, so the key arrives
|
|
470
|
-
* whether or not the feature is on and this is what decides it goes no further.
|
|
471
|
-
* @param {object} data
|
|
472
|
-
*/
|
|
473
|
-
dropCustomFieldsWhenDisabled(data) {
|
|
474
|
-
if (!this.labsService.isSet('membersCustomFields')) {
|
|
475
|
-
delete data.custom_fields;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
464
|
async add(data, options) {
|
|
480
|
-
this.
|
|
481
|
-
|
|
482
|
-
// Values cannot be set on create, only on a subsequent edit. `namesValues`
|
|
483
|
-
// both judges the body and rejects a malformed one, so a body refused here is
|
|
484
|
-
// refused on edit for the same reason.
|
|
485
|
-
if (this.customFieldValues.namesValues(data.custom_fields)) {
|
|
465
|
+
if (this.customFieldValues.namesValues(this.customFieldValues.unwrapWire(data.metafields))) {
|
|
486
466
|
throw new errors.ValidationError({
|
|
487
467
|
message: tpl(messages.customFieldsOnAdd),
|
|
488
|
-
property: '
|
|
468
|
+
property: 'metafields',
|
|
489
469
|
});
|
|
490
470
|
}
|
|
491
471
|
|
|
492
|
-
|
|
493
|
-
// an absent key or one naming no values gets this far.
|
|
494
|
-
delete data.custom_fields;
|
|
472
|
+
delete data.metafields;
|
|
495
473
|
|
|
496
474
|
if (!this.stripeService.configured && (data.comped || data.stripe_customer_id)) {
|
|
497
475
|
const property = data.comped ? 'comped' : 'stripe_customer_id';
|
|
@@ -587,15 +565,9 @@ module.exports = class MemberBREADService {
|
|
|
587
565
|
async edit(data, options) {
|
|
588
566
|
delete data.last_seen_at;
|
|
589
567
|
|
|
590
|
-
this.
|
|
591
|
-
|
|
592
|
-
// Values live in their own table, so they come off the member data before
|
|
593
|
-
// the repository sees it — `custom_fields` is not a member column. The gate
|
|
594
|
-
// above has already dropped it when the feature is off, so by this point its
|
|
595
|
-
// presence is the signal to write.
|
|
596
|
-
const customFields = data.custom_fields;
|
|
568
|
+
const customFields = this.customFieldValues.unwrapWire(data.metafields);
|
|
597
569
|
const writeCustomFields = customFields !== undefined;
|
|
598
|
-
delete data.
|
|
570
|
+
delete data.metafields;
|
|
599
571
|
|
|
600
572
|
// Plan (which validates) before the member is touched, so a bad value 422s
|
|
601
573
|
// here rather than after the member edit has been applied — and keep the
|
|
@@ -833,7 +805,7 @@ module.exports = class MemberBREADService {
|
|
|
833
805
|
delete member.products;
|
|
834
806
|
}
|
|
835
807
|
if (customFieldsByMember) {
|
|
836
|
-
member.
|
|
808
|
+
member.metafields = customFieldsByMember.get(model.id) ?? {};
|
|
837
809
|
}
|
|
838
810
|
member.email_suppression = {
|
|
839
811
|
suppressed: bulkSuppressionData[index].suppressed || !!model.get('email_disabled'),
|
|
@@ -161,7 +161,7 @@ class PaymentsService {
|
|
|
161
161
|
*/
|
|
162
162
|
async getCheckoutConfigForTier(tier) {
|
|
163
163
|
const checkoutConfig = this.tiersService?.checkout;
|
|
164
|
-
if (!this.labsService?.isSet('
|
|
164
|
+
if (!this.labsService?.isSet('stripeCheckoutCollection') || !checkoutConfig) {
|
|
165
165
|
return undefined;
|
|
166
166
|
}
|
|
167
167
|
try {
|
|
@@ -7,7 +7,6 @@ const MembersConfigProvider = require('./members-config-provider');
|
|
|
7
7
|
const { makeImporter, makeExporter } = require('./import-export');
|
|
8
8
|
const { resolveInlineThreshold } = require('./import-export/config');
|
|
9
9
|
const MembersStats = require('./stats/members-stats');
|
|
10
|
-
const memberJobs = require('./jobs');
|
|
11
10
|
const logging = require('@tryghost/logging');
|
|
12
11
|
const urlUtils = require('../../../shared/url-utils').default;
|
|
13
12
|
const settingsCache = require('../../../shared/settings-cache');
|
|
@@ -29,7 +28,7 @@ const messages = {
|
|
|
29
28
|
sslRequiredForStripe:
|
|
30
29
|
'Cannot run Ghost without SSL when Stripe is connected. Please update your url config to use "https://".',
|
|
31
30
|
remoteWebhooksInDevelopment:
|
|
32
|
-
'Cannot use remote webhooks in development. See https://ghost.org/
|
|
31
|
+
'Cannot use remote webhooks in development. See https://docs.ghost.org/webhooks/#stripe-webhooks for developing with Stripe.',
|
|
33
32
|
};
|
|
34
33
|
|
|
35
34
|
const ghostMailer = new GhostMailer();
|
|
@@ -216,9 +215,6 @@ module.exports = {
|
|
|
216
215
|
);
|
|
217
216
|
}
|
|
218
217
|
}
|
|
219
|
-
|
|
220
|
-
// Schedule daily cron job to clean expired comp subs
|
|
221
|
-
memberJobs.scheduleExpiredCompCleanupJob();
|
|
222
218
|
},
|
|
223
219
|
contentGating: require('./content-gating'),
|
|
224
220
|
|
|
@@ -8,6 +8,7 @@ const bson_objectid_1 = __importDefault(require("bson-objectid"));
|
|
|
8
8
|
const logging_1 = __importDefault(require("@tryghost/logging"));
|
|
9
9
|
const schema_1 = require("./schema");
|
|
10
10
|
const FIELDS_TABLE = 'members_custom_fields';
|
|
11
|
+
const { CUSTOM_NAMESPACE } = require('@tryghost/custom-field-types/identity');
|
|
11
12
|
const BINDINGS_TABLE = 'members_custom_field_bindings';
|
|
12
13
|
/**
|
|
13
14
|
* Where a source sends what it collected: a `port` is the name that source uses for a
|
|
@@ -60,7 +61,7 @@ class CustomFieldBindingsService {
|
|
|
60
61
|
async writeOne(memberId, into, value) {
|
|
61
62
|
let planned;
|
|
62
63
|
try {
|
|
63
|
-
planned = await this.values.planWrite({ [into.key]: value });
|
|
64
|
+
planned = await this.values.planWrite({ [`${CUSTOM_NAMESPACE}.${into.key}`]: value });
|
|
64
65
|
}
|
|
65
66
|
catch (err) {
|
|
66
67
|
logging_1.default.warn({
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.customFieldCodec = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const identity_1 = require("@tryghost/custom-field-types/identity");
|
|
5
6
|
const case_keys_1 = require("../../lib/case-keys");
|
|
6
7
|
const schema_1 = require("./schema");
|
|
7
8
|
const models_1 = require("./models");
|
|
8
|
-
// Maps a members_custom_fields row to/from the domain CustomField (snake_case to
|
|
9
|
-
// camelCase; DbDate decoding happens in DbCustomField).
|
|
10
9
|
exports.customFieldCodec = zod_1.z.codec(schema_1.DbCustomField, models_1.CustomField, {
|
|
11
10
|
// DbCustomField validates `type` as the field-type enum, so the decoded row
|
|
12
11
|
// already carries a FieldType and camelKeys preserves it — no cast needed.
|
|
13
|
-
decode: (row) => (0, case_keys_1.camelKeys)(row),
|
|
14
|
-
encode: (field) => (0, case_keys_1.snakeKeys)(field),
|
|
12
|
+
decode: (row) => ({ ...(0, case_keys_1.camelKeys)(row), namespace: identity_1.CUSTOM_NAMESPACE }),
|
|
13
|
+
encode: ({ namespace: _namespace, ...field }) => (0, case_keys_1.snakeKeys)(field),
|
|
15
14
|
});
|