ghost 6.60.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 +62 -21
- 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/{PolarAngleAxis-C4qtHy1B.js → PolarAngleAxis-pkMyqz8g.js} +1 -1
- package/core/built/admin/assets/{RadialBarChart-Bh09Stsj.js → RadialBarChart-JAKoS4KT.js} +1 -1
- package/core/built/admin/assets/{about-BgpmhCuM.js → about-Dyae_UT6.js} +1 -1
- package/core/built/admin/assets/account-migration-CESa0mnX.js +1 -0
- package/core/built/admin/assets/{action-list-lGzZLHc8.js → action-list-C4v0-du8.js} +1 -1
- package/core/built/admin/assets/activitypub/{account-migration-DMHuPnJn.js → account-migration-By69CgCp.js} +16 -16
- package/core/built/admin/assets/activitypub/activitypub.js +9 -10
- package/core/built/admin/assets/activitypub/{avatar-DhTo5D1B.js → avatar-DLPL3Abs.js} +59 -68
- package/core/built/admin/assets/activitypub/{avatar-flipboard-DnVgbEfa.js → avatar-flipboard-C9iDY-QV.js} +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-BT4zAlW7.js → bluesky-sharing-BJcPMrDd.js} +37 -37
- package/core/built/admin/assets/activitypub/{content-formatters-BeDZ-DIa.js → content-formatters-3rTHg3mp.js} +18 -18
- package/core/built/admin/assets/activitypub/{copy-8sqxUuNd.js → copy-DIAOQoCZ.js} +2 -2
- package/core/built/admin/assets/activitypub/{domain-xQDDu1CS.js → domain-DUR4xSkV.js} +121 -121
- package/core/built/admin/assets/activitypub/{edit-profile-BXdF_r2G.js → edit-profile-BqtfzxCp.js} +40 -40
- package/core/built/admin/assets/activitypub/{explore-CMt7gKlL.js → explore-BxuJd-J4.js} +27 -27
- package/core/built/admin/assets/activitypub/{feed-Bwqdddp_.js → feed-BM1TcksA.js} +51 -51
- package/core/built/admin/assets/activitypub/{field-4co_8FVg.js → field-Dn7HHx2-.js} +3 -3
- package/core/built/admin/assets/activitypub/{hash-DwakMs4X.js → hash-Bm3WxYN4.js} +2 -2
- package/core/built/admin/assets/activitypub/inbox-CCjkuow2.js +1284 -0
- package/core/built/admin/assets/activitypub/{inbox-ckD4wo_r.js → inbox-d8oJRTf4.js} +2 -2
- 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-KCCO7L2J.js → moderation-CnmxEB8w.js} +91 -91
- package/core/built/admin/assets/activitypub/{note-BX_Bz5A0.js → note-ZKc_Bnba.js} +24 -24
- package/core/built/admin/assets/activitypub/{notifications-BQOYGvRv.js → notifications-CB2tJZau.js} +51 -51
- 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-6h43G9_q.js → preferences-0-JZnUkI.js} +1519 -1519
- package/core/built/admin/assets/activitypub/{profile-BMN9VVZ2.js → profile-C35cFIhM.js} +256 -256
- package/core/built/admin/assets/activitypub/{reply-ZNo04xsO.js → reply-DYK5vVqb.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-3B9mUQ7i.js → routes-BD4vscyc.js} +796 -790
- package/core/built/admin/assets/activitypub/{separator-D9taVCCa.js → separator-BbQqTm-p.js} +3 -3
- 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-BsGGnBuT.js → step-1-BMSx7c_X.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-2-teosIS0k.js → step-2-DtPQzlTH.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-3-BjD5TokC.js → step-3-CLlOZTyt.js} +11 -11
- package/core/built/admin/assets/activitypub/{tabs-Cvwl1wXU.js → tabs-Dxk-b9M-.js} +306 -306
- package/core/built/admin/assets/activitypub/{topic-filter-C3LZJc2X.js → topic-filter-5yZH6tId.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-Dp9f0gov.js → use-activity-pub-queries-CV50qe03.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-C4RI0sa9.js → use-navigate-with-base-path-Bmk5h4lW.js} +220 -220
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-C2oNDMUH.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/activitypub/{x-Dxm6pV9X.js → x-DbQZOLiI.js} +2 -2
- 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-BTHiy1ZO.js → announcement-bar-modal-Ci4zz8jO.js} +1 -1
- package/core/built/admin/assets/{api-keys-Boy5pLbD.js → api-keys-Ck-Yteiv.js} +1 -1
- package/core/built/admin/assets/audience-CtbA54Sn.js +1 -0
- 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/{box-By_EgGtm.js → box-CdfQAP_F.js} +1 -1
- package/core/built/admin/assets/{brand-icon-09YqFZjV.js → brand-icon-CrIGOA3Z.js} +1 -1
- package/core/built/admin/assets/{breadcrumb-CcFr_ltt.js → breadcrumb-zUrZrBtW.js} +1 -1
- package/core/built/admin/assets/{button-BshWPHvn.js → button-eNMKQWXr.js} +1 -1
- package/core/built/admin/assets/{card-CiiE7QfM.js → card--VNbfgo3.js} +1 -1
- package/core/built/admin/assets/{chart-BnXyfH11.js → chart-BrhA41Zi.js} +1 -1
- package/core/built/admin/assets/chart-helpers-CfBKt0vT.js +1 -0
- package/core/built/admin/assets/{checkbox-Dwwr_3Py.js → checkbox-CgOn_tKW.js} +1 -1
- package/core/built/admin/assets/{chunk.524.91ecb33e6afc3bd8949b.js → chunk.524.a697dee88db67fdf6021.js} +4 -4
- package/core/built/admin/assets/{chunk.582.512549909741883f960c.js → chunk.582.5ed5d124cfca9c259b9c.js} +6 -6
- package/core/built/admin/assets/{chunk.16.f76a6314082d813d67e0.js → chunk.598.7e056fabb47ce7dbd73f.js} +14 -14
- package/core/built/admin/assets/{code-editor-view-BwIdPy_k.js → code-editor-view-BYNoAoNV.js} +1 -1
- package/core/built/admin/assets/{code-editor-view-CtkF82Fv.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/{container-LiZf3XdY.js → container-BuQG1wuP.js} +1 -1
- package/core/built/admin/assets/{content-api-modal-BtpNI92-.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-CglgRZyG.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/{data-list-CupF7bjM.js → data-list-CA2jYGPq.js} +1 -1
- package/core/built/admin/assets/{date-range-select-JPwM0yUj.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/{detail-page-D8lx2SdP.js → detail-page-Dnv-CdR1.js} +1 -1
- package/core/built/admin/assets/dirty-confirm-dialog-BZ1iytEd.js +1 -0
- package/core/built/admin/assets/{disabled-sources-indicator-BTJ2ClQu.js → disabled-sources-indicator-DMRrxsiJ.js} +1 -1
- package/core/built/admin/assets/{dist-DzcfoDJ3.js → dist-8YJUlf3B.js} +1 -1
- package/core/built/admin/assets/{dist-Cb5RSHSg.js → dist-B3keLvjj.js} +1 -1
- package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
- package/core/built/admin/assets/{dist-BT_Z-eCn.js → dist-Dgt2cr6a.js} +1 -1
- 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-BFTPf04i.js → embed-signup-form-modal-Ds6mPEi5.js} +1 -1
- package/core/built/admin/assets/{empty-indicator-WB1WgT9h.js → empty-indicator-D9QdpuNX.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-LmNk7wZh.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-403cb39badad3df411fc0ba27d220047.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/{grid-CUciBfjf.js → grid-Dj29PY05.js} +1 -1
- 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/{heading-CRZZ2FUe.js → heading-Dh5SFVjL.js} +1 -1
- package/core/built/admin/assets/history-modal-CFd1Hvx6.js +1 -0
- package/core/built/admin/assets/html-field-CJBCLTvv.js +1 -0
- package/core/built/admin/assets/{images-C0XvUYMb.js → images-scfkWZiK.js} +1 -1
- package/core/built/admin/assets/{inbox-DZXDUt4s.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/{inline-Cw-gigDW.js → inline-BWSs_VzR.js} +1 -1
- package/core/built/admin/assets/{input-group-BPAxETpQ.js → input-group-CMhe2DvY.js} +1 -1
- package/core/built/admin/assets/{input-surface-BdOe4KzO.js → input-surface-BsrIZeSF.js} +1 -1
- package/core/built/admin/assets/{integration-header-B4DyXV06.js → integration-header-Bm6IDb1A.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-60O_8aiO.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-DBRMfGOW.js +1 -0
- package/core/built/admin/assets/{kpi-card-fUHZlzBX.js → kpi-card-DFafD1qq.js} +1 -1
- package/core/built/admin/assets/kpi-helpers-Cv8i8hns.js +1 -0
- package/core/built/admin/assets/kpi-tabs-BJItvLYm.js +1 -0
- package/core/built/admin/assets/{label-VIG969IC.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/{link-helpers-Dtq9fxQg.js → link-helpers-MVDdnFCY.js} +1 -1
- package/core/built/admin/assets/{list-page-CdsnQR9N.js → list-page-BucXJ0hi.js} +1 -1
- 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/{modal-page-BMTzFHVO.js → modal-page-xCivTMvI.js} +1 -1
- package/core/built/admin/assets/moderation-AgCIEso4.js +1 -0
- package/core/built/admin/assets/{multi-select-combobox-CGohnsxJ.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-D5ql1rud.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-Cu_ROWPn.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-Cfds8pCg.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-TDTrJ89x.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-Cu3jNeFh.js → post-analytics-provider-Bo1gmYaP.js} +1 -1
- package/core/built/admin/assets/{post-share-modal-P1_M6o-H.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-chrome-BOVO6_PE.js → preview-chrome-BljUBlOk.js} +1 -1
- package/core/built/admin/assets/{preview-modal-MlTjP8UU.js → preview-modal-BfeFqi5y.js} +1 -1
- package/core/built/admin/assets/profile-B8mx2yAu.js +1 -0
- package/core/built/admin/assets/{radio-group-CjtmsCPl.js → radio-group-DczlLKOn.js} +1 -1
- package/core/built/admin/assets/{router-provider-CJC58zTy.js → router-provider-B0gZyiGJ.js} +1 -1
- package/core/built/admin/assets/{schemas-CRsC53ls.js → schemas-DppqmpeJ.js} +2 -2
- 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-sLDNedBW.js → settings-breadcrumbs-DLzbRRSt.js} +1 -1
- package/core/built/admin/assets/{shade-app-F7WxOyfk-nufqw1hd.js → shade-app-CcS3f8MZ-vwURazk8.js} +2 -2
- package/core/built/admin/assets/share-modal-D2-Bz1_I.js +1 -0
- package/core/built/admin/assets/{skeleton-D7hwjdry.js → skeleton-Ce9GgUpf.js} +1 -1
- package/core/built/admin/assets/slack-modal-DYDTUria.js +1 -0
- package/core/built/admin/assets/sort-button-VVeQjjbu.js +1 -0
- package/core/built/admin/assets/{source-icon-BPsD5ees.js → source-icon-Ck5_5Kgq.js} +1 -1
- package/core/built/admin/assets/{stack-CIfOAAVf.js → stack-B2eszIiq.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-CMta6YFO.js → step-1-CsaBjeN4.js} +1 -1
- package/core/built/admin/assets/{step-2-BG04nh5q.js → step-2-D2vnxOOM.js} +1 -1
- package/core/built/admin/assets/{step-3-ZnMaVIPj.js → step-3-wBoLdGEb.js} +2 -2
- package/core/built/admin/assets/{stripe-button-DDoUKN5a.js → stripe-button-CDgLz0S0.js} +1 -1
- package/core/built/admin/assets/stripe-connect-modal-CSjMJetP.js +1 -0
- package/core/built/admin/assets/{switch-C9djUIMO.js → switch-CI4gLWqb.js} +1 -1
- package/core/built/admin/assets/{table-CrqQtkR2.js → table-Do6iQ83Q.js} +1 -1
- package/core/built/admin/assets/{tabs-CGisSbWq.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/{text-DU9Hv33_.js → text-BQDSDsKs.js} +1 -1
- package/core/built/admin/assets/{textarea-d9qEkMOP.js → textarea-DJ1Q5V39.js} +1 -1
- package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +1 -0
- package/core/built/admin/assets/{toggle-group-CtKZURJd.js → toggle-group-ByUJsxwD.js} +1 -1
- package/core/built/admin/assets/{topic-filter-D8JT8Tq1.js → topic-filter-BgC3g5_v.js} +1 -1
- package/core/built/admin/assets/{transistor-modal-6PUf0idx.js → transistor-modal-Drr0SNfo.js} +1 -1
- package/core/built/admin/assets/trend-badge-6ye93YAW.js +1 -0
- package/core/built/admin/assets/{unsplash-modal-BPuDBPja.js → unsplash-modal-p6AoQoWp.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data--opuzwcz.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-Cw3WQHy8.js +2 -0
- 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-TDSNiHPB.js → use-limiter-D2WRRx0H.js} +1 -1
- package/core/built/admin/assets/{use-navigate-with-base-path-CK989MlC.js → use-navigate-with-base-path-BHPA228f.js} +1 -1
- package/core/built/admin/assets/{use-pintura-config-CnCGrDFk.js → use-pintura-config-h-J0Lvta.js} +1 -1
- package/core/built/admin/assets/{use-pintura-editor-ntphvtUd.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-BwfQS2mq.js → use-router-history-entry-uldn7zJO.js} +1 -1
- package/core/built/admin/assets/{use-setting-group-DQxV42-O.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-B2TdNX67.js → use-simple-pagination-DzJWobPR.js} +1 -1
- package/core/built/admin/assets/{use-staff-users-QrR9voeC.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-DpYJcj1d.js → use-unsaved-changes-guard-CBzs-KPi.js} +1 -1
- package/core/built/admin/assets/{use-url-input-WnIqckzS.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-D3MfPNOh.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-BO6PS_Vd.js → zapier-modal-BBFfI6Ml.js} +1 -1
- package/core/built/admin/index.html +24 -30
- 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/rendering/renderer.js +15 -0
- package/core/frontend/services/sitemap/user-map-generator.js +9 -2
- package/core/server/adapters/storage/LocalStorageBase.js +8 -5
- package/core/server/api/endpoints/db.js +19 -5
- package/core/server/api/endpoints/index.js +6 -2
- package/core/server/api/endpoints/mail.js +1 -1
- package/core/server/api/endpoints/member-metafields.js +89 -0
- package/core/server/api/endpoints/members.js +4 -4
- package/core/server/api/endpoints/posts.js +4 -3
- package/core/server/api/endpoints/tiers-checkout-config.js +59 -0
- package/core/server/api/endpoints/utils/serializers/input/members.js +4 -7
- package/core/server/api/endpoints/utils/serializers/output/config.js +1 -0
- package/core/server/api/endpoints/utils/serializers/output/index.js +6 -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/serializers/output/tiers-checkout-config.js +12 -0
- package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
- package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
- package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
- package/core/server/data/exporter/table-lists.js +3 -0
- package/core/server/data/importer/content-files.js +57 -0
- package/core/server/data/importer/handlers/image.js +2 -2
- package/core/server/data/importer/import-archive.js +131 -0
- package/core/server/data/importer/import-manager.js +18 -180
- package/core/server/data/importer/importers/content-file-importer.js +66 -4
- package/core/server/data/importer/importers/data/data-importer.js +3 -3
- package/core/server/data/migrations/utils/migrations.js +1 -1
- package/core/server/data/migrations/versions/6.61/2026-08-19-14-30-20-add-written-by-to-members-custom-field-values.js +42 -0
- package/core/server/data/migrations/versions/6.61/2026-08-19-14-38-53-add-members-custom-field-bindings-table.js +26 -0
- package/core/server/data/migrations/versions/6.61/2026-08-19-14-48-06-add-tier-checkout-field-tables.js +35 -0
- package/core/server/data/schema/schema.js +90 -0
- package/core/server/data/seeders/importers/automation-action-revisions-importer.js +3 -3
- package/core/server/data/seeders/importers/automation-actions-importer.js +3 -3
- package/core/server/data/seeders/importers/automation-run-steps-importer.js +3 -3
- package/core/server/data/seeders/importers/automation-runs-importer.js +5 -5
- package/core/server/data/seeders/importers/automations-importer.js +3 -3
- package/core/server/data/seeders/importers/comment-reports-importer.js +1 -1
- package/core/server/data/seeders/importers/comments-importer.js +1 -1
- package/core/server/data/seeders/importers/email-batches-importer.js +1 -1
- package/core/server/data/seeders/importers/email-recipients-importer.js +1 -1
- package/core/server/data/seeders/importers/emails-importer.js +1 -1
- package/core/server/data/seeders/importers/labels-importer.js +1 -1
- package/core/server/data/seeders/importers/members-click-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-created-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-feedback-importer.js +1 -1
- package/core/server/data/seeders/importers/members-importer.js +1 -1
- package/core/server/data/seeders/importers/members-login-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-products-importer.js +1 -1
- package/core/server/data/seeders/importers/members-status-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-stripe-customers-importer.js +1 -1
- package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +1 -1
- package/core/server/data/seeders/importers/members-subscribe-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +1 -1
- package/core/server/data/seeders/importers/offer-redemptions-importer.js +1 -1
- package/core/server/data/seeders/importers/offers-importer.js +1 -1
- package/core/server/data/seeders/importers/posts-importer.js +1 -1
- package/core/server/data/seeders/importers/table-importer.js +2 -2
- package/core/server/data/seeders/importers/tags-importer.js +1 -1
- package/core/server/data/seeders/importers/users-importer.js +1 -1
- package/core/server/data/seeders/importers/web-mentions-importer.js +1 -1
- package/core/server/data/seeders/utils/random.js +3 -3
- package/core/server/ghost-server.js +3 -2
- package/core/server/lib/db-types/boolean.js +18 -0
- package/core/server/lib/image/image-size.js +24 -0
- package/core/server/lib/package-json/parse.js +2 -2
- package/core/server/lib/promise-pool.js +31 -0
- 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/automations/database-automations-repository.js +26 -26
- package/core/server/services/automations/poll.js +1 -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/assets.js +74 -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 +204 -54
- 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 +1 -1
- package/core/server/services/content-import/import/post-link.js +11 -0
- package/core/server/services/content-import/import/post-repository.js +100 -0
- package/core/server/services/content-import/import/reader.js +9 -2
- package/core/server/services/content-import/import/relations.js +149 -0
- package/core/server/services/content-import/import/report.js +34 -0
- package/core/server/services/content-import/import/row.js +11 -2
- package/core/server/services/content-import/import/schema.js +30 -0
- package/core/server/services/content-import/import/source.js +125 -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 +58 -34
- 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/email-analytics-service.js +8 -1
- package/core/server/services/email-analytics/index.js +2 -7
- package/core/server/services/email-analytics/lib/queries.js +7 -1
- 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/gift-links/schema.js +3 -3
- package/core/server/services/gifts/CONTEXT.md +1 -1
- package/core/server/services/gifts/constants.js +1 -1
- package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
- package/core/server/services/gifts/gift-bookshelf-repository.js +2 -2
- package/core/server/services/gifts/gift-delivery-bookshelf-repository.js +18 -9
- package/core/server/services/gifts/gift-delivery-schema.js +5 -5
- package/core/server/services/gifts/gift-delivery-service.js +4 -0
- package/core/server/services/gifts/gift-email-service.js +0 -1
- package/core/server/services/gifts/gift-schema.js +10 -10
- package/core/server/services/gifts/gift-service.js +4 -2
- 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 +25 -15
- package/core/server/services/lib/mailgun-client.js +44 -8
- package/core/server/services/mail/ghost-mailer.js +4 -4
- package/core/server/services/media-inliner/external-media-inliner-job.js +12 -0
- package/core/server/services/media-inliner/external-media-inliner.js +103 -29
- package/core/server/services/media-inliner/service.js +13 -41
- package/core/server/services/media-inliner/types.js +2 -0
- 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/export/exporter.js +4 -6
- package/core/server/services/members/import-export/import/completion-email.js +2 -5
- package/core/server/services/members/import-export/import/importer.js +21 -5
- package/core/server/services/members/import-export/import/row.js +0 -3
- package/core/server/services/members/import-export/import/stripe-utils.js +6 -1
- package/core/server/services/members/import-export/index.js +10 -12
- 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 +9 -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 +53 -63
- package/core/server/services/members/members-api/services/payments-service.js +47 -1
- package/core/server/services/members/service.js +1 -5
- package/core/server/services/members-custom-fields/actions.js +27 -1
- package/core/server/services/members-custom-fields/bindings-service.js +120 -0
- package/core/server/services/members-custom-fields/codec.js +3 -4
- package/core/server/services/members-custom-fields/definitions-service.js +165 -22
- package/core/server/services/members-custom-fields/filter.js +75 -93
- package/core/server/services/members-custom-fields/index.js +11 -4
- 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/queries.js +5 -0
- package/core/server/services/members-custom-fields/schema.js +37 -6
- package/core/server/services/members-custom-fields/serializers.js +3 -5
- package/core/server/services/members-custom-fields/values-service.js +65 -31
- 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/public-config/config.js +7 -0
- 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 +68 -0
- package/core/server/services/stripe/services/checkout/session-options.js +100 -0
- package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +71 -1
- package/core/server/services/stripe/stripe-api.js +31 -0
- package/core/server/services/stripe/stripe-service.js +26 -9
- package/core/server/services/stripe/webhook-controller.js +10 -0
- package/core/server/services/tier-checkout-config/codec.js +99 -0
- package/core/server/services/tier-checkout-config/index.js +26 -0
- package/core/server/services/tier-checkout-config/models.js +63 -0
- package/core/server/services/tier-checkout-config/queries.js +80 -0
- package/core/server/services/tier-checkout-config/schema.js +33 -0
- package/core/server/services/tier-checkout-config/serializers.js +128 -0
- package/core/server/services/tier-checkout-config/service.js +304 -0
- package/core/server/services/tiers/service.js +21 -0
- 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 +34 -20
- package/core/server/web/api/middleware/upload.js +2 -2
- package/core/server/web/parent/app.js +5 -0
- package/core/server/web/parent/middleware/filter-query-parameters.js +94 -0
- package/core/server/web/parent/middleware/index.js +1 -0
- package/core/server/web/query-parameter-policy/index.js +9 -0
- package/core/server/web/query-parameter-policy/policy.json +58 -0
- package/core/server/web/query-parameter-policy/schema.js +38 -0
- package/core/shared/config/defaults.json +3 -0
- package/core/shared/config/env/config.testing-mysql.json +4 -1
- package/core/shared/config/env/config.testing.json +3 -0
- package/core/shared/config/overrides.json +4 -2
- package/core/shared/labs.js +9 -15
- package/package.json +25 -25
- package/pnpm-lock.yaml +741 -108
- package/pnpm-workspace.yaml +12 -9
- package/tsconfig.json +2 -3
- package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
- package/core/built/admin/assets/Combination-gnJO3vIw.js +0 -41
- package/core/built/admin/assets/account-migration-8qTEI1i1.js +0 -1
- package/core/built/admin/assets/activitypub/inbox-DQ5CwLma.js +0 -1284
- package/core/built/admin/assets/activitypub/label-B72sfvEU.js +0 -16
- package/core/built/admin/assets/activitypub/layout-CXajhRsL.js +0 -1
- package/core/built/admin/assets/activitypub/settings-71gCm3SO.js +0 -315
- package/core/built/admin/assets/add-integration-modal--YpTq3c0.js +0 -1
- package/core/built/admin/assets/add-newsletter-modal-C8Ix2hol.js +0 -1
- package/core/built/admin/assets/add-recommendation-modal-CScuNFz4.js +0 -1
- package/core/built/admin/assets/alert-dialog-wEbVxANM.js +0 -1
- package/core/built/admin/assets/analytics-Cnji45H5.js +0 -1
- package/core/built/admin/assets/app-utils-D2Wp7ZSS.js +0 -1
- package/core/built/admin/assets/audience-DTLMXAFH.js +0 -1
- package/core/built/admin/assets/automations-BWpRCZ_f.js +0 -1
- package/core/built/admin/assets/bluesky-sharing-DHOpQxff.js +0 -1
- package/core/built/admin/assets/chart-helpers-B3OqQ6Ez.js +0 -1
- package/core/built/admin/assets/color-picker-Bmo1r9Fc.js +0 -3
- package/core/built/admin/assets/color-picker-field-DywowPhF.js +0 -1
- package/core/built/admin/assets/combobox-C4QCh6Yw.js +0 -1
- package/core/built/admin/assets/command-DcLbSifC.js +0 -1
- package/core/built/admin/assets/comments-Bxy_3WyE.js +0 -1
- package/core/built/admin/assets/confirmation-context-CLFHhyyH.js +0 -1
- package/core/built/admin/assets/custom-field-type-option-D0PXoSnP.js +0 -10
- package/core/built/admin/assets/custom-integration-modal-DCIHKN33.js +0 -1
- package/core/built/admin/assets/design-and-theme-modal-CZ-PkW7o.js +0 -23
- package/core/built/admin/assets/dialog-Db7c164G.js +0 -1
- package/core/built/admin/assets/dirty-confirm-dialog-CmARpZQS.js +0 -1
- package/core/built/admin/assets/dist-QLZuGq7o2.js +0 -1
- package/core/built/admin/assets/domain-D0SAtc-T.js +0 -1
- package/core/built/admin/assets/dropzone-CaPOeDRZ.js +0 -5
- package/core/built/admin/assets/edit-profile-By7v5XW5.js +0 -1
- package/core/built/admin/assets/editor-COXn4Atu.js +0 -8
- package/core/built/admin/assets/explore-BsNYrubV.js +0 -1
- package/core/built/admin/assets/feed-8RR1O1bK.js +0 -1
- package/core/built/admin/assets/filter-sources-4C0kF1NU.js +0 -1
- package/core/built/admin/assets/filters-CV5jCb9n.js +0 -1
- package/core/built/admin/assets/filters-Dmr0PoqU.js +0 -1
- package/core/built/admin/assets/first-promoter-modal-OCzSaL3B.js +0 -1
- package/core/built/admin/assets/gift-link-modal-0mzjn5oF.js +0 -1
- package/core/built/admin/assets/growth-55vWlGT_.js +0 -1
- package/core/built/admin/assets/growth-DA5AluYw.js +0 -3
- package/core/built/admin/assets/history-modal-G1s5hHz7.js +0 -1
- package/core/built/admin/assets/html-field-BegxsWpw.js +0 -1
- package/core/built/admin/assets/index-CDP9tIOk.js +0 -4
- package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
- package/core/built/admin/assets/index.es-BMUCj9TR.js +0 -1
- package/core/built/admin/assets/input-UHrKuvBT.js +0 -1
- package/core/built/admin/assets/invite-user-modal-BrAkxEO3.js +0 -1
- package/core/built/admin/assets/koenig-loader-DwVY_V-H.js +0 -1
- package/core/built/admin/assets/kpi-card-LERqWBoY.js +0 -1
- package/core/built/admin/assets/kpi-helpers-DB3ouhYF.js +0 -1
- package/core/built/admin/assets/kpi-tabs-BGvtMD8S.js +0 -1
- package/core/built/admin/assets/label-picker-BBWykUeA.js +0 -1
- package/core/built/admin/assets/layout-Di5K7doM.js +0 -1
- package/core/built/admin/assets/loading-indicator-SFTqyYVE.js +0 -1
- package/core/built/admin/assets/member-custom-fields-gOv6Hoh3.js +0 -1
- package/core/built/admin/assets/member-detail-D7mZDDp3.js +0 -1
- package/core/built/admin/assets/member-route-0Aa52Ntz.js +0 -1
- package/core/built/admin/assets/members-DvZG9t69.js +0 -2
- package/core/built/admin/assets/moderation-DzzPLDyl.js +0 -1
- package/core/built/admin/assets/navigation-modal-CI8Bx5vn.js +0 -1
- package/core/built/admin/assets/newsletter-Bg3cq5U-.js +0 -1
- package/core/built/admin/assets/newsletter-detail-modal-DQU3r4g2.js +0 -1
- package/core/built/admin/assets/newsletters-DMDfZbMS.js +0 -1
- package/core/built/admin/assets/note-i8k6pjaw.js +0 -1
- package/core/built/admin/assets/notifications-psA_2Ph4.js +0 -1
- package/core/built/admin/assets/offers-container-modal-BWfjSdyg.js +0 -1
- package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
- package/core/built/admin/assets/overview-C-6xOLaf.js +0 -1
- package/core/built/admin/assets/overview-DaLhpRrC.js +0 -1
- package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
- package/core/built/admin/assets/popover-CFgqFDvC.js +0 -1
- package/core/built/admin/assets/portal-frame-DjBF-uy2.js +0 -1
- package/core/built/admin/assets/portal-modal-Cf0pBAk8.js +0 -1
- package/core/built/admin/assets/post-analytics-Buz1COoY.js +0 -1
- package/core/built/admin/assets/post-analytics-header-B-P0eFnT.js +0 -1
- package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
- package/core/built/admin/assets/preferences-Cq1aOiLy.js +0 -5
- package/core/built/admin/assets/profile-D6dHYf2o.js +0 -1
- package/core/built/admin/assets/select-D_RQaXgt.js +0 -1
- package/core/built/admin/assets/settings-B5hJKZ5C.js +0 -1
- package/core/built/admin/assets/settings-DIo_F-MF.js +0 -4
- package/core/built/admin/assets/share-modal-CLBfj377.js +0 -1
- package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
- package/core/built/admin/assets/slack-modal-Bt9I_tEo.js +0 -1
- package/core/built/admin/assets/sort-button-DMBXF7tP.js +0 -1
- package/core/built/admin/assets/stats-B_YkF7bp.js +0 -1
- package/core/built/admin/assets/stats-view-BOCp9RG8.js +0 -1
- package/core/built/admin/assets/stripe-connect-modal-BeSukI8q.js +0 -1
- package/core/built/admin/assets/tag-detail-2a3BfzTW.js +0 -2
- package/core/built/admin/assets/tags-Dp2_8UzL.js +0 -1
- package/core/built/admin/assets/testimonials-modal-C9nrypNo.js +0 -1
- package/core/built/admin/assets/tier-detail-modal-CxRwgTPR.js +0 -1
- package/core/built/admin/assets/use-check-theme-limit-error-C9-QhGdV.js +0 -1
- package/core/built/admin/assets/use-filter-params-CSpAvgD2.js +0 -1
- package/core/built/admin/assets/use-growth-stats-BOmoPDHJ.js +0 -1
- package/core/built/admin/assets/use-post-referrers-CbXLFIex.js +0 -1
- package/core/built/admin/assets/use-reply-chain-data-JYFKSO83.js +0 -1
- package/core/built/admin/assets/use-settings-navigation-BBzro2-V.js +0 -1
- package/core/built/admin/assets/use-tinybird-query-D2Aeoty5.js +0 -39
- package/core/built/admin/assets/use-tinybird-token-DBuwMmln.js +0 -1
- package/core/built/admin/assets/user-detail-modal-59mBJqxN.js +0 -1
- package/core/built/admin/assets/users-5msE1WMs.js +0 -1
- package/core/built/admin/assets/web-DUuX7nE2.js +0 -2
- package/core/built/admin/assets/web-N8ucs2aG.js +0 -1
- package/core/server/api/endpoints/member-custom-fields.js +0 -100
- 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/update-check/run-update-check.js +0 -63
- /package/core/server/lib/{db-date.js → db-types/date.js} +0 -0
|
@@ -33,7 +33,6 @@ class BatchSendingService {
|
|
|
33
33
|
#models;
|
|
34
34
|
#db;
|
|
35
35
|
#sentry;
|
|
36
|
-
#debugStorageFilePath;
|
|
37
36
|
#getRequiredUrlRelations;
|
|
38
37
|
#shuttingDown = false;
|
|
39
38
|
#inFlight = new Set();
|
|
@@ -68,7 +67,6 @@ class BatchSendingService {
|
|
|
68
67
|
* @param {object} [dependencies.BEFORE_RETRY_CONFIG]
|
|
69
68
|
* @param {object} [dependencies.AFTER_RETRY_CONFIG]
|
|
70
69
|
* @param {object} [dependencies.MAILGUN_API_RETRY_CONFIG]
|
|
71
|
-
* @param {string} [dependencies.debugStorageFilePath]
|
|
72
70
|
*/
|
|
73
71
|
constructor({
|
|
74
72
|
emailRenderer,
|
|
@@ -83,7 +81,6 @@ class BatchSendingService {
|
|
|
83
81
|
BEFORE_RETRY_CONFIG,
|
|
84
82
|
AFTER_RETRY_CONFIG,
|
|
85
83
|
MAILGUN_API_RETRY_CONFIG,
|
|
86
|
-
debugStorageFilePath,
|
|
87
84
|
}) {
|
|
88
85
|
this.#emailRenderer = emailRenderer;
|
|
89
86
|
this.#sendingService = sendingService;
|
|
@@ -93,7 +90,6 @@ class BatchSendingService {
|
|
|
93
90
|
this.#models = models;
|
|
94
91
|
this.#db = db;
|
|
95
92
|
this.#sentry = sentry;
|
|
96
|
-
this.#debugStorageFilePath = debugStorageFilePath;
|
|
97
93
|
this.#getRequiredUrlRelations = getRequiredUrlRelations;
|
|
98
94
|
|
|
99
95
|
if (BEFORE_RETRY_CONFIG) {
|
|
@@ -13,7 +13,7 @@ function isUnsplashImage(url) {
|
|
|
13
13
|
}
|
|
14
14
|
const { DateTime } = require('luxon');
|
|
15
15
|
const htmlToPlaintext = require('@tryghost/html-to-plaintext');
|
|
16
|
-
const
|
|
16
|
+
const emailAddressParser = require('../email-address/email-address-parser');
|
|
17
17
|
const { getEmailDesign } = require('../email-rendering/email-design');
|
|
18
18
|
const { registerHelpers } = require('./helpers/register-helpers');
|
|
19
19
|
const crypto = require('crypto');
|
|
@@ -229,6 +229,8 @@ function cheerioLoad(html) {
|
|
|
229
229
|
* @prop {string} id
|
|
230
230
|
* @prop {RegExp} token
|
|
231
231
|
* @prop {(member: MemberLike) => string} getValue
|
|
232
|
+
* @prop {boolean} [trusted] - Value is server-generated, so it is inserted into the
|
|
233
|
+
* html body as-is instead of being HTML-escaped. Defaults to false (escaped).
|
|
232
234
|
*/
|
|
233
235
|
|
|
234
236
|
/**
|
|
@@ -337,7 +339,7 @@ class EmailRenderer {
|
|
|
337
339
|
}
|
|
338
340
|
|
|
339
341
|
#getRawFromAddress(post, newsletter) {
|
|
340
|
-
// Pass the raw name through;
|
|
342
|
+
// Pass the raw name through; emailAddressParser.stringify() is the single
|
|
341
343
|
// point that escapes it for the RFC5322 quoted-string From header. Escaping
|
|
342
344
|
// here too would double-escape (e.g. a title containing a double quote).
|
|
343
345
|
let senderName = this.#settingsCache.get('title') || '';
|
|
@@ -394,7 +396,7 @@ class EmailRenderer {
|
|
|
394
396
|
{ useFallbackAddress },
|
|
395
397
|
);
|
|
396
398
|
|
|
397
|
-
return
|
|
399
|
+
return emailAddressParser.stringify(addresses.from);
|
|
398
400
|
}
|
|
399
401
|
|
|
400
402
|
/**
|
|
@@ -423,7 +425,7 @@ class EmailRenderer {
|
|
|
423
425
|
);
|
|
424
426
|
|
|
425
427
|
if (addresses.replyTo) {
|
|
426
|
-
return
|
|
428
|
+
return emailAddressParser.stringify(addresses.replyTo);
|
|
427
429
|
}
|
|
428
430
|
return null;
|
|
429
431
|
}
|
|
@@ -920,18 +922,21 @@ class EmailRenderer {
|
|
|
920
922
|
getValue: (member) => {
|
|
921
923
|
return this.createUnsubscribeUrl(member.uuid, { newsletterUuid });
|
|
922
924
|
},
|
|
925
|
+
trusted: true, // Server-generated URL, must not be HTML-escaped
|
|
923
926
|
},
|
|
924
927
|
{
|
|
925
928
|
id: 'manage_account_url',
|
|
926
929
|
getValue: () => {
|
|
927
930
|
return this.createManageAccountUrl();
|
|
928
931
|
},
|
|
932
|
+
trusted: true, // Server-generated URL, must not be HTML-escaped
|
|
929
933
|
},
|
|
930
934
|
{
|
|
931
935
|
id: 'uuid',
|
|
932
936
|
getValue: (member) => {
|
|
933
937
|
return member.uuid;
|
|
934
938
|
},
|
|
939
|
+
trusted: true, // Server-generated identifier
|
|
935
940
|
},
|
|
936
941
|
{
|
|
937
942
|
id: 'key',
|
|
@@ -941,6 +946,7 @@ class EmailRenderer {
|
|
|
941
946
|
.update(member.uuid)
|
|
942
947
|
.digest('hex');
|
|
943
948
|
},
|
|
949
|
+
trusted: true, // Server-generated hmac
|
|
944
950
|
},
|
|
945
951
|
{
|
|
946
952
|
id: 'first_name',
|
|
@@ -1000,6 +1006,7 @@ class EmailRenderer {
|
|
|
1000
1006
|
return this.createUnsubscribeUrl(member.uuid, { newsletterUuid });
|
|
1001
1007
|
},
|
|
1002
1008
|
required: true, // Used in email headers
|
|
1009
|
+
trusted: true, // Server-generated URL, must not be HTML-escaped
|
|
1003
1010
|
},
|
|
1004
1011
|
// Unique ID used for ad images to bypass ESP image proxies
|
|
1005
1012
|
{
|
|
@@ -1007,6 +1014,7 @@ class EmailRenderer {
|
|
|
1007
1014
|
getValue: () => {
|
|
1008
1015
|
return crypto.randomUUID();
|
|
1009
1016
|
},
|
|
1017
|
+
trusted: true, // Server-generated identifier
|
|
1010
1018
|
},
|
|
1011
1019
|
];
|
|
1012
1020
|
|
|
@@ -1043,6 +1051,7 @@ class EmailRenderer {
|
|
|
1043
1051
|
getValue: fallback
|
|
1044
1052
|
? (member) => definition.getValue(member) || fallback
|
|
1045
1053
|
: definition.getValue,
|
|
1054
|
+
trusted: definition.trusted === true,
|
|
1046
1055
|
});
|
|
1047
1056
|
}
|
|
1048
1057
|
}
|
|
@@ -1056,6 +1065,7 @@ class EmailRenderer {
|
|
|
1056
1065
|
originalId: definition.id,
|
|
1057
1066
|
token: new RegExp(`%%\\{${definition.id}\\}%%`, 'g'),
|
|
1058
1067
|
getValue: definition.getValue,
|
|
1068
|
+
trusted: definition.trusted === true,
|
|
1059
1069
|
});
|
|
1060
1070
|
}
|
|
1061
1071
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const debug = require('@tryghost/debug')('i18n');
|
|
2
|
-
const logging = require('@tryghost/logging');
|
|
3
2
|
const url = require('../../api/endpoints/utils/serializers/output/utils/url');
|
|
4
3
|
const events = require('../../lib/common/events');
|
|
5
4
|
|
|
@@ -55,12 +54,6 @@ class EmailServiceWrapper {
|
|
|
55
54
|
const emailAnalyticsJobs = require('../email-analytics/jobs');
|
|
56
55
|
const { cachedImageSizeFromUrl } = require('../../lib/image');
|
|
57
56
|
|
|
58
|
-
// capture errors from mailgun client and log them in sentry
|
|
59
|
-
const errorHandler = (error) => {
|
|
60
|
-
logging.info(`Capturing error for mailgun email provider service`);
|
|
61
|
-
sentry.captureException(error);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
57
|
// Mailgun client instance for email provider
|
|
65
58
|
const mailgunClient = new MailgunClient({
|
|
66
59
|
config: configService,
|
|
@@ -78,7 +71,6 @@ class EmailServiceWrapper {
|
|
|
78
71
|
const mailgunEmailProvider = new MailgunEmailProvider({
|
|
79
72
|
mailgunClient,
|
|
80
73
|
config: configService,
|
|
81
|
-
errorHandler,
|
|
82
74
|
});
|
|
83
75
|
|
|
84
76
|
const emailRenderer = new EmailRenderer({
|
|
@@ -134,7 +126,6 @@ class EmailServiceWrapper {
|
|
|
134
126
|
db,
|
|
135
127
|
sentry,
|
|
136
128
|
getRequiredUrlRelations,
|
|
137
|
-
debugStorageFilePath: configService.getContentPath('data'),
|
|
138
129
|
});
|
|
139
130
|
|
|
140
131
|
if (ghostServer) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
2
|
const errors = require('@tryghost/errors');
|
|
3
3
|
const debug = require('@tryghost/debug')('email-service:mailgun-provider-service');
|
|
4
|
+
const { escapeExpression } = require('handlebars');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @typedef {object} Config
|
|
@@ -35,35 +36,41 @@ const debug = require('@tryghost/debug')('email-service:mailgun-provider-service
|
|
|
35
36
|
class MailgunEmailProvider {
|
|
36
37
|
#mailgunClient;
|
|
37
38
|
#config;
|
|
38
|
-
#errorHandler;
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* @param {object} dependencies
|
|
42
42
|
* @param {import('../lib/mailgun-client')} dependencies.mailgunClient - mailgun client to send emails
|
|
43
43
|
* @param {Config} dependencies.config
|
|
44
|
-
* @param {Function} [dependencies.errorHandler] - custom error handler for logging exceptions
|
|
45
44
|
*/
|
|
46
|
-
constructor({ mailgunClient, config
|
|
45
|
+
constructor({ mailgunClient, config }) {
|
|
47
46
|
this.#mailgunClient = mailgunClient;
|
|
48
47
|
this.#config = config;
|
|
49
|
-
this.#errorHandler = errorHandler;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
#createRecipientData(replacements) {
|
|
50
|
+
#createRecipientData(replacements, htmlEscapedIds) {
|
|
53
51
|
let recipientData = {};
|
|
54
52
|
|
|
55
53
|
recipientData = replacements.reduce((acc, replacement) => {
|
|
56
54
|
const { id, value } = replacement;
|
|
57
55
|
acc[id] = value;
|
|
56
|
+
// Mailgun's recipient-variables substitution is a simple string replace with
|
|
57
|
+
// no HTML awareness, and the same value is used for both the html and plaintext
|
|
58
|
+
// bodies. Member-controlled values get an extra, escaped variant that only the
|
|
59
|
+
// html body points at. Trusted server-generated values (urls, uuids, hmacs) are
|
|
60
|
+
// skipped so their URLs don't end up entity-encoded inside hrefs.
|
|
61
|
+
if (htmlEscapedIds.has(id)) {
|
|
62
|
+
acc[`${id}_html`] = typeof value === 'string' ? escapeExpression(value) : value;
|
|
63
|
+
}
|
|
58
64
|
return acc;
|
|
59
65
|
}, {});
|
|
60
66
|
|
|
61
67
|
return recipientData;
|
|
62
68
|
}
|
|
63
69
|
|
|
64
|
-
#updateRecipientVariables(data, replacementDefinitions) {
|
|
70
|
+
#updateRecipientVariables(data, replacementDefinitions, isHtml) {
|
|
65
71
|
for (const def of replacementDefinitions) {
|
|
66
|
-
|
|
72
|
+
const useHtmlVariant = isHtml && !def.trusted;
|
|
73
|
+
data = data.replace(def.token, `%recipient.${def.id}${useHtmlVariant ? '_html' : ''}%`);
|
|
67
74
|
}
|
|
68
75
|
return data;
|
|
69
76
|
}
|
|
@@ -128,8 +135,11 @@ class MailgunEmailProvider {
|
|
|
128
135
|
}
|
|
129
136
|
|
|
130
137
|
// create recipient data for Mailgun using replacement definitions
|
|
138
|
+
const htmlEscapedIds = new Set(
|
|
139
|
+
replacementDefinitions.filter((def) => !def.trusted).map((def) => def.id),
|
|
140
|
+
);
|
|
131
141
|
const recipientData = recipients.reduce((acc, recipient) => {
|
|
132
|
-
acc[recipient.email] = this.#createRecipientData(recipient.replacements);
|
|
142
|
+
acc[recipient.email] = this.#createRecipientData(recipient.replacements, htmlEscapedIds);
|
|
133
143
|
return acc;
|
|
134
144
|
}, {});
|
|
135
145
|
|
|
@@ -139,6 +149,7 @@ class MailgunEmailProvider {
|
|
|
139
149
|
messageData[key] = this.#updateRecipientVariables(
|
|
140
150
|
messageData[key],
|
|
141
151
|
replacementDefinitions,
|
|
152
|
+
key === 'html',
|
|
142
153
|
);
|
|
143
154
|
}
|
|
144
155
|
});
|
|
@@ -165,7 +176,7 @@ class MailgunEmailProvider {
|
|
|
165
176
|
message: this.#createMailgunErrorMessage(error),
|
|
166
177
|
errorDetails: JSON.stringify({ error, messageData }),
|
|
167
178
|
context: `Mailgun Error ${error.status}: ${error.details}`,
|
|
168
|
-
help: `https://ghost.org/
|
|
179
|
+
help: `https://docs.ghost.org/newsletters/#bulk-email-configuration`,
|
|
169
180
|
code: 'BULK_EMAIL_SEND_FAILED',
|
|
170
181
|
});
|
|
171
182
|
} else {
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DbGiftLink = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
-
const
|
|
5
|
+
const date_1 = require("../../lib/db-types/date");
|
|
6
6
|
exports.DbGiftLink = zod_1.z.object({
|
|
7
7
|
token: zod_1.z.string(),
|
|
8
8
|
post_id: zod_1.z.string(),
|
|
9
|
-
created_at:
|
|
10
|
-
updated_at:
|
|
9
|
+
created_at: date_1.DbDate,
|
|
10
|
+
updated_at: date_1.DbDate.nullable(),
|
|
11
11
|
});
|
|
@@ -37,7 +37,7 @@ The buyer's chosen way of handing over a gift subscription: the publication emai
|
|
|
37
37
|
_Avoid_: Delivery mode
|
|
38
38
|
|
|
39
39
|
**Redemption link**:
|
|
40
|
-
A single-use, time-limited link through which a purchased gift subscription can be viewed and claimed. Its bearer may see the gift's buyer name, intended recipient name, and personal message
|
|
40
|
+
A single-use, time-limited link through which a purchased gift subscription can be viewed and claimed. Its bearer may see the gift's buyer name, intended recipient name, recipient email, and personal message; the intended recipient does not reserve redemption.
|
|
41
41
|
_Avoid_: Gift Link
|
|
42
42
|
|
|
43
43
|
**Gift redemption**:
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.GIFT_DELIVERY_EMAIL_TAG = exports.GIFT_DELIVERY_STALE_AFTER_MS = exports.GIFT_REMINDER_FLOOR_DAYS = exports.GIFT_REMINDER_LEAD_DAYS = exports.GIFT_SEND_HOUR = exports.GIFT_MAX_SCHEDULE_DAYS = exports.GIFT_EXPIRY_DAYS = void 0;
|
|
4
4
|
exports.GIFT_EXPIRY_DAYS = 365;
|
|
5
5
|
// How far ahead a delivery may be scheduled. Portal's picker carries its own
|
|
6
|
-
// copy (GIFT_MAX_SCHEDULE_DAYS in beta-gift-page.
|
|
6
|
+
// copy (GIFT_MAX_SCHEDULE_DAYS in beta-gift-page.tsx) since Portal ships
|
|
7
7
|
// separately — change them together.
|
|
8
8
|
exports.GIFT_MAX_SCHEDULE_DAYS = 365;
|
|
9
9
|
// Site-local hour a scheduled delivery is sent at. Portal never derives
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
<tr>
|
|
32
32
|
<td align="left" style="padding-bottom: 22px; text-align: left;">
|
|
33
33
|
{{#if siteIconUrl}}
|
|
34
|
-
<
|
|
34
|
+
<img src="{{siteIconUrl}}" alt="{{siteTitle}}" border="0" width="48" height="48" style="border-radius: 4px;">
|
|
35
35
|
{{else}}
|
|
36
|
-
<
|
|
36
|
+
<span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 17px; font-weight: 700; color: {{accentColor}};">{{siteTitle}}</span>
|
|
37
37
|
{{/if}}
|
|
38
38
|
</td>
|
|
39
39
|
</tr>
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
</tr>
|
|
93
93
|
<tr>
|
|
94
94
|
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-top: 40px;">
|
|
95
|
-
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 16px; font-size: 11px; color: #738A94; font-weight: normal; margin: 0;">{{t 'This message was sent from {siteDomain} to {email} on behalf of {buyerName} ({buyerEmail}).' siteDomain=
|
|
95
|
+
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 16px; font-size: 11px; color: #738A94; font-weight: normal; margin: 0;">{{t 'This message was sent from {siteDomain} to {email} on behalf of {buyerName} ({buyerEmail}).' siteDomain=siteDomain email=toEmail buyerName=buyerName buyerEmail=buyerEmail}}</p>
|
|
96
96
|
</td>
|
|
97
97
|
</tr>
|
|
98
98
|
</table>
|
|
@@ -7,7 +7,7 @@ exports.GiftBookshelfRepository = void 0;
|
|
|
7
7
|
const errors_1 = __importDefault(require("@tryghost/errors"));
|
|
8
8
|
const mongo_utils_1 = require("@tryghost/mongo-utils");
|
|
9
9
|
const gift_codec_1 = require("./gift-codec");
|
|
10
|
-
const
|
|
10
|
+
const date_1 = require("../../lib/db-types/date");
|
|
11
11
|
class GiftBookshelfRepository {
|
|
12
12
|
model;
|
|
13
13
|
knex;
|
|
@@ -117,7 +117,7 @@ class GiftBookshelfRepository {
|
|
|
117
117
|
async deleteAbandonedCheckouts(cutoff) {
|
|
118
118
|
return this.knex('gifts')
|
|
119
119
|
.where({ status: 'payment_pending' })
|
|
120
|
-
.where('checkout_started_at', '<=', (0,
|
|
120
|
+
.where('checkout_started_at', '<=', (0, date_1.toDatabaseDate)(cutoff))
|
|
121
121
|
.del();
|
|
122
122
|
}
|
|
123
123
|
async create(gift, options = {}) {
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.GiftDeliveryBookshelfRepository = void 0;
|
|
7
7
|
const errors_1 = __importDefault(require("@tryghost/errors"));
|
|
8
|
-
const
|
|
8
|
+
const date_1 = require("../../lib/db-types/date");
|
|
9
9
|
const gift_codec_1 = require("./gift-codec");
|
|
10
10
|
const gift_delivery_codec_1 = require("./gift-delivery-codec");
|
|
11
11
|
// A null scheduled_at means the delivery was due at purchase time, so it is
|
|
@@ -14,7 +14,7 @@ function dueDeliveries(query, now) {
|
|
|
14
14
|
query.andWhere((due) => {
|
|
15
15
|
due
|
|
16
16
|
.whereNull('gift_deliveries.scheduled_at')
|
|
17
|
-
.orWhere('gift_deliveries.scheduled_at', '<=', (0,
|
|
17
|
+
.orWhere('gift_deliveries.scheduled_at', '<=', (0, date_1.toDatabaseDate)(now));
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
// Deliveries that still need a send attempt: never started, or claimed by a
|
|
@@ -24,7 +24,7 @@ function recoverableDeliveries(query, staleBefore) {
|
|
|
24
24
|
recoverable.where('gift_deliveries.status', 'pending').orWhere((stale) => {
|
|
25
25
|
stale
|
|
26
26
|
.where('gift_deliveries.status', 'sending')
|
|
27
|
-
.where('gift_deliveries.started_at', '<=', (0,
|
|
27
|
+
.where('gift_deliveries.started_at', '<=', (0, date_1.toDatabaseDate)(staleBefore));
|
|
28
28
|
});
|
|
29
29
|
});
|
|
30
30
|
}
|
|
@@ -43,6 +43,15 @@ class GiftDeliveryBookshelfRepository {
|
|
|
43
43
|
const model = await this.model.findOne({ gift_id: giftId }, { require: false, ...options });
|
|
44
44
|
return model ? (0, gift_delivery_codec_1.decodeGiftDeliveryRow)(model.toJSON()) : null;
|
|
45
45
|
}
|
|
46
|
+
async getByGiftToken(giftToken, options = {}) {
|
|
47
|
+
const db = options.transacting ?? this.knex;
|
|
48
|
+
const row = await db('gift_deliveries')
|
|
49
|
+
.select('gift_deliveries.*')
|
|
50
|
+
.join('gifts', 'gifts.id', 'gift_deliveries.gift_id')
|
|
51
|
+
.where('gifts.token', giftToken)
|
|
52
|
+
.first();
|
|
53
|
+
return row ? (0, gift_delivery_codec_1.decodeGiftDeliveryRow)(row) : null;
|
|
54
|
+
}
|
|
46
55
|
async getByProviderMessageId(providerMessageId) {
|
|
47
56
|
const model = await this.model.findOne({ email_provider_message_id: providerMessageId }, { require: false });
|
|
48
57
|
return model ? (0, gift_delivery_codec_1.decodeGiftDeliveryRow)(model.toJSON()) : null;
|
|
@@ -83,8 +92,8 @@ class GiftDeliveryBookshelfRepository {
|
|
|
83
92
|
.join('gifts', 'gifts.id', 'gift_deliveries.gift_id')
|
|
84
93
|
.where('gift_deliveries.status', 'pending')
|
|
85
94
|
.where('gifts.status', 'purchased')
|
|
86
|
-
.where('gift_deliveries.scheduled_at', '>', (0,
|
|
87
|
-
return rows.map((row) => (0,
|
|
95
|
+
.where('gift_deliveries.scheduled_at', '>', (0, date_1.toDatabaseDate)(now));
|
|
96
|
+
return rows.map((row) => (0, date_1.fromDatabaseDate)(row.scheduled_at));
|
|
88
97
|
}
|
|
89
98
|
async tryStartDelivery(id, now, staleBefore) {
|
|
90
99
|
const claimed = await this.knex('gift_deliveries')
|
|
@@ -100,7 +109,7 @@ class GiftDeliveryBookshelfRepository {
|
|
|
100
109
|
.modify(recoverableDeliveries, staleBefore)
|
|
101
110
|
.update({
|
|
102
111
|
status: 'sending',
|
|
103
|
-
started_at: (0,
|
|
112
|
+
started_at: (0, date_1.toDatabaseDate)(now),
|
|
104
113
|
});
|
|
105
114
|
if (claimed !== 1) {
|
|
106
115
|
return null;
|
|
@@ -110,7 +119,7 @@ class GiftDeliveryBookshelfRepository {
|
|
|
110
119
|
async markSent(id, sentAt, providerMessageId) {
|
|
111
120
|
return this.updateState(id, 'sending', {
|
|
112
121
|
status: 'sent',
|
|
113
|
-
email_sent_at: (0,
|
|
122
|
+
email_sent_at: (0, date_1.toDatabaseDate)(sentAt),
|
|
114
123
|
email_provider_message_id: providerMessageId,
|
|
115
124
|
started_at: null,
|
|
116
125
|
});
|
|
@@ -119,7 +128,7 @@ class GiftDeliveryBookshelfRepository {
|
|
|
119
128
|
// details so the message can still be correlated with transport outcomes
|
|
120
129
|
async recordCancelledAcceptance(id, sentAt, providerMessageId) {
|
|
121
130
|
return this.updateState(id, 'cancelled', {
|
|
122
|
-
email_sent_at: (0,
|
|
131
|
+
email_sent_at: (0, date_1.toDatabaseDate)(sentAt),
|
|
123
132
|
email_provider_message_id: providerMessageId,
|
|
124
133
|
});
|
|
125
134
|
}
|
|
@@ -145,7 +154,7 @@ class GiftDeliveryBookshelfRepository {
|
|
|
145
154
|
return updated === 1;
|
|
146
155
|
}
|
|
147
156
|
async recordOutcome({ providerMessageId, outcome, timestamp, error, }) {
|
|
148
|
-
const outcomeAt = (0,
|
|
157
|
+
const outcomeAt = (0, date_1.toDatabaseDate)(timestamp);
|
|
149
158
|
const lowerPriorityOutcomes = outcome === 'permanent_failed'
|
|
150
159
|
? ['temporary_failed', 'delivered']
|
|
151
160
|
: outcome === 'delivered'
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DbGiftDelivery = exports.GiftDeliveryOutcomeSchema = exports.GiftDeliveryStatusSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
-
const
|
|
5
|
+
const date_1 = require("../../lib/db-types/date");
|
|
6
6
|
exports.GiftDeliveryStatusSchema = zod_1.z.enum([
|
|
7
7
|
'pending',
|
|
8
8
|
'sending',
|
|
@@ -21,11 +21,11 @@ exports.DbGiftDelivery = zod_1.z.object({
|
|
|
21
21
|
gift_id: zod_1.z.string(),
|
|
22
22
|
recipient_email: zod_1.z.string().email(),
|
|
23
23
|
status: exports.GiftDeliveryStatusSchema.default('pending'),
|
|
24
|
-
scheduled_at:
|
|
25
|
-
started_at:
|
|
26
|
-
email_sent_at:
|
|
24
|
+
scheduled_at: date_1.DbDate.nullable().default(null),
|
|
25
|
+
started_at: date_1.DbDate.nullable().default(null),
|
|
26
|
+
email_sent_at: date_1.DbDate.nullable().default(null),
|
|
27
27
|
email_provider_message_id: zod_1.z.string().nullable().default(null),
|
|
28
28
|
outcome: exports.GiftDeliveryOutcomeSchema.default('unknown'),
|
|
29
|
-
outcome_at:
|
|
29
|
+
outcome_at: date_1.DbDate.nullable().default(null),
|
|
30
30
|
outcome_error: zod_1.z.string().nullable().default(null),
|
|
31
31
|
});
|
|
@@ -41,6 +41,10 @@ class GiftDeliveryService {
|
|
|
41
41
|
await this.deps.giftDeliveryRepository.create(delivery, options);
|
|
42
42
|
return delivery.id;
|
|
43
43
|
}
|
|
44
|
+
async getRecipientEmailForGift(giftToken, options = {}) {
|
|
45
|
+
const delivery = await this.deps.giftDeliveryRepository.getByGiftToken(giftToken, options);
|
|
46
|
+
return delivery?.recipientEmail ?? null;
|
|
47
|
+
}
|
|
44
48
|
async dispatchForGift({ giftId, }) {
|
|
45
49
|
const delivery = await this.deps.giftDeliveryRepository.getByGiftId(giftId);
|
|
46
50
|
if (!delivery || delivery.status !== 'pending') {
|
|
@@ -182,7 +182,6 @@ class GiftEmailService {
|
|
|
182
182
|
const giftLink = `${siteUrl.replace(/\/$/, '')}/gift/${token}`;
|
|
183
183
|
const { html, text } = await this.renderer.renderDelivery({
|
|
184
184
|
siteTitle,
|
|
185
|
-
siteUrl,
|
|
186
185
|
siteIconUrl: this.blogIcon.getIconUrl({ absolute: true, fallbackToDefault: false }),
|
|
187
186
|
siteDomain,
|
|
188
187
|
accentColor: this.accentColor,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DbGift = exports.GiftStatusSchema = exports.GiftCadenceSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
-
const
|
|
5
|
+
const date_1 = require("../../lib/db-types/date");
|
|
6
6
|
exports.GiftCadenceSchema = zod_1.z.enum(['month', 'year']);
|
|
7
7
|
exports.GiftStatusSchema = zod_1.z.enum([
|
|
8
8
|
'payment_pending',
|
|
@@ -32,14 +32,14 @@ exports.DbGift = zod_1.z.object({
|
|
|
32
32
|
amount: zod_1.z.number().int().nonnegative(),
|
|
33
33
|
stripe_checkout_session_id: zod_1.z.string().nullable(),
|
|
34
34
|
stripe_payment_intent_id: zod_1.z.string().nullable(),
|
|
35
|
-
checkout_started_at:
|
|
36
|
-
consumes_at:
|
|
37
|
-
expires_at:
|
|
35
|
+
checkout_started_at: date_1.DbDate.nullable().default(null),
|
|
36
|
+
consumes_at: date_1.DbDate.nullable(),
|
|
37
|
+
expires_at: date_1.DbDate.nullable(),
|
|
38
38
|
status: exports.GiftStatusSchema,
|
|
39
|
-
purchased_at:
|
|
40
|
-
redeemed_at:
|
|
41
|
-
consumed_at:
|
|
42
|
-
expired_at:
|
|
43
|
-
refunded_at:
|
|
44
|
-
consumes_soon_reminder_sent_at:
|
|
39
|
+
purchased_at: date_1.DbDate.nullable(),
|
|
40
|
+
redeemed_at: date_1.DbDate.nullable(),
|
|
41
|
+
consumed_at: date_1.DbDate.nullable(),
|
|
42
|
+
expired_at: date_1.DbDate.nullable(),
|
|
43
|
+
refunded_at: date_1.DbDate.nullable(),
|
|
44
|
+
consumes_soon_reminder_sent_at: date_1.DbDate.nullable().default(null),
|
|
45
45
|
});
|
|
@@ -565,7 +565,7 @@ class GiftService {
|
|
|
565
565
|
transacting,
|
|
566
566
|
newMember: input.newMember,
|
|
567
567
|
});
|
|
568
|
-
const redemption = await this.serializeRedemption(redeemed);
|
|
568
|
+
const redemption = await this.serializeRedemption(redeemed, { transacting });
|
|
569
569
|
return { redeemed, member, redemption };
|
|
570
570
|
};
|
|
571
571
|
const { redeemed, member, redemption } = input.transacting
|
|
@@ -1044,7 +1044,8 @@ class GiftService {
|
|
|
1044
1044
|
});
|
|
1045
1045
|
return true;
|
|
1046
1046
|
}
|
|
1047
|
-
async serializeRedemption(gift) {
|
|
1047
|
+
async serializeRedemption(gift, options = {}) {
|
|
1048
|
+
const recipientEmail = await this.deps.giftDeliveryService.getRecipientEmailForGift(gift.token, options);
|
|
1048
1049
|
const tier = await this.deps.tiersService.api.read(gift.tierId);
|
|
1049
1050
|
if (!tier) {
|
|
1050
1051
|
throw new errors_1.default.InternalServerError({
|
|
@@ -1060,6 +1061,7 @@ class GiftService {
|
|
|
1060
1061
|
amount: gift.amount,
|
|
1061
1062
|
buyer_name: gift.buyerName,
|
|
1062
1063
|
recipient_name: gift.recipientName,
|
|
1064
|
+
recipient_email: recipientEmail,
|
|
1063
1065
|
message: gift.personalMessage,
|
|
1064
1066
|
expires_at: gift.expiresAt,
|
|
1065
1067
|
consumes_at: gift.consumesAt,
|
|
@@ -14,7 +14,7 @@ const send_gift_delivery_event_1 = require("./events/send-gift-delivery-event");
|
|
|
14
14
|
// Persistent scheduling adapters keep their queue across restarts and opt out
|
|
15
15
|
// of boot-time rebuilds (same contract post scheduling honours in boot.js).
|
|
16
16
|
let rescheduleDeliveriesOnBoot = true;
|
|
17
|
-
|
|
17
|
+
function init(options) {
|
|
18
18
|
if (exports.service) {
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
@@ -37,7 +37,7 @@ async function init(options) {
|
|
|
37
37
|
const labsService = require('../../../shared/labs');
|
|
38
38
|
const urlUtils = require('../../../shared/url-utils').default;
|
|
39
39
|
const settingsHelpers = require('../settings-helpers');
|
|
40
|
-
const
|
|
40
|
+
const emailAddressParser = require('../email-address/email-address-parser');
|
|
41
41
|
const { blogIcon } = require('../../../server/lib/image');
|
|
42
42
|
const { t } = require('../i18n');
|
|
43
43
|
const repository = new gift_bookshelf_repository_1.GiftBookshelfRepository({
|
|
@@ -57,7 +57,7 @@ async function init(options) {
|
|
|
57
57
|
bulkMailer: new MailgunClient({ config, settings: settingsCache }),
|
|
58
58
|
settingsCache,
|
|
59
59
|
urlUtils,
|
|
60
|
-
getFromAddress: () =>
|
|
60
|
+
getFromAddress: () => emailAddressParser.stringify(settingsHelpers.getDefaultEmail()),
|
|
61
61
|
getReplyToAddress: () => settingsHelpers.getMembersSupportAddress(),
|
|
62
62
|
blogIcon,
|
|
63
63
|
t,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const logging = require('@tryghost/logging');
|
|
3
|
-
const
|
|
3
|
+
const jobManager = require('../../jobs');
|
|
4
4
|
const CleanGiftsJob = require('./clean-gifts-job').default;
|
|
5
5
|
|
|
6
6
|
let hasScheduled = {
|
|
@@ -31,7 +31,7 @@ function scheduleJob(key, name, jobFile) {
|
|
|
31
31
|
const at = randomOffPeakDailyCron();
|
|
32
32
|
|
|
33
33
|
logging.info(`[Background Job] ${name} scheduled at ${at}`);
|
|
34
|
-
|
|
34
|
+
jobManager.addJob({
|
|
35
35
|
at,
|
|
36
36
|
job: path.resolve(__dirname, jobFile),
|
|
37
37
|
name,
|
|
@@ -43,14 +43,14 @@ function scheduleJob(key, name, jobFile) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
module.exports = {
|
|
46
|
-
async scheduleGiftCleanupJob(
|
|
46
|
+
async scheduleGiftCleanupJob(jobsService) {
|
|
47
47
|
if (alreadyScheduledOrTest('cleanup')) {
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const cron = randomOffPeakDailyCron();
|
|
52
52
|
logging.info(`[Background Job] clean-gifts scheduled at ${cron}`);
|
|
53
|
-
await
|
|
53
|
+
await jobsService.scheduleRecurring(new CleanGiftsJob(), { cron });
|
|
54
54
|
|
|
55
55
|
hasScheduled.cleanup = true;
|
|
56
56
|
},
|
|
@@ -160,7 +160,7 @@ class IndexNowPingService {
|
|
|
160
160
|
err,
|
|
161
161
|
message: err.message,
|
|
162
162
|
context: (0, tpl_1.default)(constants_1.messages.requestFailedError, { service: 'IndexNow' }),
|
|
163
|
-
help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://ghost.org/
|
|
163
|
+
help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://docs.ghost.org/' }),
|
|
164
164
|
}),
|
|
165
165
|
};
|
|
166
166
|
}
|
|
@@ -181,7 +181,7 @@ class IndexNowPingService {
|
|
|
181
181
|
err,
|
|
182
182
|
message: err.message,
|
|
183
183
|
context: (0, tpl_1.default)(constants_1.messages.requestFailedError, { service: 'IndexNow' }),
|
|
184
|
-
help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://ghost.org/
|
|
184
|
+
help: (0, tpl_1.default)(constants_1.messages.requestFailedHelp, { url: 'https://docs.ghost.org/' }),
|
|
185
185
|
}),
|
|
186
186
|
};
|
|
187
187
|
}
|
|
@@ -30,7 +30,9 @@ async function accept(invitation) {
|
|
|
30
30
|
throw new errors.NotFoundError({ message: tpl(messages.inviteExpired) });
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
const email = invite.get('email');
|
|
34
|
+
|
|
35
|
+
let user = await models.User.findOne({ email }, options);
|
|
34
36
|
if (user) {
|
|
35
37
|
throw new errors.ValidationError({
|
|
36
38
|
message: tpl(messages.inviteEmailAlreadyExist.message),
|
|
@@ -45,7 +47,7 @@ async function accept(invitation) {
|
|
|
45
47
|
|
|
46
48
|
await models.User.add(
|
|
47
49
|
{
|
|
48
|
-
email
|
|
50
|
+
email,
|
|
49
51
|
name: data.name,
|
|
50
52
|
password: data.password,
|
|
51
53
|
roles: [roleId],
|
|
@@ -9,22 +9,13 @@ const models = require('../../models');
|
|
|
9
9
|
const sentry = require('../../../shared/sentry');
|
|
10
10
|
const domainEvents = require('@tryghost/domain-events');
|
|
11
11
|
const config = require('../../../shared/config');
|
|
12
|
-
const WorkerModelEventBridge = require('./worker-model-event-bridge');
|
|
13
12
|
const errorHandler = (error, workerMeta) => {
|
|
14
13
|
logging.error(error, `[Background Job] ${workerMeta.name} failed`);
|
|
15
14
|
sentry.captureException(error);
|
|
16
15
|
};
|
|
17
16
|
const events = require('../../lib/common/events');
|
|
18
|
-
const workerModelEventBridge = new WorkerModelEventBridge({ models, events, logging, sentry });
|
|
19
17
|
|
|
20
18
|
const workerMessageHandler = ({ name, message }) => {
|
|
21
|
-
if (workerModelEventBridge.isModelEventMessage(message)) {
|
|
22
|
-
// Carries its own `eventName` rather than job-manager's reserved `event` key,
|
|
23
|
-
// so it routes through the bridge instead of being dispatched as a raw domain event.
|
|
24
|
-
workerModelEventBridge.handle(message, { jobName: name });
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
19
|
if (typeof message === 'string' && !['done', 'cancelled'].includes(message)) {
|
|
29
20
|
logging.info(`[Background Job] ${name}: ${message}`);
|
|
30
21
|
}
|