ghost 6.63.0 → 6.65.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/bin/create-migration.js +15 -0
- package/bin/lib/duplicate-deps.js +204 -0
- package/bin/validate-adapters.js +50 -6
- package/components/tryghost-adapter-base-scheduling-0.2.4.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-api-framework-0.0.0.tgz +0 -0
- package/components/tryghost-i18n-0.0.0.tgz +0 -0
- package/components/{tryghost-kg-default-cards-10.3.5.tgz → tryghost-kg-default-cards-10.3.6.tgz} +0 -0
- package/components/tryghost-kg-default-nodes-2.2.1.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 → tryghost-kg-lexical-html-renderer-1.5.1.tgz} +0 -0
- package/components/tryghost-limit-service-0.0.0.tgz +0 -0
- package/components/tryghost-metafield-types-0.0.0.tgz +0 -0
- package/content/themes/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 +15 -2
- package/content/themes/casper/assets/js/init.js +37 -9
- package/content/themes/casper/package.json +8 -8
- 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 +15 -2
- package/content/themes/source/assets/js/main.js +24 -4
- package/content/themes/source/package.json +8 -8
- package/core/boot.js +27 -15
- package/core/bridge.js +1 -1
- package/core/built/admin/assets/Combination-DQ6f9A5P.js +41 -0
- package/core/built/admin/assets/{PolarAngleAxis-pkMyqz8g.js → PolarAngleAxis-BBaU7PRV.js} +2 -2
- package/core/built/admin/assets/RadialBarChart-Bp20JPnA.js +1 -0
- package/core/built/admin/assets/about-Dp43j18M.js +1 -0
- package/core/built/admin/assets/accordion-h62UzFhj.js +1 -0
- package/core/built/admin/assets/account-migration-CBTbtX6Q.js +1 -0
- package/core/built/admin/assets/action-list-DC9QpX-l.js +1 -0
- package/core/built/admin/assets/activitypub/{account-migration-KA6Jjf9L.js → account-migration-B1DUZS4Q.js} +8 -8
- package/core/built/admin/assets/activitypub/activitypub.js +24 -11
- package/core/built/admin/assets/activitypub/avatar-CRGud8yf.js +153 -0
- package/core/built/admin/assets/activitypub/{avatar-flipboard-csQaNeYK.js → avatar-flipboard-BZNFAXfm.js} +3 -3
- package/core/built/admin/assets/activitypub/{bluesky-sharing-C7nTDMvw.js → bluesky-sharing-Cg_v-LwS.js} +30 -31
- package/core/built/admin/assets/activitypub/{chunk-KS7C4IRE-Ck3O4oo2.js → chunk-KS7C4IRE-CTUL98Lc.js} +2498 -1885
- package/core/built/admin/assets/activitypub/{content-formatters-CLcjaBwV.js → content-formatters-D7GWP7nH.js} +23 -24
- package/core/built/admin/assets/activitypub/{copy-DcOh8kXw.js → copy-CgzTvoeR.js} +2 -2
- package/core/built/admin/assets/activitypub/{domain-fZ-X8i4-.js → domain-C3G_nkHU.js} +46 -46
- package/core/built/admin/assets/activitypub/{edit-profile-BqMLQV88.js → edit-profile-C8cCY-AK.js} +927 -928
- package/core/built/admin/assets/activitypub/{explore-B4yPoP8E.js → explore-NlDT4inq.js} +11 -11
- package/core/built/admin/assets/activitypub/{feed-BRC_mvAe.js → feed-DF22jCTV.js} +10 -10
- package/core/built/admin/assets/activitypub/{field-COacNgOt.js → field-95-iuTte.js} +4 -4
- package/core/built/admin/assets/activitypub/{hash-C7u-irQQ.js → hash-R7LMLnhY.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-CbTTdDQ3.js → inbox-DUJUiV6x.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-BW-yvUoN.js → inbox-DerExBzA.js} +416 -414
- package/core/built/admin/assets/activitypub/{label-kPMmYI7l.js → label-EwCn1QYc.js} +4 -4
- package/core/built/admin/assets/activitypub/layout-Dy6NnW1G.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-CuidJzc0.js → moderation-BSkfiVYo.js} +73 -75
- package/core/built/admin/assets/activitypub/{note-CAMRRSqD.js → note-DOnAJTXK.js} +9 -9
- package/core/built/admin/assets/activitypub/{notifications-BmNlXGgp.js → notifications-DZc6XTjG.js} +27 -27
- package/core/built/admin/assets/activitypub/{onboarding-Dmun9jr_.js → onboarding-8vEIwYTH.js} +3 -3
- package/core/built/admin/assets/activitypub/{onboarding-Bqg7fh_L.js → onboarding-DYVqbNmp.js} +2 -2
- package/core/built/admin/assets/activitypub/{preferences--oH19wf9.js → preferences-DDok6F2N.js} +1418 -1390
- package/core/built/admin/assets/activitypub/{profile-DH_tQx2D.js → profile-DjVa2hUk.js} +254 -255
- package/core/built/admin/assets/activitypub/{reply-Cap9PxSH.js → reply-DtXBpHxu.js} +2 -2
- package/core/built/admin/assets/activitypub/routes-Cw302e1c.js +4946 -0
- package/core/built/admin/assets/activitypub/{separator-CAxxu8VV.js → separator-FpRpVDd3.js} +8 -9
- package/core/built/admin/assets/activitypub/settings-yK-puALn.js +314 -0
- package/core/built/admin/assets/activitypub/{site-BYps63oh.js → site-CHw0R2PA.js} +2 -2
- package/core/built/admin/assets/activitypub/{step-1-CKjR2KAm.js → step-1-737bnvxk.js} +7 -7
- package/core/built/admin/assets/activitypub/{step-2-B6PKfOUQ.js → step-2-DBaIsAsM.js} +7 -7
- package/core/built/admin/assets/activitypub/{step-3-C-qBbcUo.js → step-3-BBmy9m9V.js} +23 -23
- package/core/built/admin/assets/activitypub/tabs-LQ2xirdm.js +1101 -0
- package/core/built/admin/assets/activitypub/{topic-filter-DsUOuu0k.js → topic-filter-75Nu0CKj.js} +4 -4
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-CX9snsLs.js → use-activity-pub-queries-CYI2QJMs.js} +58 -58
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-DsJTGDSS.js → use-navigate-with-base-path-B4jZ8hyg.js} +3924 -1403
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-AJi9zkzm.js → use-reply-chain-data-BHmFxc3U.js} +6 -6
- package/core/built/admin/assets/activitypub/users-CSjOwpT9.js +886 -0
- package/core/built/admin/assets/activitypub/{x-DR8AT3-4.js → x-B9ptWCds.js} +2 -2
- package/core/built/admin/assets/add-integration-modal-BwePhq95.js +1 -0
- package/core/built/admin/assets/add-newsletter-modal-Zv0I7Msm.js +1 -0
- package/core/built/admin/assets/add-recommendation-modal-cdLv0wHy.js +1 -0
- package/core/built/admin/assets/analytics-DY8_SaP7.js +1 -0
- package/core/built/admin/assets/announcement-bar-modal-C-2yWwag.js +1 -0
- package/core/built/admin/assets/api-keys-BHKATUqQ.js +1 -0
- package/core/built/admin/assets/{api-keys-BGPzLHzA.js → api-keys-omLA6iYn.js} +1 -1
- package/core/built/admin/assets/{audience-ceV3XVHq.js → audience-wRcSN0jV.js} +1 -1
- package/core/built/admin/assets/automated-emails-CzUa3v4d.js +1 -0
- package/core/built/admin/assets/automations-DupSsSOr.js +1 -0
- package/core/built/admin/assets/automations-hDVcRPjh.js +1 -0
- package/core/built/admin/assets/avatar-flipboard-DiAGgshK.js +1 -0
- package/core/built/admin/assets/badge-CI1Z0xyG.js +1 -0
- package/core/built/admin/assets/bluesky-sharing-B8PC1SBj.js +1 -0
- package/core/built/admin/assets/box-LUuYRT-1.js +1 -0
- package/core/built/admin/assets/brand-icon-CrmbX86T.js +1 -0
- package/core/built/admin/assets/breadcrumb-DDDpzLyo.js +1 -0
- package/core/built/admin/assets/button-D414TI3B.js +1 -0
- package/core/built/admin/assets/calendar-Cp_opo3i.js +1 -0
- package/core/built/admin/assets/card-C2dfd5u0.js +1 -0
- package/core/built/admin/assets/chart-B_UNLXse.js +63 -0
- package/core/built/admin/assets/chart-helpers-Czu_9QpJ.js +1 -0
- package/core/built/admin/assets/checkbox-CFFqf0Nh.js +1 -0
- package/core/built/admin/assets/{chunk-KS7C4IRE-DCsL4i4D.js → chunk-KS7C4IRE-DhOcHQOU.js} +1 -1
- package/core/built/admin/assets/{chunk.254.035b85ec456ebbd7336b.js → chunk.201.6961b57ed7a281ac193e.js} +165 -122
- package/core/built/admin/assets/chunk.524.0b850e72ec49a0fa3882.js +25 -0
- package/core/built/admin/assets/chunk.582.db2ae9e968256e8d58ac.js +27 -0
- package/core/built/admin/assets/{chunk.901.4ccc639821020230bcca.js → chunk.972.4b8c97f93d66db15e751.js} +10625 -10088
- package/core/built/admin/assets/clean-tracked-url-dkN05vOf.js +1 -0
- package/core/built/admin/assets/code-editor-view-Bd_nnHKk.js +1 -0
- package/core/built/admin/assets/code-editor-view-BeU3Yf9M.js +1 -0
- package/core/built/admin/assets/color-picker-Bzm1V7qg.js +3 -0
- package/core/built/admin/assets/color-picker-field-DP0moHz9.js +1 -0
- package/core/built/admin/assets/combobox-6_ruuTuj.js +1 -0
- package/core/built/admin/assets/command-B5wfm6pd.js +1 -0
- package/core/built/admin/assets/comments-BB26dUSl.js +1 -0
- package/core/built/admin/assets/components-CwL6a6As-CCRaoCeP.js +1 -0
- package/core/built/admin/assets/{config-kSHvwdTG.js → config-BPljH6wF.js} +1 -1
- package/core/built/admin/assets/confirmation-context-znVJD4pX.js +1 -0
- package/core/built/admin/assets/container-CHHif8km.js +1 -0
- package/core/built/admin/assets/content-api-modal-DOHwl0yZ.js +1 -0
- package/core/built/admin/assets/context-menu-BpY46Dlb.js +1 -0
- package/core/built/admin/assets/copy-field-DRBx6Ady.js +1 -0
- package/core/built/admin/assets/create-ghost-browse-value-source-eIXo5Qws.js +1 -0
- package/core/built/admin/assets/{custom-field-type-option-BAuW0F-E.js → custom-field-type-option-DrSlETOI.js} +1 -1
- package/core/built/admin/assets/custom-integration-modal-Dgo425Ec.js +1 -0
- package/core/built/admin/assets/data-list-DM8yqpXi.js +1 -0
- package/core/built/admin/assets/date-range-select-DdC23c13.js +1 -0
- package/core/built/admin/assets/design-and-theme-modal-CbSu9IT4.js +2 -0
- package/core/built/admin/assets/detail-page-CN4NdhpV.js +1 -0
- package/core/built/admin/assets/dirty-confirm-dialog-BT_Vq9TD.js +1 -0
- package/core/built/admin/assets/disabled-sources-indicator-C5xtW0Q2.js +1 -0
- package/core/built/admin/assets/dist-B40T-RCQ.js +1 -0
- package/core/built/admin/assets/dist-BRQkNYN1.js +11 -0
- package/core/built/admin/assets/dist-Bm-PB47a.js +6 -0
- package/core/built/admin/assets/{dist-B6bJuxL3.js → dist-C2lYC76d.js} +1 -1
- package/core/built/admin/assets/dist-Cm2qbZKL.js +1 -0
- package/core/built/admin/assets/dist-CrlaEoaK.js +1 -0
- package/core/built/admin/assets/{dist-BtaTA7Ii.js → dist-D7yMk931.js} +1 -1
- package/core/built/admin/assets/{dist-zwwGt8Yf.js → dist-DNAdeRyr.js} +1 -1
- package/core/built/admin/assets/dist-DS6zpxid.js +1 -0
- package/core/built/admin/assets/dist-DVVKsyPh.js +23 -0
- package/core/built/admin/assets/dist-DxfQlAmn.js +1 -0
- package/core/built/admin/assets/dist-DziNzWI2.js +1 -0
- package/core/built/admin/assets/dist-nmRzULcD.js +1 -0
- package/core/built/admin/assets/domain-BPReCZa8.js +1 -0
- package/core/built/admin/assets/dropzone-B2auMkf2.js +5 -0
- package/core/built/admin/assets/edit-profile-B7XTBzKe.js +1 -0
- package/core/built/admin/assets/editor-BcaC9dqm.js +8 -0
- package/core/built/admin/assets/editor-screen-FuMpItC8.js +27 -0
- package/core/built/admin/assets/email-previews-Bs-JDhIw.js +1 -0
- package/core/built/admin/assets/email-sending-status-context-C76KYL1V.js +1 -0
- package/core/built/admin/assets/email-sending-status-provider-9d81o1C2.js +1 -0
- package/core/built/admin/assets/{emails-vFMk4yYl.js → emails-CgvIIz3q.js} +1 -1
- package/core/built/admin/assets/embed-signup-form-modal-CbVbMsxl.js +8 -0
- package/core/built/admin/assets/empty-indicator-CSQts7GV.js +1 -0
- package/core/built/admin/assets/esm--rhhUGIG.js +2 -0
- package/core/built/admin/assets/explore-DbSXFTJN.js +1 -0
- package/core/built/admin/assets/feature-flag-overrides-context-CrcQKm9Z.js +1 -0
- package/core/built/admin/assets/feature-image-placeholder-DFXA4vfJ.js +1 -0
- package/core/built/admin/assets/feed-W7RlF-Gp.js +1 -0
- package/core/built/admin/assets/feedback-BTPBQLT5.js +1 -0
- package/core/built/admin/assets/field-BXEh3ptU.js +1 -0
- package/core/built/admin/assets/filter-sources-DHK2IoCk.js +1 -0
- package/core/built/admin/assets/filters-0SYNTqyQ.js +1 -0
- package/core/built/admin/assets/filters-DTtZKQyq.js +1 -0
- package/core/built/admin/assets/first-promoter-modal-DcoN_OXu.js +1 -0
- package/core/built/admin/assets/focus-koenig-editor-on-bottom-click-CkFA8EkI.js +1 -0
- package/core/built/admin/assets/framework-provider-DB-svAju.js +4 -0
- package/core/built/admin/assets/{ghost-b4e8a403baba61905cd7560e30b9732d.js → ghost-25495154132af7305cb7b646fd83f48f.js} +580 -523
- package/core/built/admin/assets/gift-link-modal-BX-Q1TOk.js +1 -0
- package/core/built/admin/assets/{gift-links-CfLSnst2.js → gift-links-D8gl_yJS.js} +1 -1
- package/core/built/admin/assets/global-data-context-3MItMry2.js +1 -0
- package/core/built/admin/assets/grid-BEUIDQX7.js +1 -0
- package/core/built/admin/assets/growth-G6PLO4aF.js +1 -0
- package/core/built/admin/assets/growth-tkD-fBOY.js +3 -0
- package/core/built/admin/assets/heading-ih-fOVqF.js +1 -0
- package/core/built/admin/assets/history-modal-Ca-gStoq.js +1 -0
- package/core/built/admin/assets/hooks-DYfTEQLk.js +2 -0
- package/core/built/admin/assets/html-field-B3CrKV9Y.js +1 -0
- package/core/built/admin/assets/iframe-buffering-Bq1el-gw.js +1 -0
- package/core/built/admin/assets/images-H-BIm8OQ.js +1 -0
- package/core/built/admin/assets/{inbox-gJHG7_xd.js → inbox-DBbDVMPz.js} +35 -35
- package/core/built/admin/assets/index-DOF2jDq0.js +4 -0
- package/core/built/admin/assets/index-JrrNchW1.css +2 -0
- package/core/built/admin/assets/index.es-Ct5XQNSj.js +1 -0
- package/core/built/admin/assets/input-group-CvH-3d3F.js +1 -0
- package/core/built/admin/assets/input-surface-CL23Mlh8.js +1 -0
- package/core/built/admin/assets/integration-header-C7GXGis_.js +1 -0
- package/core/built/admin/assets/{integrations-B4kuRBFY.js → integrations-DnJrZnHv.js} +1 -1
- package/core/built/admin/assets/invite-user-modal-EJ2_6RpV.js +1 -0
- package/core/built/admin/assets/isPlainObject-BzzgUf1E.js +1 -0
- package/core/built/admin/assets/jsx-runtime-BlNNh7jY.js +1 -0
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +3 -3
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +1 -1
- package/core/built/admin/assets/{koenig-lexical-CGXb0F8o.js → koenig-lexical-Dkwee5FG.js} +1 -1
- package/core/built/admin/assets/koenig-loader-BzXCXHoA.js +2 -0
- package/core/built/admin/assets/kpi-card-iCDUTgOR.js +1 -0
- package/core/built/admin/assets/kpi-card-jTnpLKGr.js +1 -0
- package/core/built/admin/assets/kpi-helpers-Criu0YAf.js +1 -0
- package/core/built/admin/assets/kpi-tabs-DbOmmyOo.js +1 -0
- package/core/built/admin/assets/label-Du0yqMqL.js +1 -0
- package/core/built/admin/assets/label-picker-Bq1XXr1D.js +1 -0
- package/core/built/admin/assets/labels-0x2NfLtC.js +1 -0
- package/core/built/admin/assets/layout-Ckwzsnsu.js +1 -0
- package/core/built/admin/assets/lib-CCz2mjm8.js +2 -0
- package/core/built/admin/assets/link-helpers-o9GgBTni.js +1 -0
- package/core/built/admin/assets/links-Ctujreuh.js +1 -0
- package/core/built/admin/assets/list-page-CH_wnDC3.js +1 -0
- package/core/built/admin/assets/luxon-BXCsmep3.js +1 -0
- package/core/built/admin/assets/member-activity-CsAh6MxK.js +1 -0
- package/core/built/admin/assets/member-activity-feed-0ytsQbtY.js +1 -0
- package/core/built/admin/assets/member-custom-fields-CTFGnnYv.js +1 -0
- package/core/built/admin/assets/member-detail-QU3vB1ML.js +1 -0
- package/core/built/admin/assets/members-CtMVO_AB.js +4 -0
- package/core/built/admin/assets/modal-page-8Ipfl51B.js +1 -0
- package/core/built/admin/assets/moderation-B8VtA-W0.js +1 -0
- package/core/built/admin/assets/multi-select-combobox-_9wEYmGv.js +1 -0
- package/core/built/admin/assets/navigation-modal-CGcjJvkc.js +1 -0
- package/core/built/admin/assets/newsletter-BpHjjqmq.js +1 -0
- package/core/built/admin/assets/newsletter-detail-modal-DzTbGOyo.js +1 -0
- package/core/built/admin/assets/newsletter-emails-BMKH4Osp.js +1 -0
- package/core/built/admin/assets/newsletters-BxC84_cL.js +1 -0
- package/core/built/admin/assets/{newsletters-Rq1M3GD-.js → newsletters-Dz77m__5.js} +1 -1
- package/core/built/admin/assets/note-BPtEzzZS.js +1 -0
- package/core/built/admin/assets/notifications-ng3ulEdp.js +1 -0
- package/core/built/admin/assets/{nql-BLpCn7qX.js → nql-DnDc7UuU.js} +1 -1
- package/core/built/admin/assets/nql-lang-CeTB_Bhv.js +19 -0
- package/core/built/admin/assets/{offers--e2nGvkW.js → offers-ByWSK0rR.js} +1 -1
- package/core/built/admin/assets/offers-container-modal-CwqnRa3T.js +1 -0
- package/core/built/admin/assets/onboarding-B4hfBi9a.js +1 -0
- package/core/built/admin/assets/onboarding-DV_XbHts.js +1 -0
- package/core/built/admin/assets/onboarding-route-CplZzd7F.js +1 -0
- package/core/built/admin/assets/overview-B0yD9OoX.js +1 -0
- package/core/built/admin/assets/overview-C4eJzQqi.js +1 -0
- package/core/built/admin/assets/page-header-CdCpekG9.js +1 -0
- package/core/built/admin/assets/pagemenu-CKQD9hoP.js +1 -0
- package/core/built/admin/assets/{pages-CjDY2CBI.js → pages-DZ_YGB1D.js} +1 -1
- package/core/built/admin/assets/pages-route-CKsnxIvw.js +1 -0
- package/core/built/admin/assets/papaparse.min-BlhnCUXn.js +10 -0
- package/core/built/admin/assets/pintura-modal-C5jzeyGk.js +1 -0
- package/core/built/admin/assets/portal-frame-DYo0bh0E.js +1 -0
- package/core/built/admin/assets/portal-modal-C0d8xjKa.js +1 -0
- package/core/built/admin/assets/post-analytics-C5C7IyAm.js +1 -0
- package/core/built/admin/assets/post-analytics-context-bt2YTBAC.js +1 -0
- package/core/built/admin/assets/post-analytics-header-DKWHwoK2.js +1 -0
- package/core/built/admin/assets/post-analytics-provider-BqCPPxmW.js +1 -0
- package/core/built/admin/assets/post-share-modal-wxmqbAv_.js +1 -0
- package/core/built/admin/assets/posts-list-screen-B978ZO0R.js +2 -0
- package/core/built/admin/assets/posts-route-CDqxKazl.js +1 -0
- package/core/built/admin/assets/{posts-pCPrhQeR.js → posts-tcoO3iRG.js} +1 -1
- package/core/built/admin/assets/preferences-CnejTRc4.js +5 -0
- package/core/built/admin/assets/preview-chrome-C7yZWVLZ.js +1 -0
- package/core/built/admin/assets/preview-modal-CFUxUGHp.js +1 -0
- package/core/built/admin/assets/profile-ClRGiOqA.js +1 -0
- package/core/built/admin/assets/prop-types-6lTeqvom.js +1 -0
- package/core/built/admin/assets/radio-group-CTmLo0h9.js +1 -0
- package/core/built/admin/assets/react-BXwhMTuc.js +1 -0
- package/core/built/admin/assets/{jsx-runtime-DX3WBWVO.js → react-dom-CMOtJ5MH.js} +2 -2
- package/core/built/admin/assets/{referrers-D8oHPmDB.js → referrers-1R8bPpoV.js} +1 -1
- package/core/built/admin/assets/router-provider-DDZvgS3V.js +1 -0
- package/core/built/admin/assets/select-D_4xWFYv.js +1 -0
- package/core/built/admin/assets/settings-BRl7-7a9.js +1 -0
- package/core/built/admin/assets/settings-BoQcPa-y.js +4 -0
- package/core/built/admin/assets/settings-breadcrumbs-C9Yxl81q.js +1 -0
- package/core/built/admin/assets/{dist-B3keLvjj.js → shade-scope-Cccj-c7I-D0XwkdKQ.js} +5 -3
- package/core/built/admin/assets/share-modal-DBqZobuR.js +1 -0
- package/core/built/admin/assets/simple-pagination-D5t_ox6x.js +1 -0
- package/core/built/admin/assets/skeleton-CPcTiTSX.js +1 -0
- package/core/built/admin/assets/slack-modal-BF9ex8cd.js +1 -0
- package/core/built/admin/assets/sort-button-C0EXGjnS.js +1 -0
- package/core/built/admin/assets/source-icon-BzzftCQ2.js +1 -0
- package/core/built/admin/assets/{stats-D9PDLS3x.js → stats-Cvp8Ep5m.js} +1 -1
- package/core/built/admin/assets/stats-view-CzpGoHzF.js +1 -0
- package/core/built/admin/assets/step-1-CBUYUPPF.js +1 -0
- package/core/built/admin/assets/step-2-CEIXUwQa.js +1 -0
- package/core/built/admin/assets/step-3-C1HA5i1N.js +2 -0
- package/core/built/admin/assets/stripe-button-DMFsLs80.js +1 -0
- package/core/built/admin/assets/stripe-connect-modal-CEvxCUTv.js +1 -0
- package/core/built/admin/assets/switch-DoOJF2yg.js +1 -0
- package/core/built/admin/assets/table-BDYbUHJz.js +1 -0
- package/core/built/admin/assets/tabs-BZyz4ZCH.js +1 -0
- package/core/built/admin/assets/tag-detail-CFzaz_9E.js +2 -0
- package/core/built/admin/assets/tag-picker-BKUCZuRc.js +1 -0
- package/core/built/admin/assets/tags-Bs1FiD7m.js +1 -0
- package/core/built/admin/assets/{tags-ChfdwJyS.js → tags-NwZ7BPK6.js} +1 -1
- package/core/built/admin/assets/testimonials-modal-CVm0_7E-.js +1 -0
- package/core/built/admin/assets/text-BLI0C8Mc.js +1 -0
- package/core/built/admin/assets/textarea-C5qolByg.js +1 -0
- package/core/built/admin/assets/themes-DtcEFQWm.js +1 -0
- package/core/built/admin/assets/tier-detail-modal-Cmwzi-e7.js +1 -0
- package/core/built/admin/assets/{tiers-BCpIOGQr.js → tiers-6mPzCXlM.js} +1 -1
- package/core/built/admin/assets/toggle-group-BTL1QsWY.js +1 -0
- package/core/built/admin/assets/topic-filter-BMjhquv7.js +1 -0
- package/core/built/admin/assets/transistor-modal-hMv53jF8.js +1 -0
- package/core/built/admin/assets/trend-badge-1w_HEzkG.js +1 -0
- package/core/built/admin/assets/unsplash-modal-jzC8lEB2.js +1 -0
- package/core/built/admin/assets/use-analytics-data-B3lGOxsC.js +1 -0
- package/core/built/admin/assets/use-availability-DnKqOyqd.js +1 -0
- package/core/built/admin/assets/{use-check-theme-limit-error-DRUjK4YM.js → use-check-theme-limit-error-C1tc2P4N.js} +2 -2
- package/core/built/admin/assets/use-email-sending-status-DNMtL5B9.js +1 -0
- package/core/built/admin/assets/use-filter-params-DU-aiaTb.js +1 -0
- package/core/built/admin/assets/use-filterable-api-CxCrnPxG.js +1 -0
- package/core/built/admin/assets/use-form-DJKZJhQh.js +1 -0
- package/core/built/admin/assets/use-growth-stats-E13rMQUE.js +1 -0
- package/core/built/admin/assets/use-host-limits-mpTkZIq8.js +1 -0
- package/core/built/admin/assets/use-limiter-DlL7au90.js +19 -0
- package/core/built/admin/assets/use-navigate-with-base-path-BzgNwMAx.js +1 -0
- package/core/built/admin/assets/use-pintura-config-CtEV1JQY.js +1 -0
- package/core/built/admin/assets/use-pintura-editor-CaxE64kD.js +1 -0
- package/core/built/admin/assets/use-post-referrers-DyPjyBSN.js +1 -0
- package/core/built/admin/assets/use-query-params-DlOHCo-R.js +1 -0
- package/core/built/admin/assets/use-reply-chain-data-BST2OgCM.js +1 -0
- package/core/built/admin/assets/use-router-history-entry-CKx9LhqD.js +1 -0
- package/core/built/admin/assets/use-sending-eta-DR9ueMH8.js +1 -0
- package/core/built/admin/assets/use-setting-group-ldtX1Vsk.js +1 -0
- package/core/built/admin/assets/use-settings-navigation-CzGU4sus.js +1 -0
- package/core/built/admin/assets/use-staff-users-DoeXaPsb.js +1 -0
- package/core/built/admin/assets/use-tinybird-query-BaBNCaj0.js +1 -0
- package/core/built/admin/assets/use-tinybird-token-CnZ19NDf.js +1 -0
- package/core/built/admin/assets/use-unsaved-changes-guard-CKVPWz_F.js +1 -0
- package/core/built/admin/assets/use-upgrade-route-CVjDlNSs.js +1 -0
- package/core/built/admin/assets/{use-url-input-fvp-TpPx.js → use-url-input-C5KHJw79.js} +1 -1
- package/core/built/admin/assets/user-detail-modal-Dm0KfPeR.js +1 -0
- package/core/built/admin/assets/{users-DVNWrqg9.js → users-C60_hpn6.js} +1 -1
- package/core/built/admin/assets/{validator-Cr0sMKuW.js → validator-DlFQP70j.js} +1 -1
- package/core/built/admin/assets/{vendor-2dd263291938d407802568d3357ec69e.js → vendor-97e91ff8dd1457c668f9ef103ee1a77b.js} +2748 -2977
- package/core/built/admin/assets/virtual-list-tAuPUICw.js +1 -0
- package/core/built/admin/assets/web-BQlKcW2x.js +2 -0
- package/core/built/admin/assets/web-NTT5DkEz.js +1 -0
- package/core/built/admin/assets/zapier-modal-DsHG9Oev.js +1 -0
- package/core/built/admin/index.html +35 -34
- package/core/cli/command.js +17 -2
- package/core/frontend/apps/private-blogging/index.js +2 -2
- package/core/frontend/apps/private-blogging/lib/middleware.js +1 -1
- package/core/frontend/apps/private-blogging/lib/router.js +1 -1
- package/core/frontend/helpers/cancel_link.js +3 -3
- package/core/frontend/helpers/content.js +2 -2
- package/core/frontend/helpers/content_api_url.js +1 -1
- package/core/frontend/helpers/date.js +1 -1
- package/core/frontend/helpers/foreach.js +5 -5
- package/core/frontend/helpers/get.js +7 -4
- package/core/frontend/helpers/ghost_head.js +2 -2
- package/core/frontend/helpers/has.js +1 -3
- package/core/frontend/helpers/link.js +7 -7
- package/core/frontend/helpers/link_class.js +2 -2
- package/core/frontend/helpers/navigation.js +1 -2
- package/core/frontend/helpers/recommendations.js +5 -6
- package/core/frontend/helpers/tiers.js +1 -1
- package/core/frontend/helpers/total_members.js +1 -1
- package/core/frontend/helpers/total_paid_members.js +1 -1
- package/core/frontend/meta/asset-url.js +1 -16
- package/core/frontend/meta/author-url.js +1 -1
- package/core/frontend/meta/modified-date.js +1 -1
- package/core/frontend/meta/published-date.js +1 -1
- package/core/frontend/meta/schema.js +3 -8
- package/core/frontend/meta/structured-data.js +1 -2
- package/core/frontend/services/asset-hash/index.js +32 -2
- package/core/frontend/services/assets-minification/minifier.js +1 -1
- package/core/frontend/services/data/entry-lookup.js +1 -1
- package/core/frontend/services/data/fetch-data.js +2 -2
- package/core/frontend/services/rendering/format-response.js +1 -1
- package/core/frontend/services/rendering/renderer.js +3 -0
- package/core/frontend/services/rendering/templates.js +1 -1
- package/core/frontend/services/routing/controllers/static.js +1 -1
- package/core/frontend/services/routing/controllers/unsubscribe.js +2 -1
- package/core/frontend/services/routing/parent-router.js +1 -1
- package/core/frontend/services/routing/registry.js +1 -1
- package/core/frontend/services/rss/generate-feed.js +1 -1
- package/core/frontend/services/sitemap/base-site-map-generator.js +68 -97
- package/core/frontend/services/sitemap/site-map-index-generator.js +16 -21
- package/core/frontend/services/sitemap/site-map-manager.js +82 -43
- package/core/frontend/services/sitemap/sitemap-xml.js +72 -0
- package/core/frontend/services/theme-engine/active.js +2 -4
- package/core/frontend/services/theme-engine/handlebars/utils.js +8 -8
- package/core/frontend/services/theme-engine/i18n/i18n.js +15 -6
- package/core/frontend/services/theme-engine/i18next/theme-i18n.js +1 -1
- package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +1 -1
- package/core/frontend/services/theme-engine/preview.js +1 -1
- package/core/frontend/utils/member-count.js +2 -2
- package/core/frontend/web/middleware/llms-discovery.js +34 -43
- package/core/frontend/web/routers/serve-public-file.js +1 -1
- package/core/server/adapters/route-settings/S3RouteSettingsStore.js +1 -1
- package/core/server/adapters/scheduling/README.md +4 -0
- package/core/server/adapters/scheduling/get-scheduler-idempotency-key.js +21 -0
- package/core/server/adapters/storage/LocalFilesStorage.js +12 -2
- package/core/server/adapters/storage/LocalStorageBase.js +15 -1
- package/core/server/api/endpoints/actions.js +2 -1
- package/core/server/api/endpoints/automated-emails.js +11 -4
- package/core/server/api/endpoints/automations.js +77 -49
- package/core/server/api/endpoints/db.js +1 -1
- package/core/server/api/endpoints/emails.js +11 -6
- package/core/server/api/endpoints/index.js +1 -1
- package/core/server/api/endpoints/invites.js +2 -1
- package/core/server/api/endpoints/labels.js +6 -2
- package/core/server/api/endpoints/mail.js +1 -1
- package/core/server/api/endpoints/member-metafields.js +2 -2
- package/core/server/api/endpoints/member-signin-urls.js +1 -1
- package/core/server/api/endpoints/members.js +23 -7
- package/core/server/api/endpoints/oembed.js +1 -1
- package/core/server/api/endpoints/pages.js +2 -6
- package/core/server/api/endpoints/posts.js +4 -12
- package/core/server/api/endpoints/settings.js +2 -2
- package/core/server/api/endpoints/snippets.js +2 -1
- package/core/server/api/endpoints/tags.js +6 -2
- package/core/server/api/endpoints/themes.js +5 -5
- package/core/server/api/endpoints/users.js +2 -6
- package/core/server/api/endpoints/utils/api-filter-utils.js +62 -3
- package/core/server/api/endpoints/utils/serializers/input/pages.js +2 -2
- package/core/server/api/endpoints/utils/serializers/input/posts.js +2 -2
- package/core/server/api/endpoints/utils/serializers/input/tags.js +1 -1
- package/core/server/api/endpoints/utils/serializers/input/utils/slug-filter-order.js +4 -4
- package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +8 -5
- package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +1 -1
- package/core/server/api/endpoints/utils/serializers/output/pages.js +4 -4
- package/core/server/api/endpoints/utils/serializers/output/posts.js +4 -4
- package/core/server/api/endpoints/utils/serializers/output/search-index.js +11 -11
- package/core/server/api/endpoints/utils/serializers/output/settings.js +1 -1
- package/core/server/api/endpoints/utils/serializers/output/utils/clean.js +2 -0
- package/core/server/api/endpoints/utils/serializers/output/utils/extra-attrs.js +6 -3
- package/core/server/api/endpoints/utils/validators/input/automated_emails.js +23 -33
- package/core/server/api/endpoints/utils/validators/input/settings.js +18 -4
- package/core/server/data/exporter/exporter.js +3 -3
- package/core/server/data/exporter/table-lists.js +4 -5
- package/core/server/data/importer/handlers/image.js +1 -2
- package/core/server/data/importer/handlers/json.js +1 -3
- package/core/server/data/importer/handlers/markdown.js +4 -8
- package/core/server/data/importer/import-manager.js +1 -1
- package/core/server/data/importer/importers/content-file-importer.js +4 -8
- package/core/server/data/importer/importers/data/base.js +10 -10
- package/core/server/data/importer/importers/data/custom-theme-settings-importer.js +1 -1
- package/core/server/data/importer/importers/data/data-importer.js +3 -4
- package/core/server/data/importer/importers/data/posts-importer.js +10 -10
- package/core/server/data/importer/importers/data/products-importer.js +3 -3
- package/core/server/data/importer/importers/data/settings-importer.js +10 -4
- package/core/server/data/importer/importers/data/stripe-prices-importer.js +1 -1
- package/core/server/data/importer/importers/data/stripe-products-importer.js +1 -1
- package/core/server/data/importer/importers/data/tags-importer.js +1 -1
- package/core/server/data/importer/importers/data/users-importer.js +2 -2
- package/core/server/data/importer/importers/json-to-html.js +12 -9
- package/core/server/data/migrations/versions/5.0/2022-05-11-13-12-rename-settings.js +1 -1
- package/core/server/data/migrations/versions/6.64/2026-09-03-15-40-25-add-member-access-to-members-metafields.js +12 -0
- package/core/server/data/migrations/versions/6.64/2026-09-08-11-01-12-add-posts-auto-excerpt-and-reading-time-columns.js +17 -0
- package/core/server/data/migrations/versions/6.64/2026-09-09-13-56-18-add-automation-run-updated-at-indexes.js +6 -0
- package/core/server/data/migrations/versions/6.64/2026-09-09-13-56-18-add-tinybird-syncs-table.js +10 -0
- package/core/server/data/migrations/versions/6.65/2026-09-16-15-35-26-add-members-metafield-change-events.js +17 -0
- package/core/server/data/schema/fixtures/fixture-manager.js +3 -3
- package/core/server/data/schema/index.js +1 -1
- package/core/server/data/schema/schema.js +54 -2
- package/core/server/data/schema/validator.js +96 -123
- package/core/server/data/seeders/importers/automations-importer.js +0 -1
- package/core/server/data/seeders/importers/comments-importer.js +1 -1
- package/core/server/data/seeders/importers/email-recipients-importer.js +3 -3
- package/core/server/data/seeders/importers/emails-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 +2 -2
- package/core/server/data/seeders/importers/members-newsletters-importer.js +1 -1
- package/core/server/data/seeders/importers/members-paid-subscription-events-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 +2 -2
- package/core/server/data/seeders/importers/members-subscribe-events-importer.js +2 -2
- package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +1 -1
- package/core/server/data/seeders/utils/blog-info.js +4 -3
- package/core/server/data/seeders/utils/event-generator.js +72 -46
- package/core/server/data/tinybird/datasources/_mv_automation_run_steps.datasource +10 -0
- package/core/server/data/tinybird/datasources/_mv_automation_runs.datasource +10 -0
- package/core/server/data/tinybird/datasources/_mv_pending_automation_runs.datasource +10 -0
- package/core/server/data/tinybird/datasources/automation_run_events.datasource +12 -0
- package/core/server/data/tinybird/datasources/automation_run_step_events.datasource +12 -0
- package/core/server/data/tinybird/endpoints/api_automation_browse_stats.pipe +43 -0
- package/core/server/data/tinybird/fixtures/automation_run_events.ndjson +7 -0
- package/core/server/data/tinybird/fixtures/automation_run_step_events.ndjson +8 -0
- package/core/server/data/tinybird/pipes/mv_automation_run_steps.pipe +13 -0
- package/core/server/data/tinybird/pipes/mv_automation_runs.pipe +15 -0
- package/core/server/data/tinybird/pipes/mv_hits.pipe +25 -20
- package/core/server/data/tinybird/pipes/mv_pending_automation_runs.pipe +7 -0
- package/core/server/data/tinybird/scripts/docker-analytics-manager.js +2 -2
- package/core/server/data/tinybird/tests/api_automation_browse_stats.yaml +18 -0
- package/core/server/ghost-server.js +4 -22
- package/core/server/lib/generate-password.js +54 -0
- package/core/server/lib/image/image-size.js +1 -3
- package/core/server/lib/public-jwk.js +77 -0
- package/core/server/lib/request-external.js +53 -117
- package/core/server/models/base/plugins/actions.js +2 -3
- package/core/server/models/base/plugins/crud.js +1 -2
- package/core/server/models/base/plugins/events.js +4 -4
- package/core/server/models/base/plugins/raw-knex.js +3 -3
- package/core/server/models/base/plugins/sanitize.js +1 -1
- package/core/server/models/benefit.js +1 -1
- package/core/server/models/collection.js +1 -1
- package/core/server/models/comment.js +3 -3
- package/core/server/models/invite.js +2 -5
- package/core/server/models/label.js +3 -6
- package/core/server/models/member.js +7 -10
- package/core/server/models/newsletter.js +1 -1
- package/core/server/models/permission.js +3 -6
- package/core/server/models/post.js +20 -23
- package/core/server/models/product.js +4 -1
- package/core/server/models/relations/authors.js +9 -12
- package/core/server/models/role.js +2 -5
- package/core/server/models/settings.js +3 -3
- package/core/server/models/tag.js +2 -5
- package/core/server/models/user.js +19 -19
- package/core/server/models/webhook.js +2 -4
- package/core/server/notify.js +2 -2
- package/core/server/services/adapter-manager/base-classes.js +21 -3
- package/core/server/services/adapter-manager/utils.js +6 -1
- package/core/server/services/api-version-compatibility/legacy-api-path-match.js +2 -2
- package/core/server/services/auth/api-key/admin.js +2 -2
- package/core/server/services/auth/api-key/content.js +1 -1
- package/core/server/services/auth/passwordreset.js +1 -1
- package/core/server/services/auth/setup.js +1 -3
- package/core/server/services/automations/README.md +19 -0
- package/core/server/services/automations/automations-api.js +46 -1
- package/core/server/services/automations/poll.js +3 -1
- package/core/server/services/automations/service.js +2 -2
- package/core/server/services/automations/tinybird-automation-stats.js +56 -0
- package/core/server/services/automations/welcome-email-automation-poll.js +199 -293
- package/core/server/services/comments/comments-controller.js +9 -30
- package/core/server/services/comments/comments-service-email-renderer.js +1 -1
- package/core/server/services/comments/comments-service-emails.js +1 -1
- package/core/server/services/comments/comments-service.js +27 -58
- package/core/server/services/comments/comments-stats-service.js +1 -1
- package/core/server/services/content-import/import/media.js +1 -1
- package/core/server/services/content-import/import/staged-file.js +9 -9
- package/core/server/services/content-import/index.js +1 -1
- package/core/server/services/custom-redirects/validation.js +1 -1
- package/core/server/services/email-analytics/email-analytics-service-wrapper.js +38 -84
- package/core/server/services/email-analytics/email-analytics-service.js +19 -3
- package/core/server/services/email-analytics/index.js +44 -23
- package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.js +31 -60
- package/core/server/services/email-rendering/finalize.js +7 -2
- package/core/server/services/email-service/README.md +38 -0
- package/core/server/services/email-service/batch-sending-service.js +13 -14
- package/core/server/services/email-service/email-renderer.js +57 -16
- package/core/server/services/email-service/email-service-wrapper.js +4 -3
- package/core/server/services/email-service/email-service.js +76 -42
- package/core/server/services/email-service/email-templates/partials/feedback-button.hbs +2 -1
- package/core/server/services/email-service/email-templates/partials/styles.hbs +0 -6
- package/core/server/services/email-service/email-templates/template.hbs +1 -1
- package/core/server/services/email-service/jobs/send-email-job.js +12 -0
- package/core/server/services/email-service/mailgun-email-provider.js +7 -2
- package/core/server/services/email-service/sending-service.js +1 -1
- package/core/server/services/email-service/sending-status.js +10 -4
- package/core/server/services/gifts/gift-email-service.js +10 -3
- package/core/server/services/gifts/gift-service.js +12 -3
- package/core/server/services/gifts/index.js +1 -2
- package/core/server/services/gifts/jobs/index.js +12 -24
- package/core/server/services/gifts/jobs/send-gift-reminders-job.js +6 -46
- package/core/server/services/i18n.js +1 -1
- package/core/server/services/identity-tokens/identity-token-service-wrapper.js +3 -4
- package/core/server/services/invitations/accept.js +2 -2
- package/core/server/services/jobs/job-service.js +0 -28
- package/core/server/services/jobs-service/jobs-service.js +5 -0
- package/core/server/services/jobs-service/register-job-handlers.js +17 -1
- package/core/server/services/lib/mailgun-client.js +16 -1
- package/core/server/services/lib/mailgun-recipient-message-id.js +49 -0
- package/core/server/services/limits.js +18 -2
- package/core/server/services/mail/ghost-mailer.js +1 -1
- package/core/server/services/member-attribution/member-attribution-service.js +1 -1
- package/core/server/services/member-attribution/referrer-translator.js +1 -1
- package/core/server/services/member-welcome-emails/service.js +1 -1
- package/core/server/services/members/account-service.js +3 -3
- package/core/server/services/members/api.js +1 -1
- package/core/server/services/members/import-export/import/importer.js +25 -16
- package/core/server/services/members/import-export/import/spool.js +11 -15
- package/core/server/services/members/import-export/index.js +11 -8
- package/core/server/services/members/jobs/index.js +1 -1
- package/core/server/services/members/jobs/members-import-job.js +18 -0
- package/core/server/services/members/member-avatar.js +18 -0
- package/core/server/services/members/members-api/controllers/member-controller.js +2 -2
- package/core/server/services/members/members-api/controllers/router-controller.js +7 -2
- package/core/server/services/members/members-api/controllers/well-known-controller.js +2 -1
- package/core/server/services/members/members-api/members-api.js +4 -4
- package/core/server/services/members/members-api/repositories/event-repository.js +40 -1
- package/core/server/services/members/members-api/repositories/member-repository.js +55 -17
- package/core/server/services/members/members-api/repositories/product-repository.js +1 -1
- package/core/server/services/members/members-api/services/member-bread-service.js +19 -19
- package/core/server/services/members/members-api/services/token-service.js +11 -12
- package/core/server/services/members/middleware.js +9 -2
- package/core/server/services/members/request-integrity-token-provider.js +2 -1
- package/core/server/services/members/service.js +7 -2
- package/core/server/services/members/stats/members-stats.js +2 -2
- package/core/server/services/members-events/event-storage.js +2 -2
- package/core/server/services/members-metafields/access.js +31 -20
- package/core/server/services/members-metafields/actions.js +24 -2
- package/core/server/services/members-metafields/bindings-service.js +5 -5
- package/core/server/services/members-metafields/codec.js +9 -2
- package/core/server/services/members-metafields/definitions-service.js +57 -52
- package/core/server/services/members-metafields/index.js +3 -2
- package/core/server/services/members-metafields/models.js +2 -0
- package/core/server/services/members-metafields/queries.js +45 -11
- package/core/server/services/members-metafields/schema.js +51 -1
- package/core/server/services/members-metafields/serializers.js +1 -0
- package/core/server/services/members-metafields/values-service.js +132 -21
- package/core/server/services/mentions/mention-discovery-service.js +1 -1
- package/core/server/services/mentions/mention-sending-service.js +3 -3
- package/core/server/services/mentions/mention.js +4 -5
- package/core/server/services/mentions/mentions-api.js +4 -1
- package/core/server/services/mentions-jobs/job-service.js +0 -28
- package/core/server/services/milestones/milestones-service.js +1 -1
- package/core/server/services/newsletters/newsletters-service.js +1 -1
- package/core/server/services/notifications/notifications.js +3 -3
- package/core/server/services/oembed/oembed-service.js +115 -14
- package/core/server/services/permissions/can-this.js +1 -2
- package/core/server/services/post-scheduling/post-scheduling.js +8 -1
- package/core/server/services/posts/post-scheduling.js +27 -0
- package/core/server/services/settings/settings-bread-service.js +3 -3
- package/core/server/services/settings/settings-utils.js +1 -1
- package/core/server/services/settings-helpers/settings-helpers.js +1 -1
- package/core/server/services/staff/staff-service-emails.js +14 -10
- package/core/server/services/stats/posts-stats-service.js +10 -10
- package/core/server/services/stats/referrers-stats-service.js +1 -1
- package/core/server/services/stats/stats-service.js +12 -3
- package/core/server/services/stats/subscription-stats-service.js +3 -3
- package/core/server/services/stats/utils/tinybird.js +8 -1
- package/core/server/services/stripe/stripe-api.js +3 -3
- package/core/server/services/stripe/stripe-migrations.js +6 -6
- package/core/server/services/themes/storage.js +21 -26
- package/core/server/services/themes/theme-storage.js +2 -2
- package/core/server/services/tier-checkout-config/service.js +17 -1
- package/core/server/services/tiers/tier.js +15 -15
- package/core/server/services/tinybird/tinybird-service.js +1 -0
- package/core/server/services/tinybird-sync/get-ingest-config.js +39 -0
- package/core/server/services/tinybird-sync/index.js +31 -0
- package/core/server/services/tinybird-sync/sync-table-to-tinybird.js +149 -0
- package/core/server/services/tinybird-sync/tinybird-sync-service.js +67 -0
- package/core/server/services/update-check/update-check-service.js +3 -3
- package/core/server/services/webhooks/serialize.js +1 -1
- package/core/server/web/api/app.js +0 -5
- package/core/server/web/api/endpoints/admin/routes.js +33 -34
- package/core/server/web/api/middleware/upload.js +29 -2
- package/core/server/web/parent/middleware/index.js +1 -1
- package/core/server/web/parent/middleware/log-request.js +5 -0
- package/core/server/web/parent/middleware/queue-request.js +104 -59
- package/core/server/web/shared/middleware/api/spam-prevention.js +2 -2
- package/core/server/web/well-known.js +12 -16
- package/core/shared/config/defaults.json +7 -3
- package/core/shared/custom-theme-settings-cache/custom-theme-settings-service.js +1 -1
- package/core/shared/{flush-logs.js → flush.js} +7 -3
- package/core/shared/labs.js +5 -2
- package/core/shared/settings-cache/cache-manager.js +1 -1
- package/core/shared/timing-safe-string-equal.js +26 -0
- package/nodemon.json +1 -1
- package/package.json +47 -48
- package/patches/@elastic__elasticsearch@8.19.2.patch +67 -0
- package/patches/juice@11.1.1.patch +46 -0
- package/pnpm-lock.yaml +571 -2107
- package/pnpm-workspace.yaml +38 -28
- package/scripts/prune.mts +70 -3
- package/tsconfig.json +1 -1
- package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
- package/core/built/admin/assets/Combination-B0l4MKVh.js +0 -41
- package/core/built/admin/assets/RadialBarChart-JAKoS4KT.js +0 -1
- package/core/built/admin/assets/_baseAssignValue-C_vooEQc.js +0 -1
- package/core/built/admin/assets/about-C1C3s5-g.js +0 -1
- package/core/built/admin/assets/accordion-CxGsDKwa.js +0 -1
- package/core/built/admin/assets/account-migration-CbUhW6gk.js +0 -1
- package/core/built/admin/assets/action-list-C4v0-du8.js +0 -1
- package/core/built/admin/assets/activitypub/avatar-DVJF5bxP.js +0 -261
- package/core/built/admin/assets/activitypub/layout-BL4_jtuV.js +0 -1
- package/core/built/admin/assets/activitypub/routes-DdyY9uFF.js +0 -7181
- package/core/built/admin/assets/activitypub/settings-B6EEcVkW.js +0 -315
- package/core/built/admin/assets/activitypub/tabs-DLhZtVde.js +0 -1083
- package/core/built/admin/assets/activitypub/users-inweyKL5.js +0 -1499
- package/core/built/admin/assets/add-integration-modal-BT_onDJy.js +0 -1
- package/core/built/admin/assets/add-newsletter-modal-Cx1kQpiY.js +0 -1
- package/core/built/admin/assets/add-recommendation-modal-B5nvAhvr.js +0 -1
- package/core/built/admin/assets/analytics-DjoJWPI7.js +0 -1
- package/core/built/admin/assets/announcement-bar-modal-Dwd0EGFP.js +0 -1
- package/core/built/admin/assets/api-keys-BoeacM-s.js +0 -1
- package/core/built/admin/assets/automated-emails-BLesE41L.js +0 -1
- package/core/built/admin/assets/automations-BN4u3GR8.js +0 -1
- package/core/built/admin/assets/automations-C-ZTUwW3.js +0 -1
- package/core/built/admin/assets/avatar-flipboard-C6Kj3Awu.js +0 -1
- package/core/built/admin/assets/bluesky-sharing-vzh-oPXL.js +0 -1
- package/core/built/admin/assets/box-CdfQAP_F.js +0 -1
- package/core/built/admin/assets/brand-icon-CrIGOA3Z.js +0 -1
- package/core/built/admin/assets/breadcrumb-CaLk2b7D.js +0 -1
- package/core/built/admin/assets/build-CsiH26uS.js +0 -1
- package/core/built/admin/assets/button-Dvcv1QSR.js +0 -1
- package/core/built/admin/assets/calendar-Bl9RLcZX.js +0 -1
- package/core/built/admin/assets/card--VNbfgo3.js +0 -1
- package/core/built/admin/assets/chart-BrhA41Zi.js +0 -63
- package/core/built/admin/assets/chart-helpers-FHywU0pj.js +0 -1
- package/core/built/admin/assets/checkbox-BtayFtjg.js +0 -1
- package/core/built/admin/assets/chunk.524.e6975095fccdf22d90f8.js +0 -32
- package/core/built/admin/assets/chunk.582.98b485f9b2802f540897.js +0 -34
- package/core/built/admin/assets/code-editor-view-C3ZfoF1X.js +0 -1
- package/core/built/admin/assets/code-editor-view-CAyRWy1s.js +0 -1
- package/core/built/admin/assets/color-picker-G4kGR7rp.js +0 -3
- package/core/built/admin/assets/color-picker-field-DQFVTNnT.js +0 -1
- package/core/built/admin/assets/combobox-BnYzgEB4.js +0 -1
- package/core/built/admin/assets/command-C_vyTikI.js +0 -1
- package/core/built/admin/assets/comments-aBrxfnZf.js +0 -1
- package/core/built/admin/assets/components-CwL6a6As-B0E0-NBJ.js +0 -1
- package/core/built/admin/assets/confirmation-context-DwXX_Y5h.js +0 -1
- package/core/built/admin/assets/container-BuQG1wuP.js +0 -1
- package/core/built/admin/assets/content-api-modal-D2G0nJP6.js +0 -1
- package/core/built/admin/assets/context-menu-DOVB6yaz.js +0 -1
- package/core/built/admin/assets/copy-field-DCJwh9qf.js +0 -1
- package/core/built/admin/assets/create-ghost-browse-value-source-5C53jJaX.js +0 -1
- package/core/built/admin/assets/custom-integration-modal-AbJGVyKc.js +0 -1
- package/core/built/admin/assets/data-list-CA2jYGPq.js +0 -1
- package/core/built/admin/assets/date-range-select-BY3K-ukj.js +0 -1
- package/core/built/admin/assets/design-and-theme-modal-BvEy4_pC.js +0 -2
- package/core/built/admin/assets/detail-page-Dnv-CdR1.js +0 -1
- package/core/built/admin/assets/dirty-confirm-dialog-DVPuGz3U.js +0 -1
- package/core/built/admin/assets/disabled-sources-indicator-Cy7Zp4c8.js +0 -1
- package/core/built/admin/assets/dist-4m6pHdc0.js +0 -23
- package/core/built/admin/assets/dist-8YJUlf3B.js +0 -1
- package/core/built/admin/assets/dist-CZgIBXQN.js +0 -1
- package/core/built/admin/assets/dist-CiHx7vA5.js +0 -6
- package/core/built/admin/assets/dist-DIC8yz5C.js +0 -1
- package/core/built/admin/assets/dist-Dcsslyo72.js +0 -1
- package/core/built/admin/assets/dist-Dgt2cr6a.js +0 -1
- package/core/built/admin/assets/dist-ECAUrdGc.js +0 -1
- package/core/built/admin/assets/dist-JLOy8o0Q.js +0 -1
- package/core/built/admin/assets/dist-Ndy-PuGN.js +0 -1
- package/core/built/admin/assets/dist-Z97pCNqS.js +0 -11
- package/core/built/admin/assets/domain-Dl61QGuk.js +0 -1
- package/core/built/admin/assets/dropzone-Dtz5Rmjt.js +0 -5
- package/core/built/admin/assets/edit-profile-DNJSMDwm.js +0 -1
- package/core/built/admin/assets/editor-DbAen9zf.js +0 -8
- package/core/built/admin/assets/editor-screen-BFWThIai.js +0 -26
- package/core/built/admin/assets/email-sending-status-context-CWDOD1FN.js +0 -1
- package/core/built/admin/assets/email-sending-status-provider-DCPkDICt.js +0 -1
- package/core/built/admin/assets/embed-signup-form-modal-DGqsORxS.js +0 -8
- package/core/built/admin/assets/empty-indicator-D9QdpuNX.js +0 -1
- package/core/built/admin/assets/en-B1jX3WMs.js +0 -1
- package/core/built/admin/assets/esm-CXo5SEPy.js +0 -2
- package/core/built/admin/assets/explore-nnRr1Fja.js +0 -1
- package/core/built/admin/assets/feature-flag-overrides-context-DQjdJFAk.js +0 -1
- package/core/built/admin/assets/feature-image-placeholder-BrIHmPs8.js +0 -1
- package/core/built/admin/assets/feed-BNUcNu-W.js +0 -1
- package/core/built/admin/assets/feedback-DJ4Zb9rZ.js +0 -1
- package/core/built/admin/assets/field-C93_Mg6j.js +0 -1
- package/core/built/admin/assets/filter-bar-Da1qxybu.js +0 -1
- package/core/built/admin/assets/filter-sources-CGJb4C5r.js +0 -1
- package/core/built/admin/assets/filters--kKP-EC8.js +0 -1
- package/core/built/admin/assets/filters-DxA_a4FP.js +0 -1
- package/core/built/admin/assets/first-promoter-modal-BYDtrz2S.js +0 -1
- package/core/built/admin/assets/focus-koenig-editor-on-bottom-click-BbSnGOtK.js +0 -1
- package/core/built/admin/assets/framework-provider-DqI25epG.js +0 -4
- package/core/built/admin/assets/gift-link-modal-B7u5bD4e.js +0 -1
- package/core/built/admin/assets/global-data-context-gAMDH9u1.js +0 -1
- package/core/built/admin/assets/grid-Dj29PY05.js +0 -1
- package/core/built/admin/assets/growth-Cd1uO9d2.js +0 -1
- package/core/built/admin/assets/growth-aG32xfdE.js +0 -3
- package/core/built/admin/assets/heading-Dh5SFVjL.js +0 -1
- package/core/built/admin/assets/history-modal-Df8lW8h-.js +0 -1
- package/core/built/admin/assets/hooks-Cy_-oZ4o.js +0 -2
- package/core/built/admin/assets/html-field-DA4eU7eq.js +0 -1
- package/core/built/admin/assets/iframe-buffering-B2OKJzbz.js +0 -1
- package/core/built/admin/assets/images-KXmyO3Ss.js +0 -1
- package/core/built/admin/assets/index-BHHXtR5C.css +0 -2
- package/core/built/admin/assets/index-CgMCwsxN.js +0 -4
- package/core/built/admin/assets/index.es-CY6-yuw9.js +0 -1
- package/core/built/admin/assets/inline-BWSs_VzR.js +0 -1
- package/core/built/admin/assets/input-group-BE8rM2y1.js +0 -1
- package/core/built/admin/assets/input-surface-BsrIZeSF.js +0 -1
- package/core/built/admin/assets/integration-header-Bm6IDb1A.js +0 -1
- package/core/built/admin/assets/invite-user-modal-B4CuNcx4.js +0 -1
- package/core/built/admin/assets/koenig-loader-BeM5rFPX.js +0 -2
- package/core/built/admin/assets/kpi-card-B21aToe8.js +0 -1
- package/core/built/admin/assets/kpi-card-pz6Wv4Ae.js +0 -1
- package/core/built/admin/assets/kpi-helpers-Dq5jelmP.js +0 -1
- package/core/built/admin/assets/kpi-tabs-DEZHpKUt.js +0 -1
- package/core/built/admin/assets/label-OLCzze8N.js +0 -1
- package/core/built/admin/assets/label-picker-BigOvMPV.js +0 -1
- package/core/built/admin/assets/labels-Dr0SgUQD.js +0 -1
- package/core/built/admin/assets/layout-DUTL8SH5.js +0 -1
- package/core/built/admin/assets/lib-7QPTI0FS.js +0 -1
- package/core/built/admin/assets/limit-service-BhiEvqcP.js +0 -20
- package/core/built/admin/assets/link-helpers-BRAg9SCj.js +0 -1
- package/core/built/admin/assets/links-BDHPTlyj.js +0 -1
- package/core/built/admin/assets/list-page-BucXJ0hi.js +0 -1
- package/core/built/admin/assets/luxon-D1RVjjpq.js +0 -1
- package/core/built/admin/assets/member-custom-fields-TRTHCAz9.js +0 -1
- package/core/built/admin/assets/member-detail-b6dRwc3C.js +0 -1
- package/core/built/admin/assets/members-Czt5lJSc.js +0 -4
- package/core/built/admin/assets/modal-page-xCivTMvI.js +0 -1
- package/core/built/admin/assets/moderation-ZWefD9uH.js +0 -1
- package/core/built/admin/assets/multi-select-combobox-CT13MTo-.js +0 -1
- package/core/built/admin/assets/navigation-modal-C8FEhBK5.js +0 -1
- package/core/built/admin/assets/newsletter-5VYW4RyJ.js +0 -1
- package/core/built/admin/assets/newsletter-detail-modal-ChjC0ZqH.js +0 -1
- package/core/built/admin/assets/newsletter-emails-DZH6I-PY.js +0 -1
- package/core/built/admin/assets/newsletters-DOC9KBcX.js +0 -1
- package/core/built/admin/assets/note-DIV-Pojr.js +0 -1
- package/core/built/admin/assets/notifications-s20-H49V.js +0 -1
- package/core/built/admin/assets/nql-lang-CaWrLesS.js +0 -19
- package/core/built/admin/assets/offers-container-modal-BmG5M5Tv.js +0 -1
- package/core/built/admin/assets/onboarding-CUuy9unR.js +0 -1
- package/core/built/admin/assets/onboarding-pXyct0Jm.js +0 -1
- package/core/built/admin/assets/onboarding-route-CK4pcXoR.js +0 -1
- package/core/built/admin/assets/overview-CaPsciMs.js +0 -1
- package/core/built/admin/assets/overview-a8GfcsKX.js +0 -1
- package/core/built/admin/assets/page-header-DM_KyoFI.js +0 -1
- package/core/built/admin/assets/pagemenu-vgZVUVKR.js +0 -1
- package/core/built/admin/assets/pages-route-BzKZYdV5.js +0 -1
- package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +0 -10
- package/core/built/admin/assets/pintura-modal-DExCF1ii.js +0 -1
- package/core/built/admin/assets/portal-frame-Cqanidq4.js +0 -1
- package/core/built/admin/assets/portal-modal-oinBgA27.js +0 -1
- package/core/built/admin/assets/post-analytics-C5oJ1dWV.js +0 -1
- package/core/built/admin/assets/post-analytics-context-D0Mw-Pmv.js +0 -1
- package/core/built/admin/assets/post-analytics-header-OATo3X_r.js +0 -1
- package/core/built/admin/assets/post-analytics-provider-tOpIVGT5.js +0 -1
- package/core/built/admin/assets/post-share-modal-DvhC1XgV.js +0 -1
- package/core/built/admin/assets/posts-list-screen-o4ZjbgS3.js +0 -2
- package/core/built/admin/assets/posts-route-9F--xdIb.js +0 -1
- package/core/built/admin/assets/preferences--vNubsqD.js +0 -5
- package/core/built/admin/assets/preview-chrome-BljUBlOk.js +0 -1
- package/core/built/admin/assets/preview-modal-YYbzlYdO.js +0 -1
- package/core/built/admin/assets/profile-BllKV3dR.js +0 -1
- package/core/built/admin/assets/prop-types-DeUPn3oD.js +0 -1
- package/core/built/admin/assets/radio-group-DL8GI8rt.js +0 -1
- package/core/built/admin/assets/react-Bb3IsNbi.js +0 -1
- package/core/built/admin/assets/rolldown-runtime-DAXXjFlN.js +0 -1
- package/core/built/admin/assets/router-provider-BSvTXgZY.js +0 -1
- package/core/built/admin/assets/select-v5YbA3Mw.js +0 -1
- package/core/built/admin/assets/settings-PEsZupw1.js +0 -4
- package/core/built/admin/assets/settings-breadcrumbs-NwPnCTC7.js +0 -1
- package/core/built/admin/assets/settings-u_s1CRkr.js +0 -1
- package/core/built/admin/assets/shade-app-CcS3f8MZ-vwURazk8.js +0 -3
- package/core/built/admin/assets/share-modal-SskCmVGL.js +0 -1
- package/core/built/admin/assets/skeleton-Ce9GgUpf.js +0 -1
- package/core/built/admin/assets/slack-modal-XxSJiYgo.js +0 -1
- package/core/built/admin/assets/sort-button-Cx1KtINE.js +0 -1
- package/core/built/admin/assets/source-icon-Bdp9Im_5.js +0 -1
- package/core/built/admin/assets/stack-B2eszIiq.js +0 -1
- package/core/built/admin/assets/stats-view-W2g6Jsd-.js +0 -1
- package/core/built/admin/assets/step-1-BQYzvBzr.js +0 -1
- package/core/built/admin/assets/step-2-xES32xJV.js +0 -1
- package/core/built/admin/assets/step-3-DA_XK5kW.js +0 -2
- package/core/built/admin/assets/stripe-button-CVsLHelt.js +0 -1
- package/core/built/admin/assets/stripe-connect-modal-ClmLOMGS.js +0 -1
- package/core/built/admin/assets/switch-CI4gLWqb.js +0 -1
- package/core/built/admin/assets/table-BenqVupI.js +0 -1
- package/core/built/admin/assets/tabs-eBBlxPp8.js +0 -1
- package/core/built/admin/assets/tag-detail-Ce8Se2qd.js +0 -2
- package/core/built/admin/assets/tag-picker-C3UR-uJ-.js +0 -1
- package/core/built/admin/assets/tags-B-kJxCs7.js +0 -1
- package/core/built/admin/assets/testimonials-modal-9Q6fT06V.js +0 -1
- package/core/built/admin/assets/text-BQDSDsKs.js +0 -1
- package/core/built/admin/assets/textarea-DJ1Q5V39.js +0 -1
- package/core/built/admin/assets/tier-detail-modal-CDyYdqK7.js +0 -1
- package/core/built/admin/assets/toggle-group-CviIkyok.js +0 -1
- package/core/built/admin/assets/topic-filter-I2jCBGxm.js +0 -1
- package/core/built/admin/assets/transistor-modal-p53u3W8y.js +0 -1
- package/core/built/admin/assets/trend-badge-CideVzQd.js +0 -1
- package/core/built/admin/assets/types-uYQ1HgqL.js +0 -1
- package/core/built/admin/assets/unsplash-modal-DY8UcKcE.js +0 -1
- package/core/built/admin/assets/use-analytics-data-DAIGcr2f.js +0 -1
- package/core/built/admin/assets/use-filter-params-JkZhIS8L.js +0 -1
- package/core/built/admin/assets/use-filterable-api-BVEVMrhZ.js +0 -1
- package/core/built/admin/assets/use-form-vRjI0Kwk.js +0 -1
- package/core/built/admin/assets/use-growth-stats-937CUj6j.js +0 -1
- package/core/built/admin/assets/use-host-limits-D0Dv3tKA.js +0 -1
- package/core/built/admin/assets/use-limiter-CohWfzvK.js +0 -2
- package/core/built/admin/assets/use-navigate-with-base-path-BkxcPj5l.js +0 -1
- package/core/built/admin/assets/use-pintura-config-xgytjU35.js +0 -1
- package/core/built/admin/assets/use-pintura-editor-CaV1mbfO.js +0 -1
- package/core/built/admin/assets/use-post-referrers-BCQI7fDg.js +0 -1
- package/core/built/admin/assets/use-query-params-BfzuqbcD.js +0 -1
- package/core/built/admin/assets/use-reply-chain-data-CYRhoaxY.js +0 -1
- package/core/built/admin/assets/use-router-history-entry-NOKcd--l.js +0 -1
- package/core/built/admin/assets/use-setting-group-bLKMwoBT.js +0 -1
- package/core/built/admin/assets/use-settings-navigation-B-qrriKD.js +0 -1
- package/core/built/admin/assets/use-simple-pagination-CNPd6Rf6.js +0 -1
- package/core/built/admin/assets/use-staff-users-pRIMIyiW.js +0 -1
- package/core/built/admin/assets/use-tinybird-query-CmdbCS9X.js +0 -1
- package/core/built/admin/assets/use-tinybird-token-KLne235s.js +0 -1
- package/core/built/admin/assets/use-unsaved-changes-guard-7-ug0JdH.js +0 -1
- package/core/built/admin/assets/use-upgrade-route-Dm_qqKr0.js +0 -1
- package/core/built/admin/assets/user-detail-modal-D3KlGYv-.js +0 -1
- package/core/built/admin/assets/virtual-list-CZ3RK2Yf.js +0 -1
- package/core/built/admin/assets/web-ClEJsCAj.js +0 -2
- package/core/built/admin/assets/web-X9rdnrtq.js +0 -1
- package/core/built/admin/assets/zapier-modal-DfVhV17j.js +0 -1
- package/core/frontend/services/sitemap/utils.js +0 -17
- package/core/server/services/automations/get-scheduler-idempotency-key.js +0 -13
- package/core/server/web/api/testmode/index.js +0 -1
- package/core/server/web/api/testmode/jobs/cpu-hog.js +0 -15
- package/core/server/web/api/testmode/jobs/graceful-job.js +0 -50
- package/core/server/web/api/testmode/jobs/say-hello.js +0 -17
- package/core/server/web/api/testmode/routes.js +0 -120
- /package/core/built/admin/assets/{chunk.901.4ccc639821020230bcca.js.LICENSE.txt → chunk.972.4b8c97f93d66db15e751.js.LICENSE.txt} +0 -0
|
@@ -11,11 +11,14 @@ const zod_1 = require("zod");
|
|
|
11
11
|
const metafield_types_1 = require("@tryghost/metafield-types");
|
|
12
12
|
const identity_1 = require("@tryghost/metafield-types/identity");
|
|
13
13
|
const schema_1 = require("./schema");
|
|
14
|
+
const date_1 = require("../../lib/db-types/date");
|
|
14
15
|
const queries_1 = require("./queries");
|
|
15
16
|
const access_1 = require("./access");
|
|
16
17
|
const storage_1 = require("./storage");
|
|
17
18
|
const FIELDS_TABLE = 'members_metafields';
|
|
18
19
|
const VALUES_TABLE = 'members_metafield_values';
|
|
20
|
+
const CHANGE_EVENTS_TABLE = 'members_metafield_change_events';
|
|
21
|
+
const MEMBERS_TABLE = 'members';
|
|
19
22
|
/**
|
|
20
23
|
* From the canonical schema, the same source definitions-service reads, so no key a site
|
|
21
24
|
* could hold is refused and this cannot drift from the `members_metafields.key` column.
|
|
@@ -34,6 +37,24 @@ const UPSERT_CHUNK = 400;
|
|
|
34
37
|
const MAX_IDENTITY_LENGTH = MAX_KEY_LENGTH * 2 + 1;
|
|
35
38
|
const ValuesInput = zod_1.z.record(zod_1.z.string().max(MAX_IDENTITY_LENGTH), zod_1.z.unknown());
|
|
36
39
|
const wireProperty = (identity) => [identity_1.QUALIFIER, identity].join('.');
|
|
40
|
+
/**
|
|
41
|
+
* Every refusal in one error.
|
|
42
|
+
*
|
|
43
|
+
* The API renders a single error, so the first still fills `message` and `property` and
|
|
44
|
+
* a client that reads only those sees exactly what it saw before. The whole set rides in
|
|
45
|
+
* `errorDetails`, which the renderer already passes through as `details`, so a client
|
|
46
|
+
* that wants to mark every refused input can have them all from one attempt.
|
|
47
|
+
*/
|
|
48
|
+
function refusalError(refusals) {
|
|
49
|
+
const [first, ...rest] = refusals;
|
|
50
|
+
return new errors_1.default.ValidationError({
|
|
51
|
+
message: first.message,
|
|
52
|
+
property: first.property,
|
|
53
|
+
// Omitted when there is nothing more to say, so the common single refusal keeps the
|
|
54
|
+
// shape it has always had rather than growing a one-element list.
|
|
55
|
+
...(rest.length > 0 ? { errorDetails: refusals } : {}),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
37
58
|
/**
|
|
38
59
|
* What a member holds for each defined field. Separate from the definitions service
|
|
39
60
|
* because a value belongs to the member and a definition belongs to the site's settings,
|
|
@@ -47,7 +68,11 @@ class MetafieldValuesService {
|
|
|
47
68
|
this.knex = knex;
|
|
48
69
|
this.getMaxDefinitions = getMaxDefinitions;
|
|
49
70
|
}
|
|
50
|
-
|
|
71
|
+
// The query is scoped to the audience, so a field they may not see is absent from
|
|
72
|
+
// the map and the caller reports it as unknown. Looking up unscoped and rejecting
|
|
73
|
+
// afterwards would let a member tell a hidden field from an undefined one by the
|
|
74
|
+
// reply they got.
|
|
75
|
+
async allowedFieldsByIdentity(identities, audience) {
|
|
51
76
|
const keys = identities
|
|
52
77
|
.map((identity) => (0, identity_1.parseIdentity)(identity))
|
|
53
78
|
.filter((parsed) => parsed !== null && parsed.namespace === identity_1.CUSTOM_NAMESPACE)
|
|
@@ -55,12 +80,19 @@ class MetafieldValuesService {
|
|
|
55
80
|
if (keys.length === 0) {
|
|
56
81
|
return new Map();
|
|
57
82
|
}
|
|
58
|
-
const fields = await (0, queries_1.
|
|
83
|
+
const fields = await (0, queries_1.definitions)(this.knex, { audience, status: queries_1.ACTIVE_ONLY })
|
|
59
84
|
.whereIn('key', keys)
|
|
60
|
-
.select('id', 'key', 'name', 'type');
|
|
85
|
+
.select('id', 'key', 'name', 'type', 'member_access');
|
|
61
86
|
return new Map(fields.map((field) => [
|
|
62
87
|
(0, identity_1.formatIdentity)({ namespace: identity_1.CUSTOM_NAMESPACE, key: field.key, partPath: null }),
|
|
63
|
-
{
|
|
88
|
+
{
|
|
89
|
+
id: field.id,
|
|
90
|
+
key: field.key,
|
|
91
|
+
name: field.name,
|
|
92
|
+
type: field.type,
|
|
93
|
+
namespace: identity_1.CUSTOM_NAMESPACE,
|
|
94
|
+
memberAccess: field.member_access,
|
|
95
|
+
},
|
|
64
96
|
]));
|
|
65
97
|
}
|
|
66
98
|
async getValuesForMembers(memberIds, audience) {
|
|
@@ -70,8 +102,7 @@ class MetafieldValuesService {
|
|
|
70
102
|
// Not ordered by field: these rows become an object keyed by field, and an object
|
|
71
103
|
// cannot carry an order. `path` is ordered so composite parts assemble the same
|
|
72
104
|
// way every time.
|
|
73
|
-
const rows = await this.knex(VALUES_TABLE)
|
|
74
|
-
.join(FIELDS_TABLE, `${VALUES_TABLE}.metafield_key`, `${FIELDS_TABLE}.key`)
|
|
105
|
+
const rows = await (0, queries_1.readableBy)(this.knex(VALUES_TABLE).join(FIELDS_TABLE, `${VALUES_TABLE}.metafield_key`, `${FIELDS_TABLE}.key`), audience)
|
|
75
106
|
.whereIn(`${VALUES_TABLE}.member_id`, memberIds)
|
|
76
107
|
.where(`${FIELDS_TABLE}.status`, schema_1.FIELD_STATUS.active)
|
|
77
108
|
.orderBy(`${VALUES_TABLE}.path`, 'asc')
|
|
@@ -90,10 +121,7 @@ class MetafieldValuesService {
|
|
|
90
121
|
}, 'Skipping an unreadable metafield value');
|
|
91
122
|
}
|
|
92
123
|
}
|
|
93
|
-
|
|
94
|
-
// several rows, and dropping some of its parts later would hand back half an
|
|
95
|
-
// address rather than no address.
|
|
96
|
-
const flat = (0, storage_1.valuesFromLeaves)((0, access_1.readableFields)(audience, leaves));
|
|
124
|
+
const flat = (0, storage_1.valuesFromLeaves)(leaves);
|
|
97
125
|
return new Map(memberIds.map((memberId) => [memberId, { [identity_1.CUSTOM_NAMESPACE]: flat.get(memberId) ?? {} }]));
|
|
98
126
|
}
|
|
99
127
|
parseValues(input) {
|
|
@@ -157,21 +185,29 @@ class MetafieldValuesService {
|
|
|
157
185
|
property: identity_1.QUALIFIER,
|
|
158
186
|
});
|
|
159
187
|
}
|
|
160
|
-
const byIdentity = await this.
|
|
188
|
+
const byIdentity = await this.allowedFieldsByIdentity(identities, audience);
|
|
161
189
|
const writes = [];
|
|
190
|
+
// Gathered rather than thrown as they are found. A write names several values, and
|
|
191
|
+
// a composite is several again, so refusing at the first leaves someone correcting
|
|
192
|
+
// one part per round trip to learn what was wrong with the rest.
|
|
193
|
+
const refusals = [];
|
|
162
194
|
for (const [identity, raw] of Object.entries(values)) {
|
|
163
195
|
const field = byIdentity.get(identity);
|
|
164
196
|
if (!field) {
|
|
165
|
-
|
|
197
|
+
refusals.push({
|
|
166
198
|
message: `Unknown custom field: ${identity}`,
|
|
167
199
|
property: wireProperty(identity),
|
|
168
200
|
});
|
|
201
|
+
continue;
|
|
169
202
|
}
|
|
203
|
+
// A different refusal from the unknown-field one above: this audience can
|
|
204
|
+
// already see the field, so naming it discloses nothing.
|
|
170
205
|
if (!(0, access_1.canWrite)(audience, field)) {
|
|
171
|
-
|
|
206
|
+
refusals.push({
|
|
172
207
|
message: `Cannot set custom field: ${identity}`,
|
|
173
208
|
property: wireProperty(identity),
|
|
174
209
|
});
|
|
210
|
+
continue;
|
|
175
211
|
}
|
|
176
212
|
// `null` clears any field, and `''` clears one with no parts. For a value
|
|
177
213
|
// with parts `''` names nothing, so it is left to fail validation rather than
|
|
@@ -186,14 +222,21 @@ class MetafieldValuesService {
|
|
|
186
222
|
// Which field failed rides in `property`.
|
|
187
223
|
const value = metafield_types_1.FIELD_TYPES[field.type].value.safeParse(raw);
|
|
188
224
|
if (!value.success) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
225
|
+
// Every issue, not the first: a value with parts fails once per part, and each
|
|
226
|
+
// names the part it belongs to, which is what lets a client mark them all.
|
|
227
|
+
for (const issue of value.error.issues) {
|
|
228
|
+
refusals.push({
|
|
229
|
+
message: issue.message,
|
|
230
|
+
property: [wireProperty(identity), ...issue.path].join('.'),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
continue;
|
|
194
234
|
}
|
|
195
235
|
writes.push({ field, value: value.data });
|
|
196
236
|
}
|
|
237
|
+
if (refusals.length > 0) {
|
|
238
|
+
throw refusalError(refusals);
|
|
239
|
+
}
|
|
197
240
|
return writes;
|
|
198
241
|
}
|
|
199
242
|
/**
|
|
@@ -204,13 +247,19 @@ class MetafieldValuesService {
|
|
|
204
247
|
* them, and saying nothing about a path leaves it alone. There is no whole-value
|
|
205
248
|
* replace, so a caller that does not know about a field cannot erase it.
|
|
206
249
|
*
|
|
207
|
-
* `writtenBy`
|
|
208
|
-
* one cannot quietly inherit the identity of
|
|
250
|
+
* `writtenBy` and `source` are required and have no default: every writer has to name
|
|
251
|
+
* itself and where it wrote, so a new one cannot quietly inherit the identity of
|
|
252
|
+
* whichever was written first.
|
|
209
253
|
*
|
|
210
254
|
* Always transactional. Given an executor it joins that transaction, so the importer's
|
|
211
255
|
* failed value write takes its member with it; given none it opens its own.
|
|
256
|
+
*
|
|
257
|
+
* Every write also puts an entry on the member's activity feed, naming the fields it
|
|
258
|
+
* touched and who wrote them where, in the same transaction, so the feed cannot name a
|
|
259
|
+
* change that was not stored or miss one that was. A value has more than one author,
|
|
260
|
+
* and the feed is where a publisher finds out which of them changed it.
|
|
212
261
|
*/
|
|
213
|
-
async applyWrite(memberId, writes, { writtenBy, executor = this.knex }) {
|
|
262
|
+
async applyWrite(memberId, writes, { writtenBy, source, executor = this.knex }) {
|
|
214
263
|
if (writes.length === 0) {
|
|
215
264
|
return;
|
|
216
265
|
}
|
|
@@ -273,6 +322,22 @@ class MetafieldValuesService {
|
|
|
273
322
|
// it currently holds rather than who wrote its first value.
|
|
274
323
|
.merge(['value_text', 'written_by_type', 'written_by_id', 'updated_at']);
|
|
275
324
|
}
|
|
325
|
+
const fields = writes.map(({ field }) => ({
|
|
326
|
+
namespace: field.namespace,
|
|
327
|
+
key: field.key,
|
|
328
|
+
name: field.name,
|
|
329
|
+
}));
|
|
330
|
+
await trx(CHANGE_EVENTS_TABLE).insert({
|
|
331
|
+
id: new bson_objectid_1.default().toHexString(),
|
|
332
|
+
member_id: memberId,
|
|
333
|
+
written_by_type: writtenBy.type,
|
|
334
|
+
written_by_id: writtenBy.id,
|
|
335
|
+
source,
|
|
336
|
+
metafields: schema_1.StoredFieldList.encode(fields),
|
|
337
|
+
// A string rather than the Date the value rows take: SQLite stores a bound Date
|
|
338
|
+
// as a number, which sorts before every string the feed pages through time with.
|
|
339
|
+
created_at: (0, date_1.toDatabaseDate)(now),
|
|
340
|
+
});
|
|
276
341
|
};
|
|
277
342
|
// knex's marker for a transactor: join it rather than nesting a savepoint under it.
|
|
278
343
|
if (executor.isTransaction) {
|
|
@@ -282,5 +347,51 @@ class MetafieldValuesService {
|
|
|
282
347
|
await executor.transaction(apply);
|
|
283
348
|
}
|
|
284
349
|
}
|
|
350
|
+
/**
|
|
351
|
+
* Entries from members' activity feeds, newest first, each with its member, as one page
|
|
352
|
+
* of the members events endpoint reads them.
|
|
353
|
+
*
|
|
354
|
+
* `filter` is a parsed NQL filter over this table's own columns: mapping the feed's
|
|
355
|
+
* names onto them is the feed's business, and applying them is this table's.
|
|
356
|
+
*/
|
|
357
|
+
async browseChangeEvents({ limit, filter, }) {
|
|
358
|
+
const filtered = () => {
|
|
359
|
+
const query = this.knex(CHANGE_EVENTS_TABLE);
|
|
360
|
+
return filter ? (0, queries_1.knexify)(query, filter, { tableName: CHANGE_EVENTS_TABLE }) : query;
|
|
361
|
+
};
|
|
362
|
+
// Joined rather than looked up afterwards: an entry cannot outlive its member, whose
|
|
363
|
+
// delete cascades to it, so every entry has one to join.
|
|
364
|
+
const newestFirst = filtered()
|
|
365
|
+
.join(MEMBERS_TABLE, `${MEMBERS_TABLE}.id`, `${CHANGE_EVENTS_TABLE}.member_id`)
|
|
366
|
+
.orderBy([
|
|
367
|
+
{ column: `${CHANGE_EVENTS_TABLE}.created_at`, order: 'desc' },
|
|
368
|
+
{ column: `${CHANGE_EVENTS_TABLE}.id`, order: 'desc' },
|
|
369
|
+
]);
|
|
370
|
+
const page = limit === undefined ? newestFirst : newestFirst.limit(limit);
|
|
371
|
+
const [rows, counted] = await Promise.all([
|
|
372
|
+
page.select(`${CHANGE_EVENTS_TABLE}.id`, `${CHANGE_EVENTS_TABLE}.member_id`, `${CHANGE_EVENTS_TABLE}.written_by_type`, `${CHANGE_EVENTS_TABLE}.written_by_id`, `${CHANGE_EVENTS_TABLE}.source`, `${CHANGE_EVENTS_TABLE}.metafields`, `${CHANGE_EVENTS_TABLE}.created_at`, { member_uuid: `${MEMBERS_TABLE}.uuid` }, { member_name: `${MEMBERS_TABLE}.name` }, { member_email: `${MEMBERS_TABLE}.email` }),
|
|
373
|
+
filtered().count({ total: '*' }).first(),
|
|
374
|
+
]);
|
|
375
|
+
// What to do with an entry whose field list can't be read is decided here, not in the
|
|
376
|
+
// parser: it is still shown, naming no fields. The feed pages through time a page per
|
|
377
|
+
// event type, so dropping an entry would push a valid one off the end of its page for
|
|
378
|
+
// good. Anything else a row can't be read for, the table's constraints rule out, so it
|
|
379
|
+
// throws rather than being hidden.
|
|
380
|
+
const events = rows.map(({ member_uuid: uuid, member_name: name, member_email: email, ...event }) => {
|
|
381
|
+
const fields = schema_1.StoredFieldList.safeParse(event.metafields);
|
|
382
|
+
if (!fields.success) {
|
|
383
|
+
logging_1.default.warn({
|
|
384
|
+
event: { name: 'members.metafields.change_event_unreadable' },
|
|
385
|
+
err: fields.error,
|
|
386
|
+
changeEventId: event.id,
|
|
387
|
+
}, 'Reading an unreadable metafield change entry as naming no fields');
|
|
388
|
+
}
|
|
389
|
+
return schema_1.DbMetafieldChangeEventWithMember.parse({
|
|
390
|
+
event: fields.success ? event : { ...event, metafields: schema_1.StoredFieldList.encode([]) },
|
|
391
|
+
member: { id: event.member_id, uuid, name, email },
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
return { events, total: Number(counted?.total ?? 0) };
|
|
395
|
+
}
|
|
285
396
|
}
|
|
286
397
|
exports.MetafieldValuesService = MetafieldValuesService;
|
|
@@ -63,7 +63,7 @@ module.exports = class MentionDiscoveryService {
|
|
|
63
63
|
return null;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const cheerio = require('cheerio');
|
|
66
|
+
const cheerio = require('cheerio/slim');
|
|
67
67
|
const $ = cheerio.load(response.body);
|
|
68
68
|
|
|
69
69
|
// must be first <link> OR <a> element with rel=webmention
|
|
@@ -81,8 +81,8 @@ module.exports = class MentionSendingService {
|
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
83
|
// make sure we have something to parse before we create a job
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const html = post.get('status') === 'published' ? post.get('html') : null;
|
|
85
|
+
const previousHtml = post.previous('status') === 'published' ? post.previous('html') : null;
|
|
86
86
|
if (html || previousHtml) {
|
|
87
87
|
// Capture the source URL now, from the event's data, rather than
|
|
88
88
|
// deferring the model into the job.
|
|
@@ -242,7 +242,7 @@ module.exports = class MentionSendingService {
|
|
|
242
242
|
* @returns {URL[]}
|
|
243
243
|
*/
|
|
244
244
|
getLinks(html) {
|
|
245
|
-
const cheerio = require('cheerio');
|
|
245
|
+
const cheerio = require('cheerio/slim');
|
|
246
246
|
const $ = cheerio.load(html);
|
|
247
247
|
const urls = [];
|
|
248
248
|
const siteUrl = this.siteUrl;
|
|
@@ -61,7 +61,7 @@ module.exports = class Mention {
|
|
|
61
61
|
|
|
62
62
|
if (contentType.includes('text/html')) {
|
|
63
63
|
try {
|
|
64
|
-
const cheerio = require('cheerio');
|
|
64
|
+
const cheerio = require('cheerio/slim');
|
|
65
65
|
const $ = cheerio.load(html);
|
|
66
66
|
const hasTargetUrl =
|
|
67
67
|
$(
|
|
@@ -309,12 +309,11 @@ module.exports = class Mention {
|
|
|
309
309
|
timestamp = new Date();
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
|
|
313
|
-
payload = data.payload ? JSON.parse(JSON.stringify(data.payload)) : null;
|
|
312
|
+
const payload = data.payload ? JSON.parse(JSON.stringify(data.payload)) : null;
|
|
314
313
|
|
|
315
314
|
/** @type boolean */
|
|
316
|
-
|
|
317
|
-
verified = isNew ? false : !!data.verified;
|
|
315
|
+
|
|
316
|
+
const verified = isNew ? false : !!data.verified;
|
|
318
317
|
|
|
319
318
|
/** @type {ObjectID | null} */
|
|
320
319
|
let resourceId = null;
|
|
@@ -321,7 +321,10 @@ module.exports = class MentionsAPI {
|
|
|
321
321
|
* @returns {Promise<Mention>}
|
|
322
322
|
*/
|
|
323
323
|
async processWebmention(webmention) {
|
|
324
|
-
|
|
324
|
+
const mention = await this.#repository.getBySourceAndTarget(
|
|
325
|
+
webmention.source,
|
|
326
|
+
webmention.target,
|
|
327
|
+
);
|
|
325
328
|
|
|
326
329
|
return await this.#updateWebmention(mention, webmention);
|
|
327
330
|
}
|
|
@@ -20,33 +20,6 @@ const workerMessageHandler = ({ name, message }) => {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
const initTestMode = () => {
|
|
24
|
-
// Output job queue length every 5 seconds
|
|
25
|
-
setInterval(() => {
|
|
26
|
-
logging.warn(
|
|
27
|
-
`${jobManager.inlineQueue.length()} jobs in the queue. Idle: ${jobManager.inlineQueue.idle()}`,
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const runningScheduledjobs = Object.keys(jobManager.bree.workers);
|
|
31
|
-
if (Object.keys(jobManager.bree.workers).length) {
|
|
32
|
-
logging.warn(
|
|
33
|
-
`${Object.keys(jobManager.bree.workers).length} jobs running: ${runningScheduledjobs}`,
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const scheduledJobs = Object.keys(jobManager.bree.intervals);
|
|
38
|
-
if (Object.keys(jobManager.bree.intervals).length) {
|
|
39
|
-
logging.warn(
|
|
40
|
-
`${Object.keys(jobManager.bree.intervals).length} scheduled jobs: ${scheduledJobs}`,
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (runningScheduledjobs.length === 0 && scheduledJobs.length === 0) {
|
|
45
|
-
logging.warn('No scheduled or running jobs');
|
|
46
|
-
}
|
|
47
|
-
}, 5000);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
23
|
const jobManager = new JobManager({
|
|
51
24
|
errorHandler,
|
|
52
25
|
workerMessageHandler,
|
|
@@ -56,4 +29,3 @@ const jobManager = new JobManager({
|
|
|
56
29
|
});
|
|
57
30
|
|
|
58
31
|
module.exports = jobManager;
|
|
59
|
-
module.exports.initTestMode = initTestMode;
|
|
@@ -300,7 +300,7 @@ module.exports = class MilestonesService {
|
|
|
300
300
|
const membersMilestones = this.#milestonesConfig.members;
|
|
301
301
|
|
|
302
302
|
// get the closest milestone we're over now
|
|
303
|
-
|
|
303
|
+
const achievedMilestones = this.#getMatchedMilestones(membersMilestones, membersCount);
|
|
304
304
|
|
|
305
305
|
// check for previously achieved milestones. We do not send an email when no
|
|
306
306
|
// previous milestones exist
|
|
@@ -37,7 +37,7 @@ class Notifications {
|
|
|
37
37
|
* @returns {Object[]} - all notifications
|
|
38
38
|
*/
|
|
39
39
|
fetchAllNotifications() {
|
|
40
|
-
|
|
40
|
+
const allNotifications = this.settingsCache.get('notifications');
|
|
41
41
|
|
|
42
42
|
// @TODO: this check can be removed to improve read operation perf. It's here only because
|
|
43
43
|
// reads are done often and this gives a possibility to self-heal any broken records.
|
|
@@ -67,7 +67,7 @@ class Notifications {
|
|
|
67
67
|
* @returns {boolean}
|
|
68
68
|
*/
|
|
69
69
|
areNotificationsValid(notifications) {
|
|
70
|
-
if (!
|
|
70
|
+
if (!Array.isArray(notifications)) {
|
|
71
71
|
return false;
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -151,7 +151,7 @@ class Notifications {
|
|
|
151
151
|
addedAt: moment().toDate(),
|
|
152
152
|
};
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
const notificationsToCheck = notifications;
|
|
155
155
|
let notificationsToAdd = [];
|
|
156
156
|
|
|
157
157
|
const allNotifications = this.fetchAllNotifications();
|
|
@@ -42,6 +42,7 @@ const messages = {
|
|
|
42
42
|
unableToFetchOembed: 'Unable to fetch requested embed.',
|
|
43
43
|
unauthorized: 'URL contains a private resource.',
|
|
44
44
|
unconvertibleSvg: 'SVG image is too large or compressed to convert.',
|
|
45
|
+
unsupportedImage: 'Image is not a supported file type.',
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
const SVG_RASTER_SIZE = 256;
|
|
@@ -68,6 +69,16 @@ const shouldRasterize = (buffer, ext) => {
|
|
|
68
69
|
return head.startsWith('<') && /<svg[\s:>]/i.test(head);
|
|
69
70
|
};
|
|
70
71
|
|
|
72
|
+
let fileTypeFromBuffer;
|
|
73
|
+
|
|
74
|
+
const detectFileType = async (buffer) => {
|
|
75
|
+
if (!fileTypeFromBuffer) {
|
|
76
|
+
({ fileTypeFromBuffer } = await import('file-type'));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return fileTypeFromBuffer(buffer);
|
|
80
|
+
};
|
|
81
|
+
|
|
71
82
|
/**
|
|
72
83
|
* @param {string} url
|
|
73
84
|
* @returns {{url: string, provider: boolean}}
|
|
@@ -79,15 +90,15 @@ const findUrlWithProvider = (url) => {
|
|
|
79
90
|
|
|
80
91
|
// build up a list of URL variations to test against because the oembed
|
|
81
92
|
// providers list is not always up to date with scheme or www vs non-www
|
|
82
|
-
|
|
83
|
-
|
|
93
|
+
const baseUrl = url.replace(/^\/\/|^https?:\/\/(?:www\.)?/, '');
|
|
94
|
+
const testUrls = [
|
|
84
95
|
`https://${baseUrl}`,
|
|
85
96
|
`https://www.${baseUrl}`,
|
|
86
97
|
`http://${baseUrl}`,
|
|
87
98
|
`http://www.${baseUrl}`,
|
|
88
99
|
];
|
|
89
100
|
|
|
90
|
-
for (
|
|
101
|
+
for (const testUrl of testUrls) {
|
|
91
102
|
provider = hasProvider(testUrl);
|
|
92
103
|
if (provider) {
|
|
93
104
|
url = testUrl;
|
|
@@ -234,6 +245,20 @@ class OEmbedService {
|
|
|
234
245
|
});
|
|
235
246
|
|
|
236
247
|
ext = '.png';
|
|
248
|
+
} else {
|
|
249
|
+
// The URL's extension is attacker-controlled and decides the
|
|
250
|
+
// Content-Type the stored file is later served with, so name the
|
|
251
|
+
// file after its contents and hold it to the same allowlist as image
|
|
252
|
+
// uploads. `file-type` never reports SVG, which is handled above.
|
|
253
|
+
const fileType = await detectFileType(imageBuffer);
|
|
254
|
+
ext = fileType ? `.${fileType.ext}` : '';
|
|
255
|
+
|
|
256
|
+
if (!this.config.get('uploads').images.extensions.includes(ext)) {
|
|
257
|
+
throw new errors.ValidationError({
|
|
258
|
+
message: tpl(messages.unsupportedImage),
|
|
259
|
+
context: imageUrl,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
237
262
|
}
|
|
238
263
|
|
|
239
264
|
const uniqueFileName = `${name}-${crypto.randomUUID()}${ext}`;
|
|
@@ -369,6 +394,80 @@ class OEmbedService {
|
|
|
369
394
|
};
|
|
370
395
|
}
|
|
371
396
|
|
|
397
|
+
/**
|
|
398
|
+
* Requests a URL through this.externalRequest and resolves with the response
|
|
399
|
+
* and at most the first chunk of its body, aborting the rest of the download.
|
|
400
|
+
*
|
|
401
|
+
* @param {string} url
|
|
402
|
+
* @returns {Promise<{response: import('got').Response, chunk?: Buffer}>}
|
|
403
|
+
*/
|
|
404
|
+
fetchFirstChunk(url) {
|
|
405
|
+
return new Promise((resolve, reject) => {
|
|
406
|
+
const stream = this.externalRequest.stream(url, {
|
|
407
|
+
headers: {
|
|
408
|
+
'user-agent': USER_AGENT,
|
|
409
|
+
range: 'bytes=0-0',
|
|
410
|
+
},
|
|
411
|
+
timeout: {
|
|
412
|
+
request: DEFAULT_REQUEST_TIMEOUT,
|
|
413
|
+
},
|
|
414
|
+
decompress: false,
|
|
415
|
+
throwHttpErrors: false,
|
|
416
|
+
});
|
|
417
|
+
let response;
|
|
418
|
+
|
|
419
|
+
stream.on('response', (res) => {
|
|
420
|
+
response = res;
|
|
421
|
+
});
|
|
422
|
+
stream.once('data', (chunk) => {
|
|
423
|
+
stream.destroy();
|
|
424
|
+
resolve({ response, chunk });
|
|
425
|
+
});
|
|
426
|
+
stream.once('end', () => resolve({ response }));
|
|
427
|
+
stream.on('error', reject);
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Checks that a favicon candidate is reachable and looks like an image.
|
|
433
|
+
*
|
|
434
|
+
* Replaces metascraper-logo-favicon's default resolver, which probes via
|
|
435
|
+
* reachable-url. reachable-url bundles got 11, which ignores the `dnsLookup`
|
|
436
|
+
* externalRequest installs to validate the resolved IP at connection time,
|
|
437
|
+
* leaving those probes open to DNS rebinding. Mirrors the default resolver's
|
|
438
|
+
* checks otherwise.
|
|
439
|
+
*
|
|
440
|
+
* @param {string} faviconUrl
|
|
441
|
+
* @param {Array<string|string[]>} [contentTypes] - allowed content types for the icon's extension
|
|
442
|
+
* @returns {Promise<{url: string} | undefined>}
|
|
443
|
+
*/
|
|
444
|
+
async resolveFaviconUrl(faviconUrl, contentTypes) {
|
|
445
|
+
let result;
|
|
446
|
+
try {
|
|
447
|
+
result = await this.fetchFirstChunk(faviconUrl);
|
|
448
|
+
} catch {
|
|
449
|
+
return undefined;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const { response, chunk } = result;
|
|
453
|
+
if (!response || response.statusCode < 200 || response.statusCode >= 300) {
|
|
454
|
+
return undefined;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (contentTypes) {
|
|
458
|
+
const contentType = response.headers['content-type']?.split(';')[0].toLowerCase();
|
|
459
|
+
if (!contentType || !contentTypes.some((ct) => contentType.includes(ct))) {
|
|
460
|
+
return undefined;
|
|
461
|
+
}
|
|
462
|
+
// An empty body or one starting with '<' (60) is markup, not an image
|
|
463
|
+
if (!chunk?.length || chunk[0] === 60) {
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return { url: response.url };
|
|
469
|
+
}
|
|
470
|
+
|
|
372
471
|
/**
|
|
373
472
|
* @param {string} url
|
|
374
473
|
* @param {string} html
|
|
@@ -452,6 +551,8 @@ class OEmbedService {
|
|
|
452
551
|
require('metascraper-logo-favicon')({
|
|
453
552
|
gotOpts,
|
|
454
553
|
pickFn,
|
|
554
|
+
resolveFaviconUrl: (faviconUrl, contentTypes) =>
|
|
555
|
+
this.resolveFaviconUrl(faviconUrl, contentTypes),
|
|
455
556
|
}),
|
|
456
557
|
require('metascraper-logo')(),
|
|
457
558
|
];
|
|
@@ -561,12 +662,12 @@ class OEmbedService {
|
|
|
561
662
|
*/
|
|
562
663
|
async fetchOembedData(url, html, cardType) {
|
|
563
664
|
// Lazy require the library to keep boot quick
|
|
564
|
-
const cheerio = require('cheerio');
|
|
665
|
+
const cheerio = require('cheerio/slim');
|
|
565
666
|
|
|
566
667
|
// check for <link rel="alternate" type="application/json+oembed"> element
|
|
567
668
|
let oembedUrl;
|
|
568
669
|
try {
|
|
569
|
-
oembedUrl = cheerio('link[type="application/json+oembed"]'
|
|
670
|
+
oembedUrl = cheerio.load(html)('link[type="application/json+oembed"]').attr('href');
|
|
570
671
|
} catch (e) {
|
|
571
672
|
return this.unknownProvider(url);
|
|
572
673
|
}
|
|
@@ -622,15 +723,15 @@ class OEmbedService {
|
|
|
622
723
|
return;
|
|
623
724
|
}
|
|
624
725
|
|
|
625
|
-
// `rich` and `
|
|
626
|
-
// stored in the post's Lexical payload and rendered
|
|
627
|
-
// editor preview (via srcdoc) and into public themes
|
|
628
|
-
// Known providers (YouTube, Twitter, etc.)
|
|
629
|
-
// with @extractus/oembed-extractor's
|
|
630
|
-
// here is an arbitrary site's
|
|
631
|
-
// must not trust. Drop the
|
|
632
|
-
// a bookmark card.
|
|
633
|
-
if (oembed.type === 'video' || oembed.type === 'rich') {
|
|
726
|
+
// `rich`, `video` and `photo` responses can all ship provider-supplied
|
|
727
|
+
// HTML that gets stored in the post's Lexical payload and rendered
|
|
728
|
+
// into the admin editor preview (via srcdoc) and into public themes
|
|
729
|
+
// and emails (via innerHTML). Known providers (YouTube, Twitter, etc.)
|
|
730
|
+
// go through `knownProvider` with @extractus/oembed-extractor's
|
|
731
|
+
// allowlist — anything reaching here is an arbitrary site's
|
|
732
|
+
// self-declared oEmbed endpoint, which we must not trust. Drop the
|
|
733
|
+
// response and let the caller fall back to a bookmark card.
|
|
734
|
+
if (oembed.type === 'video' || oembed.type === 'rich' || oembed.type === 'photo') {
|
|
634
735
|
return;
|
|
635
736
|
}
|
|
636
737
|
|
|
@@ -132,7 +132,6 @@ class CanThisResult {
|
|
|
132
132
|
const self = this;
|
|
133
133
|
let userPermissionLoad;
|
|
134
134
|
let apiKeyPermissionLoad;
|
|
135
|
-
let permissionsLoad;
|
|
136
135
|
|
|
137
136
|
// Get context.user, context.api_key and context.app
|
|
138
137
|
context = parseContext(context);
|
|
@@ -158,7 +157,7 @@ class CanThisResult {
|
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
// Wait for both user and api key permissions to load
|
|
161
|
-
permissionsLoad = Promise.all([userPermissionLoad, apiKeyPermissionLoad]).then(
|
|
160
|
+
const permissionsLoad = Promise.all([userPermissionLoad, apiKeyPermissionLoad]).then(
|
|
162
161
|
function (result) {
|
|
163
162
|
return {
|
|
164
163
|
user: result[0],
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const moment_1 = __importDefault(require("moment"));
|
|
7
7
|
const logging_1 = __importDefault(require("@tryghost/logging"));
|
|
8
8
|
const build_signed_job_1 = require("../../adapters/scheduling/build-signed-job");
|
|
9
|
+
const get_scheduler_idempotency_key_1 = require("../../adapters/scheduling/get-scheduler-idempotency-key");
|
|
9
10
|
// CJS-only modules — typed loosely below. models is the Bookshelf registry
|
|
10
11
|
// without TS declarations; the rest are JS modules without types.
|
|
11
12
|
const models = require('../../models');
|
|
@@ -111,14 +112,20 @@ class PostScheduling {
|
|
|
111
112
|
const resource = `${resourceType}s`;
|
|
112
113
|
const publishedAt = event === 'unscheduled' ? model.previous('published_at') : model.get('published_at');
|
|
113
114
|
const previousPublishedAt = model.previous('published_at');
|
|
115
|
+
const time = (0, moment_1.default)(publishedAt).valueOf();
|
|
114
116
|
return (0, build_signed_job_1.buildSignedJob)({
|
|
115
117
|
apiUrl: this.#apiUrl,
|
|
116
118
|
path: ['schedules', resource, `${model.get('id')}/`],
|
|
117
|
-
time
|
|
119
|
+
time,
|
|
118
120
|
key,
|
|
119
121
|
extra: {
|
|
120
122
|
oldTime: previousPublishedAt ? (0, moment_1.default)(previousPublishedAt).valueOf() : null,
|
|
121
123
|
},
|
|
124
|
+
// The key identifies one job: the URL already carries the resource
|
|
125
|
+
// and a token signed for this fire time under the current signing key,
|
|
126
|
+
// so re-registering the same job (e.g. a boot rebuild) yields the same
|
|
127
|
+
// key, while a reschedule or key rotation yields a new one.
|
|
128
|
+
getIdempotencyKey: (url) => (0, get_scheduler_idempotency_key_1.getSchedulerIdempotencyKey)({ namespace: 'post-scheduling', date: new Date(time), url }),
|
|
122
129
|
});
|
|
123
130
|
}
|
|
124
131
|
}
|