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
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.prepareImportSource = prepareImportSource;
|
|
7
|
+
exports.isDataFile = isDataFile;
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const glob_1 = require("glob");
|
|
11
|
+
const import_archive_1 = __importDefault(require("../../../data/importer/import-archive"));
|
|
12
|
+
const assets_1 = require("./assets");
|
|
13
|
+
const errors = require('@tryghost/errors');
|
|
14
|
+
const DATA_EXTENSIONS = new Set(['.csv', '.json', '.md', '.markdown']);
|
|
15
|
+
const noCleanup = async () => { };
|
|
16
|
+
async function prepareImportSource(request) {
|
|
17
|
+
const extension = path_1.default.extname(request.fileName).toLowerCase();
|
|
18
|
+
if (extension === '.csv') {
|
|
19
|
+
return { filePath: request.filePath, cleanup: noCleanup };
|
|
20
|
+
}
|
|
21
|
+
if (extension !== '.zip') {
|
|
22
|
+
throw new errors.ValidationError({ message: 'Please select a valid CSV or ZIP file.' });
|
|
23
|
+
}
|
|
24
|
+
const archive = new import_archive_1.default({
|
|
25
|
+
extensions: [...DATA_EXTENSIONS],
|
|
26
|
+
directories: [],
|
|
27
|
+
});
|
|
28
|
+
const directory = await archive.extract(request.filePath);
|
|
29
|
+
let cleaned = false;
|
|
30
|
+
const cleanup = async () => {
|
|
31
|
+
if (!cleaned) {
|
|
32
|
+
cleaned = true;
|
|
33
|
+
await fs_extra_1.default.remove(directory);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
try {
|
|
37
|
+
archive.isValid(directory);
|
|
38
|
+
const baseDirectory = archive.getBaseDirectory(directory);
|
|
39
|
+
const entries = (0, glob_1.globSync)('**/*', { cwd: directory, nodir: true, dot: true });
|
|
40
|
+
const dataFiles = entries.filter(isDataFile);
|
|
41
|
+
const csvFiles = dataFiles.filter((file) => extensionOf(file) === '.csv');
|
|
42
|
+
if (csvFiles.length === 0) {
|
|
43
|
+
throw new errors.ValidationError({
|
|
44
|
+
message: 'ZIP files uploaded here must contain one CSV file.',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (csvFiles.length > 1) {
|
|
48
|
+
throw new errors.ValidationError({
|
|
49
|
+
message: 'ZIP files can contain only one CSV file. Remove the extra CSV files and try again.',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (dataFiles.length > 1 || entries.some(isUnsupportedCompetingDataFile)) {
|
|
53
|
+
throw new errors.ValidationError({
|
|
54
|
+
message: 'ZIP files cannot contain CSV, JSON, or Markdown import files together. Keep only the CSV file and try again.',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
validateWrapper(entries, csvFiles[0]);
|
|
58
|
+
const csvParts = csvFiles[0].split('/').filter(Boolean);
|
|
59
|
+
const csvBaseDirectory = csvParts.length === 2 ? csvParts[0] : undefined;
|
|
60
|
+
if (csvBaseDirectory !== baseDirectory) {
|
|
61
|
+
throw new errors.ValidationError({ message: 'Invalid ZIP file structure.' });
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
filePath: path_1.default.join(directory, csvFiles[0]),
|
|
65
|
+
assets: await (0, assets_1.prepareAssetBatch)(archive, directory, baseDirectory),
|
|
66
|
+
cleanup,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
await cleanup();
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function validateWrapper(entries, csvFile) {
|
|
75
|
+
const csvParts = csvFile.split('/').filter(Boolean);
|
|
76
|
+
if (csvParts.length !== 2) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const wrapper = csvParts[0];
|
|
80
|
+
const outsideWrapper = entries.some((entry) => {
|
|
81
|
+
const parts = entry.split('/').filter(Boolean);
|
|
82
|
+
return !isMetadata(parts) && parts[0] !== wrapper;
|
|
83
|
+
});
|
|
84
|
+
if (outsideWrapper) {
|
|
85
|
+
throw new errors.ValidationError({ message: 'Invalid ZIP file structure.' });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function isDataFile(fileName) {
|
|
89
|
+
const parts = fileName.split('/').filter(Boolean);
|
|
90
|
+
if (parts.length === 0 || isMetadata(parts)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const extension = extensionOf(fileName);
|
|
94
|
+
if (!DATA_EXTENSIONS.has(extension)) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (parts.length === 1) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
return parts.length === 2;
|
|
101
|
+
}
|
|
102
|
+
function extensionOf(fileName) {
|
|
103
|
+
return path_1.default.posix.extname(fileName).toLowerCase();
|
|
104
|
+
}
|
|
105
|
+
function isUnsupportedCompetingDataFile(fileName) {
|
|
106
|
+
const extension = extensionOf(fileName);
|
|
107
|
+
if (extension === '.csv' || !DATA_EXTENSIONS.has(extension)) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
const parts = fileName.split('/').filter(Boolean);
|
|
111
|
+
if (parts.length === 0 || isMetadata(parts) || isFileAttachment(parts)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
return !isDataFile(fileName);
|
|
115
|
+
}
|
|
116
|
+
function isFileAttachment(parts) {
|
|
117
|
+
const assetParts = ['content', 'files'].includes(parts[0]) ? [...parts] : parts.slice(1);
|
|
118
|
+
if (assetParts[0] === 'content') {
|
|
119
|
+
assetParts.shift();
|
|
120
|
+
}
|
|
121
|
+
return assetParts.length > 1 && assetParts[0] === 'files';
|
|
122
|
+
}
|
|
123
|
+
function isMetadata(parts) {
|
|
124
|
+
return (parts[0] === '__MACOSX' || parts.some((part) => part.startsWith('._') || part === '.DS_Store'));
|
|
125
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createImportFileStager = createImportFileStager;
|
|
7
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
|
+
function createImportFileStager() {
|
|
12
|
+
return {
|
|
13
|
+
async stage({ filePath, fileName }) {
|
|
14
|
+
const stagedPath = node_path_1.default.join(node_os_1.default.tmpdir(), `content-csv-import-${node_crypto_1.default.randomUUID()}`);
|
|
15
|
+
try {
|
|
16
|
+
await fs_extra_1.default.copyFile(filePath, stagedPath, fs_extra_1.default.constants.COPYFILE_EXCL);
|
|
17
|
+
await fs_extra_1.default.chmod(stagedPath, 0o600);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
await fs_extra_1.default.remove(stagedPath).catch(() => { });
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
return { path: stagedPath, name: fileName };
|
|
24
|
+
},
|
|
25
|
+
async remove(file) {
|
|
26
|
+
await fs_extra_1.default.remove(file.path);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -10,17 +10,19 @@ const MAX_RUN_AGE_MS = 60 * 60 * 1000;
|
|
|
10
10
|
class ImportRunStore {
|
|
11
11
|
// Insertion-ordered, so count-eviction drops the oldest run first.
|
|
12
12
|
_runs = new Map();
|
|
13
|
+
_settledWaiters = new Set();
|
|
13
14
|
_now;
|
|
14
15
|
constructor({ now = () => new Date() } = {}) {
|
|
15
16
|
this._now = now;
|
|
16
17
|
}
|
|
17
|
-
create(id, total) {
|
|
18
|
+
create(id, total, sourceColumns = []) {
|
|
18
19
|
this.evict();
|
|
19
20
|
const run = {
|
|
20
21
|
id,
|
|
21
22
|
status: 'running',
|
|
22
23
|
startedAt: this._now(),
|
|
23
24
|
total,
|
|
25
|
+
sourceColumns,
|
|
24
26
|
rows: [],
|
|
25
27
|
};
|
|
26
28
|
this._runs.set(id, run);
|
|
@@ -47,10 +49,31 @@ class ImportRunStore {
|
|
|
47
49
|
get(id) {
|
|
48
50
|
return this._runs.get(id);
|
|
49
51
|
}
|
|
52
|
+
release(id) {
|
|
53
|
+
this._runs.delete(id);
|
|
54
|
+
this.resolveSettledWaiters();
|
|
55
|
+
}
|
|
56
|
+
allSettled() {
|
|
57
|
+
if (this._runs.size === 0) {
|
|
58
|
+
return Promise.resolve();
|
|
59
|
+
}
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
this._settledWaiters.add(resolve);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
resolveSettledWaiters() {
|
|
65
|
+
if (this._runs.size > 0) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
for (const resolve of this._settledWaiters) {
|
|
69
|
+
resolve();
|
|
70
|
+
}
|
|
71
|
+
this._settledWaiters.clear();
|
|
72
|
+
}
|
|
50
73
|
// A running run is never evicted, whatever its age: the job holds only the runId,
|
|
51
74
|
// so evicting mid-import would silently turn its record()/finish() calls into
|
|
52
75
|
// no-ops and lose the report. The count cap can briefly overshoot while several
|
|
53
|
-
// imports run at once; the
|
|
76
|
+
// imports run at once; the jobs backend bounds how many that can be.
|
|
54
77
|
evict() {
|
|
55
78
|
const cutoff = this._now().getTime() - MAX_RUN_AGE_MS;
|
|
56
79
|
for (const [id, run] of this._runs) {
|
|
@@ -5,36 +5,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.init = init;
|
|
7
7
|
exports.importCSV = importCSV;
|
|
8
|
+
exports.handleJob = handleJob;
|
|
9
|
+
exports.allSettled = allSettled;
|
|
8
10
|
const zod_1 = require("zod");
|
|
9
11
|
const importer_1 = __importDefault(require("./import/importer"));
|
|
12
|
+
const completion_email_1 = __importDefault(require("./import/completion-email"));
|
|
13
|
+
const post_repository_1 = require("./import/post-repository");
|
|
10
14
|
const reader_1 = __importDefault(require("./import/reader"));
|
|
11
|
-
const
|
|
15
|
+
const schema_1 = require("./import/schema");
|
|
12
16
|
const store_1 = require("./import/store");
|
|
17
|
+
const source_1 = require("./import/source");
|
|
18
|
+
const media_1 = require("./import/media");
|
|
19
|
+
const local_media_url_1 = require("./import/local-media-url");
|
|
20
|
+
const post_link_1 = require("./import/post-link");
|
|
21
|
+
const staged_file_1 = require("./import/staged-file");
|
|
22
|
+
const jobs_service_1 = require("../jobs-service");
|
|
13
23
|
// The request is built from HTTP upload metadata, so it is validated at the
|
|
14
24
|
// service boundary rather than trusted.
|
|
15
|
-
const importableFields = new Set(row_1.EDITORIAL_POST_FIELDS);
|
|
16
|
-
const mappingSchema = zod_1.z.record(zod_1.z.string(), zod_1.z.string()).superRefine((mapping, ctx) => {
|
|
17
|
-
const targets = new Set();
|
|
18
|
-
for (const [header, target] of Object.entries(mapping)) {
|
|
19
|
-
if (!header || header in Object.prototype) {
|
|
20
|
-
ctx.addIssue({ code: 'custom', message: `Invalid CSV header mapping: "${header}"` });
|
|
21
|
-
}
|
|
22
|
-
if (target && !importableFields.has(target)) {
|
|
23
|
-
ctx.addIssue({ code: 'custom', message: `Unknown post field mapping: "${target}"` });
|
|
24
|
-
}
|
|
25
|
-
if (target && targets.has(target)) {
|
|
26
|
-
ctx.addIssue({ code: 'custom', message: `Post field is mapped more than once: "${target}"` });
|
|
27
|
-
}
|
|
28
|
-
targets.add(target);
|
|
29
|
-
}
|
|
30
|
-
if (!targets.has('title')) {
|
|
31
|
-
ctx.addIssue({ code: 'custom', message: 'Post field mapping must include "title"' });
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
const importRequestSchema = zod_1.z.object({
|
|
35
|
-
filePath: zod_1.z.string().min(1),
|
|
36
|
-
mapping: mappingSchema.optional(),
|
|
37
|
-
});
|
|
38
25
|
// A junk timezone setting falls back to UTC rather than mis-stamping the batch tag.
|
|
39
26
|
const timezoneSchema = zod_1.z.string().min(1).catch('Etc/UTC');
|
|
40
27
|
const errors = require('@tryghost/errors');
|
|
@@ -47,12 +34,16 @@ function makeImporter() {
|
|
|
47
34
|
// are guaranteed loaded.
|
|
48
35
|
const models = require('../../models');
|
|
49
36
|
const lexicalLib = require('../../lib/lexical');
|
|
50
|
-
const jobsService = require('../jobs');
|
|
51
37
|
const settingsCache = require('../../../shared/settings-cache');
|
|
52
38
|
const urlService = require('../url');
|
|
39
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
40
|
+
const mediaInlinerService = require('../media-inliner');
|
|
41
|
+
const config = require('../../../shared/config');
|
|
53
42
|
const ObjectID = require('bson-objectid').default;
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
const { GhostMailer } = require('../mail');
|
|
44
|
+
const ghostMailer = new GhostMailer();
|
|
45
|
+
// Row aggregates and best-effort cleanup are intentionally reported without
|
|
46
|
+
// failing a run. Fatal handler errors are reported by the class-based jobs service.
|
|
56
47
|
const report = (error) => {
|
|
57
48
|
try {
|
|
58
49
|
logging.error({ event: { name: 'content.import.error' }, err: error }, '[Background Job] content-import error');
|
|
@@ -62,19 +53,38 @@ function makeImporter() {
|
|
|
62
53
|
// Callers report from catch blocks, so this must not throw.
|
|
63
54
|
}
|
|
64
55
|
};
|
|
56
|
+
const email = {
|
|
57
|
+
send: (run, recipient) => ghostMailer.send((0, completion_email_1.default)(run, recipient, urlUtils.urlFor('admin', true))),
|
|
58
|
+
getDefaultRecipient: async () => (await models.User.getOwnerUser()).get('email'),
|
|
59
|
+
};
|
|
65
60
|
return new importer_1.default({
|
|
66
61
|
readRows: reader_1.default,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
},
|
|
62
|
+
prepareSource: source_1.prepareImportSource,
|
|
63
|
+
posts: new post_repository_1.BookshelfPostsRepository(models),
|
|
70
64
|
getHtmlToLexical: () => lexicalLib.htmlToLexicalConverter,
|
|
71
65
|
getMarkdownToHtml: () => require('@tryghost/kg-markdown-html-renderer').render,
|
|
72
66
|
getCleanHTML: () => require('@tryghost/mg-clean-html').cleanHTML,
|
|
73
|
-
|
|
67
|
+
createMediaInliner: () => new media_1.PostMediaInliner({
|
|
68
|
+
media: mediaInlinerService.getInstance(),
|
|
69
|
+
isLocalMediaUrl: (sourceUrl) => (0, local_media_url_1.isLocalMediaUrl)(sourceUrl, {
|
|
70
|
+
siteUrl: config.getSiteUrl(),
|
|
71
|
+
subdir: config.getSubdir(),
|
|
72
|
+
assetBaseUrls: [
|
|
73
|
+
config.get('urls:image'),
|
|
74
|
+
config.get('urls:media'),
|
|
75
|
+
config.get('urls:files'),
|
|
76
|
+
],
|
|
77
|
+
}),
|
|
78
|
+
}),
|
|
79
|
+
email,
|
|
80
|
+
dispatchJob: (job) => (0, jobs_service_1.getInstance)().dispatch(job),
|
|
81
|
+
fileStager: (0, staged_file_1.createImportFileStager)(),
|
|
74
82
|
report,
|
|
75
83
|
store: new store_1.ImportRunStore(),
|
|
76
|
-
|
|
77
|
-
|
|
84
|
+
urlForPost: (post) => (0, post_link_1.urlForImportedPost)(post, {
|
|
85
|
+
adminUrl: urlUtils.urlFor('admin', true),
|
|
86
|
+
publishedUrl: (publishedPost) => urlService.getUrlForResource({ ...publishedPost.toJSON(), type: 'posts' }, { absolute: true }),
|
|
87
|
+
}),
|
|
78
88
|
newRunId: () => new ObjectID().toHexString(),
|
|
79
89
|
getTimezone: () => timezoneSchema.parse(settingsCache.get('timezone')),
|
|
80
90
|
});
|
|
@@ -88,7 +98,7 @@ function importCSV(request) {
|
|
|
88
98
|
if (!importer) {
|
|
89
99
|
throw new errors.InternalServerError({ message: 'Content import service used before init' });
|
|
90
100
|
}
|
|
91
|
-
const parsedRequest = importRequestSchema.safeParse(request);
|
|
101
|
+
const parsedRequest = schema_1.importRequestSchema.safeParse(request);
|
|
92
102
|
if (!parsedRequest.success) {
|
|
93
103
|
throw new errors.ValidationError({
|
|
94
104
|
message: parsedRequest.error.issues[0]?.message ?? 'Invalid content import request',
|
|
@@ -97,3 +107,17 @@ function importCSV(request) {
|
|
|
97
107
|
}
|
|
98
108
|
return importer.importCSV(parsedRequest.data);
|
|
99
109
|
}
|
|
110
|
+
function handleJob(job) {
|
|
111
|
+
if (!importer) {
|
|
112
|
+
throw new errors.InternalServerError({ message: 'Content import service used before init' });
|
|
113
|
+
}
|
|
114
|
+
return importer.handle(job);
|
|
115
|
+
}
|
|
116
|
+
// Test-facing parity with the legacy inline queue while the import run store
|
|
117
|
+
// remains in memory. M8 removes this together with that store.
|
|
118
|
+
function allSettled() {
|
|
119
|
+
if (!importer) {
|
|
120
|
+
return Promise.resolve();
|
|
121
|
+
}
|
|
122
|
+
return importer.allSettled();
|
|
123
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const job_1 = require("../../jobs-service/job");
|
|
4
|
+
class ContentCSVImportJob extends job_1.Job {
|
|
5
|
+
static type = 'content-csv-import';
|
|
6
|
+
importId;
|
|
7
|
+
file;
|
|
8
|
+
mapping;
|
|
9
|
+
importTagNames;
|
|
10
|
+
emailRecipient;
|
|
11
|
+
constructor(data) {
|
|
12
|
+
super();
|
|
13
|
+
this.importId = data.importId;
|
|
14
|
+
this.file = data.file;
|
|
15
|
+
this.mapping = data.mapping;
|
|
16
|
+
this.importTagNames = data.importTagNames;
|
|
17
|
+
this.emailRecipient = data.emailRecipient;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.default = ContentCSVImportJob;
|
|
@@ -45,7 +45,7 @@ const messages = {
|
|
|
45
45
|
jsonInvalid: 'JSON input must be an array of redirect objects.',
|
|
46
46
|
yamlParse: 'Could not parse YAML: {context}.',
|
|
47
47
|
yamlInvalid: 'YAML input is invalid. Check the contents of your YAML file.',
|
|
48
|
-
redirectsHelp: 'https://ghost.org/
|
|
48
|
+
redirectsHelp: 'https://docs.ghost.org/themes/routing/#redirects',
|
|
49
49
|
};
|
|
50
50
|
const parseJson = (content) => {
|
|
51
51
|
let parsed;
|
|
@@ -124,7 +124,7 @@ const parseYaml = (content) => {
|
|
|
124
124
|
exports.parseYaml = parseYaml;
|
|
125
125
|
// Round-trips through parseYaml to []. Avoids a "download → save →
|
|
126
126
|
// re-upload throws on empty body" footgun on fresh installs.
|
|
127
|
-
const EMPTY_DOWNLOAD_TEMPLATE = '# See https://ghost.org/
|
|
127
|
+
const EMPTY_DOWNLOAD_TEMPLATE = '# See https://docs.ghost.org/themes/routing/#redirects\n301: {}\n302: {}\n';
|
|
128
128
|
const serializeToYaml = (redirects) => {
|
|
129
129
|
const permanent = [];
|
|
130
130
|
const temporary = [];
|
|
@@ -44,7 +44,7 @@ const dynamic_redirect_manager_1 = __importDefault(require("../lib/dynamic-redir
|
|
|
44
44
|
const errify_1 = require("../../../shared/errify");
|
|
45
45
|
const messages = {
|
|
46
46
|
redirectsRegister: 'Could not register custom redirects.',
|
|
47
|
-
redirectsHelp: 'https://ghost.org/
|
|
47
|
+
redirectsHelp: 'https://docs.ghost.org/themes/routing/#redirects',
|
|
48
48
|
skippedInvalidRedirect: 'Skipped invalid redirect: {context}',
|
|
49
49
|
rejectedRedirect: 'Could not register redirect: {from} -> {to}',
|
|
50
50
|
allRedirectsSkipped: 'None of the {total} redirect(s) in the store could be activated. Check the logged errors above.',
|
|
@@ -5,7 +5,7 @@ const errors = require('@tryghost/errors');
|
|
|
5
5
|
const messages = {
|
|
6
6
|
redirectsWrongFormat: 'Incorrect redirects file format.',
|
|
7
7
|
invalidRedirectsFromRegex: 'Incorrect RegEx in redirects file.',
|
|
8
|
-
redirectsHelp: 'https://ghost.org/
|
|
8
|
+
redirectsHelp: 'https://docs.ghost.org/themes/routing/#redirects',
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -1,53 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.stringify = exports.parse = void 0;
|
|
7
|
+
const addressparser_1 = __importDefault(require("nodemailer/lib/addressparser"));
|
|
3
8
|
/**
|
|
4
|
-
*
|
|
5
|
-
* @
|
|
6
|
-
* @
|
|
9
|
+
* Parse an email string into an EmailAddress object
|
|
10
|
+
* @param email Email string to parse
|
|
11
|
+
* @returns Parsed email or null if invalid
|
|
7
12
|
*/
|
|
8
|
-
|
|
9
|
-
module.exports = class EmailAddressParser {
|
|
10
|
-
/**
|
|
11
|
-
* Parse an email string into an EmailAddress object
|
|
12
|
-
* @param {string} email - Email string to parse
|
|
13
|
-
* @returns {EmailAddress|null} Parsed email or null if invalid
|
|
14
|
-
*/
|
|
15
|
-
static parse(email) {
|
|
13
|
+
const parse = (email) => {
|
|
16
14
|
if (!email || typeof email !== 'string' || !email.length) {
|
|
17
|
-
|
|
15
|
+
return null;
|
|
18
16
|
}
|
|
19
|
-
|
|
20
|
-
const parsed = addressparser(email);
|
|
21
|
-
|
|
17
|
+
const parsed = (0, addressparser_1.default)(email);
|
|
22
18
|
if (parsed.length !== 1) {
|
|
23
|
-
|
|
19
|
+
return null;
|
|
24
20
|
}
|
|
25
21
|
const first = parsed[0];
|
|
26
|
-
|
|
27
22
|
// Check first has a group property
|
|
28
23
|
if ('group' in first) {
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
// Unsupported format
|
|
25
|
+
return null;
|
|
31
26
|
}
|
|
32
|
-
|
|
33
27
|
return {
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
address: first.address,
|
|
29
|
+
name: first.name || undefined,
|
|
36
30
|
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
31
|
+
};
|
|
32
|
+
exports.parse = parse;
|
|
33
|
+
/**
|
|
34
|
+
* Convert an EmailAddress object to a string representation
|
|
35
|
+
* @param email Email object to stringify
|
|
36
|
+
* @returns String representation of the email
|
|
37
|
+
*/
|
|
38
|
+
const stringify = (email) => {
|
|
45
39
|
if (!email.name) {
|
|
46
|
-
|
|
40
|
+
return email.address;
|
|
47
41
|
}
|
|
48
|
-
|
|
49
42
|
const escapedName = email.name.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
50
|
-
|
|
51
43
|
/**
|
|
52
44
|
* https://linear.app/ghost/issue/ONC-969
|
|
53
45
|
*
|
|
@@ -65,8 +57,8 @@ module.exports = class EmailAddressParser {
|
|
|
65
57
|
* We remove these characters from the name.
|
|
66
58
|
*/
|
|
67
59
|
const nameCleanedForGmail = escapedName
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
.replace(/[\u2705\u2713\u2714\u2611\u{1F5F8}]/gu, '')
|
|
61
|
+
.trim();
|
|
70
62
|
return `"${nameCleanedForGmail}" <${email.address}>`;
|
|
71
|
-
}
|
|
72
63
|
};
|
|
64
|
+
exports.stringify = stringify;
|
|
@@ -1,11 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
39
|
exports.EmailAddressService = void 0;
|
|
7
40
|
const logging_1 = __importDefault(require("@tryghost/logging"));
|
|
8
|
-
const
|
|
41
|
+
const emailAddressParser = __importStar(require("./email-address-parser"));
|
|
9
42
|
class EmailAddressService {
|
|
10
43
|
#getManagedEmailEnabled;
|
|
11
44
|
#getSendingDomain;
|
|
@@ -25,7 +58,7 @@ class EmailAddressService {
|
|
|
25
58
|
if (!fallbackAddress) {
|
|
26
59
|
return null;
|
|
27
60
|
}
|
|
28
|
-
return
|
|
61
|
+
return emailAddressParser.parse(fallbackAddress);
|
|
29
62
|
};
|
|
30
63
|
this.#isValidEmailAddress = dependencies.isValidEmailAddress;
|
|
31
64
|
}
|
|
@@ -54,8 +87,8 @@ class EmailAddressService {
|
|
|
54
87
|
return transformed.from.address;
|
|
55
88
|
}
|
|
56
89
|
getAddressFromString(from, replyTo) {
|
|
57
|
-
const parsedFrom =
|
|
58
|
-
const parsedReplyTo = replyTo ?
|
|
90
|
+
const parsedFrom = emailAddressParser.parse(from);
|
|
91
|
+
const parsedReplyTo = replyTo ? emailAddressParser.parse(replyTo) : undefined;
|
|
59
92
|
return this.getAddress({
|
|
60
93
|
from: parsedFrom ?? this.defaultFromEmail,
|
|
61
94
|
replyTo: parsedReplyTo ?? undefined,
|
|
@@ -364,15 +364,22 @@ class EmailAnalyticsService {
|
|
|
364
364
|
}
|
|
365
365
|
};
|
|
366
366
|
try {
|
|
367
|
-
await this.#fetchEvents({
|
|
367
|
+
const fetchResult = await this.#fetchEvents({
|
|
368
368
|
batchHandler: processBatch,
|
|
369
369
|
begin,
|
|
370
370
|
end,
|
|
371
371
|
maxEvents,
|
|
372
372
|
events: eventTypes,
|
|
373
373
|
});
|
|
374
|
+
if (fetchResult?.safeCursor &&
|
|
375
|
+
(!fetchData.lastEventTimestamp || fetchResult.safeCursor < fetchData.lastEventTimestamp)) {
|
|
376
|
+
fetchData.lastEventTimestamp = fetchResult.safeCursor;
|
|
377
|
+
}
|
|
374
378
|
}
|
|
375
379
|
catch (err) {
|
|
380
|
+
// A fetch can process events from one domain before another domain fails. Keep the
|
|
381
|
+
// in-memory cursor at the start of this run so the next attempt retries every domain.
|
|
382
|
+
fetchData.lastEventTimestamp = begin;
|
|
376
383
|
if (!(err instanceof Error) || err.message !== 'Fetching canceled') {
|
|
377
384
|
logging_1.default.error('[EmailAnalytics] Error while fetching');
|
|
378
385
|
logging_1.default.error(err);
|
|
@@ -20,7 +20,6 @@ const constants_1 = require("../member-welcome-emails/constants");
|
|
|
20
20
|
const automation_email_analytics_batch_processor_1 = require("./automation-email-analytics-batch-processor");
|
|
21
21
|
const gift_email_analytics_batch_processor_1 = require("./gift-email-analytics-batch-processor");
|
|
22
22
|
const start_gift_email_analytics_job_event_1 = require("./events/start-gift-email-analytics-job-event");
|
|
23
|
-
const gifts_1 = require("../gifts");
|
|
24
23
|
const constants_2 = require("../gifts/constants");
|
|
25
24
|
exports.newsletters = new email_analytics_service_wrapper_1.EmailAnalyticsServiceWrapper({
|
|
26
25
|
logName: 'newsletters',
|
|
@@ -31,7 +30,7 @@ exports.automations = new email_analytics_service_wrapper_1.EmailAnalyticsServic
|
|
|
31
30
|
exports.gifts = new email_analytics_service_wrapper_1.EmailAnalyticsServiceWrapper({
|
|
32
31
|
logName: 'gifts',
|
|
33
32
|
});
|
|
34
|
-
const init = ({ automationsApi, config, db, domainEvents, emailSuppressionList, membersRepository, models: { Email, EmailRecipientFailure, EmailSpamComplaintEvent }, metrics, prometheusClient, settingsCache, }) => {
|
|
33
|
+
const init = ({ automationsApi, config, db, domainEvents, emailSuppressionList, giftDeliveryService, membersRepository, models: { Email, EmailRecipientFailure, EmailSpamComplaintEvent }, metrics, prometheusClient, settingsCache, }) => {
|
|
35
34
|
const queries = new queries_1.Queries(db.knex);
|
|
36
35
|
const newsletterEmailEventProcessor = new email_event_processor_1.default({
|
|
37
36
|
domainEvents,
|
|
@@ -133,11 +132,7 @@ const init = ({ automationsApi, config, db, domainEvents, emailSuppressionList,
|
|
|
133
132
|
},
|
|
134
133
|
metrics,
|
|
135
134
|
settingsCache,
|
|
136
|
-
createEventProcessor: () => new gift_email_analytics_batch_processor_1.GiftEmailAnalyticsBatchProcessor({
|
|
137
|
-
giftDeliveryService: {
|
|
138
|
-
recordOutcome: (data) => gifts_1.deliveryService.recordOutcome(data),
|
|
139
|
-
},
|
|
140
|
-
}),
|
|
135
|
+
createEventProcessor: () => new gift_email_analytics_batch_processor_1.GiftEmailAnalyticsBatchProcessor({ giftDeliveryService }),
|
|
141
136
|
});
|
|
142
137
|
};
|
|
143
138
|
exports.init = init;
|
|
@@ -122,7 +122,13 @@ class Queries {
|
|
|
122
122
|
*/
|
|
123
123
|
async getLastJobRunTimestamp(jobName) {
|
|
124
124
|
const jobData = await this.getJobData(jobName);
|
|
125
|
-
|
|
125
|
+
const timestamp = jobData?.finished_at ?? jobData?.started_at ?? null;
|
|
126
|
+
if (timestamp === null) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
// SQLite returns datetime columns as strings or numbers, so normalise to a Date to match
|
|
130
|
+
// the declared return type and keep callers using Date methods (e.g. getTime()) safe.
|
|
131
|
+
return timestamp instanceof Date ? timestamp : new Date(timestamp);
|
|
126
132
|
}
|
|
127
133
|
/**
|
|
128
134
|
* Sets the timestamp of the last seen event for the specified email analytics events.
|