ghost 6.53.0 → 6.54.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-scheduling-0.1.1.tgz +0 -0
- package/components/tryghost-adapter-base-sso-0.1.1.tgz +0 -0
- package/components/tryghost-admin-api-schema-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-converters-1.2.3.tgz +0 -0
- package/components/tryghost-kg-default-nodes-2.1.3.tgz +0 -0
- package/components/tryghost-kg-lexical-html-renderer-1.4.3.tgz +0 -0
- package/core/boot.js +9 -6
- package/core/built/admin/assets/Combination-CJG7Flp-.js +41 -0
- package/core/built/admin/assets/Growth-CSaHoSVD.js +3 -0
- package/core/built/admin/assets/Newsletters-C5cs6FGo.js +1 -0
- package/core/built/admin/assets/Overview-j4NaeUNm.js +1 -0
- package/core/built/admin/assets/{PolarAngleAxis-pciQ0MOy.js → PolarAngleAxis-BGjf7sBu.js} +1 -1
- package/core/built/admin/assets/{RadialBarChart-DWmw2PcX.js → RadialBarChart-zeFf9mBz.js} +1 -1
- package/core/built/admin/assets/Web-_fD935OX.js +2 -0
- package/core/built/admin/assets/account-migration-DLvVA5yq.js +1 -0
- package/core/built/admin/assets/activitypub/{account-migration-BPZG37DJ.js → account-migration-DHbZcxGM.js} +13 -13
- package/core/built/admin/assets/activitypub/activitypub.js +7 -7
- package/core/built/admin/assets/activitypub/{avatar-ZYco0ITb.js → avatar-B3DEDB1l.js} +10 -10
- package/core/built/admin/assets/activitypub/{avatar-flipboard-D541lc4F.js → avatar-flipboard-Cqrg0XMx.js} +3 -3
- package/core/built/admin/assets/activitypub/{bluesky-sharing-NOHUtHjl.js → bluesky-sharing-zfxUey_L.js} +38 -37
- package/core/built/admin/assets/activitypub/{chunk-KS7C4IRE-B-GOFDPZ.js → chunk-KS7C4IRE-D4HEcEwi.js} +716 -710
- package/core/built/admin/assets/activitypub/{content-formatters-bwrp4iEO.js → content-formatters-BpQARh28.js} +229 -181
- package/core/built/admin/assets/activitypub/{copy-C7m7ovHw.js → copy-D9UWIAan.js} +2 -2
- package/core/built/admin/assets/activitypub/{dist-B5ira32t.js → dist-Ba_QxHHl.js} +5 -5
- package/core/built/admin/assets/activitypub/{domain-iqE4YXwD.js → domain-CmwSZLHK.js} +33 -33
- package/core/built/admin/assets/activitypub/{edit-profile-B8MFYh28.js → edit-profile-CXdwNmVG.js} +46 -45
- package/core/built/admin/assets/activitypub/{explore-BbdKodp3.js → explore-DfbjzGM1.js} +20 -20
- package/core/built/admin/assets/activitypub/{feed-Cl3A5owG.js → feed-DSEBJOqf.js} +15 -15
- package/core/built/admin/assets/activitypub/{field-DL6WyR-c.js → field-CY7XVcx6.js} +13 -13
- package/core/built/admin/assets/activitypub/{hash-6G3DzwL9.js → hash-BC9Q0N4c.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-YmhuBice.js → inbox-DQ4ZnC1m.js} +2 -2
- package/core/built/admin/assets/activitypub/inbox-DtQ0kytT.js +1221 -0
- package/core/built/admin/assets/activitypub/{label-DGbLjDvE.js → label-Dw96GQ7u.js} +6 -6
- package/core/built/admin/assets/activitypub/layout-IdVq3lRy.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-qnBtk1zS.js → moderation-Dg_-I-8C.js} +32 -31
- package/core/built/admin/assets/activitypub/{note-C7ZRoSJv.js → note-Cy1-uKMY.js} +21 -21
- package/core/built/admin/assets/activitypub/{notifications-DiEA4b1o.js → notifications-B_fvoLIM.js} +17 -17
- package/core/built/admin/assets/activitypub/{onboarding-_JVgEwgV.js → onboarding-BFDkzeR2.js} +2 -2
- package/core/built/admin/assets/activitypub/{onboarding-DG4zu3qM.js → onboarding-D6rcBdPe.js} +5 -5
- package/core/built/admin/assets/activitypub/{preferences-B3FtocnP.js → preferences-ByJseZp6.js} +1607 -1606
- package/core/built/admin/assets/activitypub/{profile-D8ZJfYXB.js → profile-BFtbnIjz.js} +264 -263
- package/core/built/admin/assets/activitypub/{reply-C1vggenw.js → reply-CpdMeAO5.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-BOii-V9n.js → routes-Dh3xXfce.js} +1311 -1295
- package/core/built/admin/assets/activitypub/{separator-1gNokN5S.js → separator-BI1FLsYM.js} +4 -4
- package/core/built/admin/assets/activitypub/{settings--9Sb0nbl.js → settings-DTgqJPxM.js} +14 -14
- package/core/built/admin/assets/activitypub/{site-fkMmqv0V.js → site-CdL9ZLqm.js} +10 -10
- package/core/built/admin/assets/activitypub/{step-1-QhivSMw2.js → step-1-DIDg4aHb.js} +15 -15
- package/core/built/admin/assets/activitypub/{step-2-pMk9YwqD.js → step-2-BfGe8BYt.js} +7 -7
- package/core/built/admin/assets/activitypub/{step-3-DvmVC1fo.js → step-3-mE9spAqw.js} +12 -12
- package/core/built/admin/assets/activitypub/{tabs-Dc0FEEYD.js → tabs-ogqwoBlb.js} +241 -237
- package/core/built/admin/assets/activitypub/{topic-filter-CuDyM5bD.js → topic-filter-DLHBZT93.js} +4 -4
- package/core/built/admin/assets/activitypub/use-activity-pub-queries-VzbN99u_.js +1957 -0
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Drx1kdAK.js → use-navigate-with-base-path-CAwXTmqH.js} +165 -175
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-BHkCHcW5.js → use-reply-chain-data-CxonteFD.js} +8 -8
- package/core/built/admin/assets/activitypub/users-BLeiOTHc.js +1464 -0
- package/core/built/admin/assets/activitypub/{x-BHCEe-c2.js → x-C8tAnXly.js} +2 -2
- package/core/built/admin/assets/{audience-adiFehTD.js → audience-BKRdsFmy.js} +1 -1
- package/core/built/admin/assets/{automated-emails-UWM02CMr.js → automated-emails-Cn87L5Md.js} +1 -1
- package/core/built/admin/assets/automations-B7-y3dXt.js +1 -0
- package/core/built/admin/assets/automations-BP_aHamJ.js +1 -0
- package/core/built/admin/assets/{avatar-flipboard-Lz3F9fNT.js → avatar-flipboard-C6Kj3Awu.js} +1 -1
- package/core/built/admin/assets/bluesky-sharing-Bh36XPh4.js +1 -0
- package/core/built/admin/assets/box-BWbhXh21.js +1 -0
- package/core/built/admin/assets/breadcrumb-D34YWnaw.js +1 -0
- package/core/built/admin/assets/card-DGoDJzrn.js +1 -0
- package/core/built/admin/assets/{chart-ChpW-NzQ.js → chart-BuRT2Y6p.js} +14 -14
- package/core/built/admin/assets/chart-helpers-DbklaJw9.js +1 -0
- package/core/built/admin/assets/checkbox-DA4-1UiI.js +1 -0
- package/core/built/admin/assets/chunk.524.45e0875f41b71e46e849.js +25 -0
- package/core/built/admin/assets/chunk.582.51defd4b009f0de8d4d5.js +27 -0
- package/core/built/admin/assets/{chunk.831.0703a12e49f51cec3f3a.js → chunk.589.096f4d0bb775e5229aa9.js} +78 -85
- package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js → chunk.962.b73442b07be930bb5d85.js} +2216 -3188
- package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js.LICENSE.txt → chunk.962.b73442b07be930bb5d85.js.LICENSE.txt} +0 -63
- package/core/built/admin/assets/code-editor-view-BKBrkffZ.js +1 -0
- package/core/built/admin/assets/comments-CzVNIT8b.js +1 -0
- package/core/built/admin/assets/container-BYz2Ed39.js +1 -0
- package/core/built/admin/assets/data-list-16rkJYYi.js +1 -0
- package/core/built/admin/assets/date-range-select-B5vSsrpx.js +1 -0
- package/core/built/admin/assets/disabled-sources-indicator-NkOIoMue.js +1 -0
- package/core/built/admin/assets/{dist-CsekE4FL.js → dist-CQJY6SVY.js} +1 -1
- package/core/built/admin/assets/dist-DGzPJ_bO.js +4 -0
- package/core/built/admin/assets/{dist-BbGrW05X.js → dist-DyViJwIy.js} +1 -1
- package/core/built/admin/assets/dist-Ndy-PuGN.js +1 -0
- package/core/built/admin/assets/dist-P_ohUlTi.js +1 -0
- package/core/built/admin/assets/domain-B7_n5nfx.js +1 -0
- package/core/built/admin/assets/dropzone-DcuJEEUf.js +5 -0
- package/core/built/admin/assets/edit-profile-rvDGrS8J.js +1 -0
- package/core/built/admin/assets/editor-BCiIyFjm.js +8 -0
- package/core/built/admin/assets/empty-indicator-oX1u1Pkn.js +1 -0
- package/core/built/admin/assets/esm-CFX93H5M.js +2 -0
- package/core/built/admin/assets/explore-BZAZOg5X.js +1 -0
- package/core/built/admin/assets/feed-CFV8xDw9.js +1 -0
- package/core/built/admin/assets/field-BW-M2Zwp.js +1 -0
- package/core/built/admin/assets/{filter-sources-v39ihhhV.js → filter-sources-Fx8wiYYw.js} +1 -1
- package/core/built/admin/assets/filters-CGX_pf2N.js +1 -0
- package/core/built/admin/assets/filters-DtcXMZDU.js +1 -0
- package/core/built/admin/assets/framework-provider-CmtnPXIT.js +4 -0
- package/core/built/admin/assets/{ghost-b57f077997b739a8ae9a70772dc016cb.js → ghost-b1dce91ad3232cc259ee5fbbf9526243.js} +294 -290
- package/core/built/admin/assets/ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css +1 -0
- package/core/built/admin/assets/gift-link-modal-Bk8qpnMw.js +1 -0
- package/core/built/admin/assets/{gift-links-CY3GwiVi.js → gift-links-nBxJjZiQ.js} +1 -1
- package/core/built/admin/assets/growth-Ck2s3JjR.js +1 -0
- package/core/built/admin/assets/hooks-BApwwBE0.js +2 -0
- package/core/built/admin/assets/{inbox-TEISAmth.js → inbox-BRp1_aaC.js} +35 -35
- package/core/built/admin/assets/index-BBf502Wg.js +69 -0
- package/core/built/admin/assets/index-BCCZKxP2.css +1 -0
- package/core/built/admin/assets/inline-EMAm3okk.js +1 -0
- package/core/built/admin/assets/input-group-DjuYnNCd.js +1 -0
- package/core/built/admin/assets/{react-dom-C6aoWSfl.js → jsx-runtime-DX3WBWVO.js} +1 -1
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +5 -2
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +2 -2
- package/core/built/admin/assets/{koenig-lexical-Di7b48ED.js → koenig-lexical-CM7UFNdL.js} +2 -2
- package/core/built/admin/assets/kpi-card-BrGH6FsT.js +1 -0
- package/core/built/admin/assets/kpi-card-CIGyijjx.js +1 -0
- package/core/built/admin/assets/kpi-helpers-_HRRsklE.js +1 -0
- package/core/built/admin/assets/kpi-tabs-BSvh9eoq.js +1 -0
- package/core/built/admin/assets/label-BOR9XdKl.js +1 -0
- package/core/built/admin/assets/label-picker-BdNAWuUX.js +1 -0
- package/core/built/admin/assets/{labels-GbxlXWtf.js → labels-Cyayfd-e.js} +1 -1
- package/core/built/admin/assets/layout-Bw4GnxXp.js +1 -0
- package/core/built/admin/assets/limit-service-9fwD33lU.js +20 -0
- package/core/built/admin/assets/link-helpers-tOlxmuH5.js +1 -0
- package/core/built/admin/assets/list-page-B6ANtzkd.js +1 -0
- package/core/built/admin/assets/mailchimp-Ds_NQ04w.svg +9 -0
- package/core/built/admin/assets/member-custom-fields-DvFyamLu.js +1 -0
- package/core/built/admin/assets/member-detail-Cg2vTqvJ.js +1 -0
- package/core/built/admin/assets/members-DsPxYAVm.js +10 -0
- package/core/built/admin/assets/modals-Bf_fyvHZ.js +31 -0
- package/core/built/admin/assets/moderation-Dlp7M5sa.js +1 -0
- package/core/built/admin/assets/multi-select-combobox-CH1o8XXQ.js +1 -0
- package/core/built/admin/assets/newsletter-CQ5CAYUI.js +1 -0
- package/core/built/admin/assets/{newsletters-DZm3yLj8.js → newsletters-D1jbtV-h.js} +1 -1
- package/core/built/admin/assets/note-BrAZ7Z0o.js +1 -0
- package/core/built/admin/assets/notifications-BnbHLOPC.js +1 -0
- package/core/built/admin/assets/nql-lang-B7faUf8D.js +19 -0
- package/core/built/admin/assets/{offers-D11QtPXX.js → offers-CrY6nSRR.js} +1 -1
- package/core/built/admin/assets/onboarding-route-eU146kuA.js +1 -0
- package/core/built/admin/assets/overview-BpbaK-xu.js +1 -0
- package/core/built/admin/assets/page-header-C0jVxtS8.js +1 -0
- package/core/built/admin/assets/{pages-BnObVRrf.js → pages-BbNWFcGj.js} +1 -1
- package/core/built/admin/assets/pintura-CXOmq-5H.svg +15 -0
- package/core/built/admin/assets/post-analytics-Iw7dk1mT.js +1 -0
- package/core/built/admin/assets/post-analytics-header-D9pJ4iNm.js +1 -0
- package/core/built/admin/assets/{post-analytics-provider-DSfBCtnj.js → post-analytics-provider-BDqcfBor.js} +1 -1
- package/core/built/admin/assets/post-share-modal-DBfKl2GZ.js +1 -0
- package/core/built/admin/assets/{posts-CwH8VJvB.js → posts-EWpZIjkr.js} +1 -1
- package/core/built/admin/assets/preferences-D4EANGoc.js +5 -0
- package/core/built/admin/assets/profile-dJ44Bn_W.js +1 -0
- package/core/built/admin/assets/{referrers-nxR52jPI.js → referrers-BCfFYSHc.js} +1 -1
- package/core/built/admin/assets/router-provider-C1R4AZ2o.js +1 -0
- package/core/built/admin/assets/select--2uVN9_-.js +1 -0
- package/core/built/admin/assets/settings-Bz3RZRmE.js +1 -0
- package/core/built/admin/assets/settings-SD9bxIpt.js +4 -0
- package/core/built/admin/assets/share-modal-CkdTTMJd.js +1 -0
- package/core/built/admin/assets/social-urls-BvFZwYcE.js +8 -0
- package/core/built/admin/assets/sort-button-DZp9Y2r1.js +1 -0
- package/core/built/admin/assets/source-icon-CHr9qJ2Y.js +1 -0
- package/core/built/admin/assets/stack-xiN0eQ6Z.js +1 -0
- package/core/built/admin/assets/stats-DGoXZxWE.js +1 -0
- package/core/built/admin/assets/stats-view-D2-1L0ms.js +1 -0
- package/core/built/admin/assets/step-1-RdahbwyG.js +1 -0
- package/core/built/admin/assets/step-2-D83PeRwd.js +1 -0
- package/core/built/admin/assets/step-3-p_Op4wv4.js +2 -0
- package/core/built/admin/assets/switch-qp518gFQ.js +1 -0
- package/core/built/admin/assets/table-B8LgTQJZ.js +1 -0
- package/core/built/admin/assets/tabs-D3ZOYkM7.js +1 -0
- package/core/built/admin/assets/tags-B4l891z2.js +1 -0
- package/core/built/admin/assets/text-DwtjwGkh.js +1 -0
- package/core/built/admin/assets/textarea-CTlb3Uu6.js +1 -0
- package/core/built/admin/assets/{tiers-EghDzCKc.js → tiers-BgYLWRJv.js} +1 -1
- package/core/built/admin/assets/toggle-group-DNXDkAwf.js +1 -0
- package/core/built/admin/assets/topic-filter-DZGjEcz3.js +1 -0
- package/core/built/admin/assets/{use-analytics-data-0l_OHtnR.js → use-analytics-data-CaT8RirX.js} +1 -1
- package/core/built/admin/assets/use-filter-params-DeQ8sX4N.js +1 -0
- package/core/built/admin/assets/use-growth-stats-9Db2CuJe.js +1 -0
- package/core/built/admin/assets/{use-post-referrers-DwI31Ril.js → use-post-referrers-BV54YcQS.js} +1 -1
- package/core/built/admin/assets/use-reply-chain-data-DuYZGDan.js +1 -0
- package/core/built/admin/assets/use-simple-pagination-8fTua9Nt.js +1 -0
- package/core/built/admin/assets/{use-tinybird-query-DvZBBMG7.js → use-tinybird-query-Dz156HvZ.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-CQtebkvU.js → use-tinybird-token-C9RUdL_n.js} +1 -1
- package/core/built/admin/assets/{users-Pc8IRjk9.js → users-CcSCQFcQ.js} +1 -1
- package/core/built/admin/assets/virtual-list-BCvP0YF-.js +1 -0
- package/core/built/admin/assets/web-DTZnnUGr.js +1 -0
- package/core/built/admin/index.html +18 -22
- package/core/frontend/apps/private-blogging/index.js +1 -1
- package/core/frontend/apps/private-blogging/lib/middleware.js +1 -1
- package/core/frontend/helpers/split.js +2 -1
- package/core/frontend/meta/asset-url.js +1 -1
- package/core/frontend/meta/author-image.js +1 -1
- package/core/frontend/meta/blog-logo.js +1 -1
- package/core/frontend/meta/canonical-url.js +1 -1
- package/core/frontend/meta/cover-image.js +1 -1
- package/core/frontend/meta/get-meta.js +1 -1
- package/core/frontend/meta/og-image.js +1 -1
- package/core/frontend/meta/paginated-url.js +1 -1
- package/core/frontend/meta/twitter-image.js +1 -1
- package/core/frontend/meta/url.js +1 -1
- package/core/frontend/services/assets-minification/admin-auth-assets.js +1 -1
- package/core/frontend/services/llms/handler.js +1 -1
- package/core/frontend/services/proxy.js +31 -2
- package/core/frontend/services/routing/collection-router.js +1 -1
- package/core/frontend/services/routing/controllers/email-post.js +1 -1
- package/core/frontend/services/routing/controllers/entry/markdown.js +1 -1
- package/core/frontend/services/routing/controllers/entry/markdown.ts +1 -1
- package/core/frontend/services/routing/controllers/entry.js +1 -1
- package/core/frontend/services/routing/controllers/entry.ts +1 -1
- package/core/frontend/services/routing/controllers/previews.js +6 -7
- package/core/frontend/services/routing/controllers/unsubscribe.js +7 -3
- package/core/frontend/services/routing/email-router.js +1 -1
- package/core/frontend/services/routing/events.js +12 -0
- package/core/frontend/services/routing/middleware/page-param.js +1 -1
- package/core/frontend/services/routing/parent-router.js +1 -1
- package/core/frontend/services/routing/preview-router.js +1 -1
- package/core/frontend/services/routing/router-manager.js +4 -8
- package/core/frontend/services/routing/rss-router.js +1 -1
- package/core/frontend/services/routing/static-pages-router.js +1 -1
- package/core/frontend/services/routing/static-routes-router.js +1 -1
- package/core/frontend/services/routing/taxonomy-router.js +1 -1
- package/core/frontend/services/rss/generate-feed.js +1 -1
- package/core/frontend/services/sitemap/base-site-map-generator.js +23 -4
- package/core/frontend/services/sitemap/site-map-index-generator.js +1 -1
- package/core/frontend/services/sitemap/site-map-manager.js +14 -8
- package/core/frontend/services/sitemap/utils.js +1 -1
- package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +1 -1
- package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +1 -1
- package/core/frontend/utils/images.js +1 -1
- package/core/frontend/web/middleware/admin-toolbar.js +1 -1
- package/core/frontend/web/middleware/handle-image-sizes.js +2 -2
- package/core/frontend/web/middleware/redirect-ghost-to-admin.js +1 -1
- package/core/frontend/web/routers/serve-favicon.js +1 -1
- package/core/frontend/web/routers/serve-public-file.js +1 -1
- package/core/frontend/web/site.js +5 -5
- package/core/server/adapters/cache/AdapterCacheMemoryTTL.js +2 -2
- package/core/server/adapters/cache/MemoryCache.js +2 -2
- package/core/server/adapters/cache/Redis.js +1 -1
- package/core/server/adapters/cache/index.js +1 -1
- package/core/server/adapters/lib/redis/AdapterCacheRedis.js +2 -2
- package/core/server/adapters/route-settings/FileStore.js +2 -8
- package/core/server/adapters/route-settings/FileStore.ts +1 -6
- package/core/server/adapters/route-settings/S3RouteSettingsStore.js +206 -0
- package/core/server/adapters/route-settings/S3RouteSettingsStore.ts +199 -0
- package/core/server/adapters/route-settings/utils.js +13 -0
- package/core/server/adapters/route-settings/utils.ts +7 -0
- package/core/server/adapters/scheduling/deps.d.ts +0 -2
- package/core/server/adapters/scheduling/error-capture.js +76 -0
- package/core/server/adapters/scheduling/error-capture.ts +91 -0
- package/core/server/adapters/scheduling/utils.js +18 -34
- package/core/server/adapters/scheduling/utils.ts +36 -0
- package/core/server/adapters/storage/LocalFilesStorage.js +1 -1
- package/core/server/adapters/storage/LocalImagesStorage.js +1 -1
- package/core/server/adapters/storage/LocalMediaStorage.js +1 -1
- package/core/server/adapters/storage/LocalStorageBase.js +3 -3
- package/core/server/adapters/storage/S3Storage.js +2 -2
- package/core/server/adapters/storage/S3Storage.ts +1 -1
- package/core/server/adapters/storage/utils.js +1 -1
- package/core/server/api/endpoints/authentication.js +1 -1
- package/core/server/api/endpoints/featurebase.js +1 -1
- package/core/server/api/endpoints/files.js +2 -2
- package/core/server/api/endpoints/images.js +2 -2
- package/core/server/api/endpoints/libraries.d.ts +0 -1
- package/core/server/api/endpoints/media.js +8 -5
- package/core/server/api/endpoints/member-custom-fields.js +4 -1
- package/core/server/api/endpoints/member-custom-fields.ts +4 -1
- package/core/server/api/endpoints/posts.js +17 -1
- package/core/server/api/endpoints/search-index-public.js +4 -3
- package/core/server/api/endpoints/search-index.js +5 -4
- package/core/server/api/endpoints/settings-public.js +1 -1
- package/core/server/api/endpoints/settings.js +3 -1
- package/core/server/api/endpoints/utils/serializers/input/utils/url.js +9 -1
- package/core/server/api/endpoints/utils/serializers/output/default.js +7 -0
- package/core/server/api/endpoints/utils/serializers/output/files.js +1 -1
- package/core/server/api/endpoints/utils/serializers/output/media.js +1 -1
- package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +7 -4
- package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.ts +8 -4
- package/core/server/api/endpoints/utils/serializers/output/members.js +16 -26
- package/core/server/api/endpoints/utils/serializers/output/pages.js +7 -0
- package/core/server/api/endpoints/utils/serializers/output/posts.js +13 -0
- package/core/server/api/endpoints/utils/serializers/output/utils/url.js +1 -1
- package/core/server/api/endpoints/utils/validators/input/members.js +2 -52
- package/core/server/data/db/backup.js +1 -1
- package/core/server/data/importer/handlers/image.js +3 -3
- package/core/server/data/importer/import-manager.js +6 -4
- package/core/server/data/importer/importers/content-file-importer.js +2 -2
- package/core/server/data/migrations/utils/schema.js +4 -2
- package/core/server/data/migrations/versions/6.54/2026-07-19-16-59-00-add-content-import-permission.js +10 -0
- package/core/server/data/migrations/versions/6.54/2026-07-20-13-59-21-drop-email-tracked-sent-count-from-automation-action-revisions.js +7 -0
- package/core/server/data/migrations/versions/6.54/2026-07-21-01-58-20-add-automation-run-steps-poller-index.js +3 -0
- package/core/server/data/migrations/versions/6.54/2026-07-21-21-08-15-add-automated-email-recipients-mailgun-message-id-index.js +3 -0
- package/core/server/data/migrations/versions/6.54/2026-07-22-10-41-08-add-click-tracking-to-automated-email-recipients.js +13 -0
- package/core/server/data/migrations/versions/6.54/2026-07-22-15-10-30-add-email-clicked-count-to-automation-action-revisions.js +7 -0
- package/core/server/data/migrations/versions/6.54/2026-07-23-10-24-18-add-automation-action-revision-to-redirects.js +9 -0
- package/core/server/data/schema/commands.js +37 -3
- package/core/server/data/schema/fixtures/fixtures.json +7 -0
- package/core/server/data/schema/lib/default-index-name.js +20 -0
- package/core/server/data/schema/schema.js +40 -17
- package/core/server/data/seeders/data-generator.js +4 -2
- package/core/server/lib/image/image-size.js +5 -7
- package/core/server/lib/image/image-utils.js +2 -2
- package/core/server/lib/image/index.js +4 -4
- package/core/server/lib/lexical.js +3 -3
- package/core/server/lib/mobiledoc.js +2 -2
- package/core/server/lib/validate-password.js +1 -1
- package/core/server/models/action.js +9 -0
- package/core/server/models/base/plugins/generate-slug.js +1 -1
- package/core/server/models/collection.js +1 -1
- package/core/server/models/custom-theme-setting.js +1 -1
- package/core/server/models/member.js +73 -0
- package/core/server/models/newsletter.js +1 -1
- package/core/server/models/post.js +19 -5
- package/core/server/models/posts-meta.js +1 -1
- package/core/server/models/redirect.js +1 -1
- package/core/server/models/settings.js +1 -1
- package/core/server/models/snippet.js +1 -1
- package/core/server/models/tag.js +1 -1
- package/core/server/models/user.js +1 -1
- package/core/server/models/welcome-email-automated-email.js +1 -1
- package/core/server/services/activitypub/activity-pub-service-wrapper.js +1 -1
- package/core/server/services/adapter-manager/adapter-manager.js +5 -1
- package/core/server/services/adapter-manager/adapter-manager.ts +7 -2
- package/core/server/services/adapter-manager/index.js +18 -15
- package/core/server/services/adapter-manager/index.ts +23 -17
- package/core/server/services/adapter-manager/utils.js +124 -14
- package/core/server/services/adapter-manager/utils.ts +130 -14
- package/core/server/services/api-version-compatibility/mw-version-rewrites.js +1 -1
- package/core/server/services/audience-feedback/index.js +1 -1
- package/core/server/services/auth/passwordreset.js +1 -1
- package/core/server/services/auth/session/express-session.js +1 -1
- package/core/server/services/auth/session/index.js +2 -2
- package/core/server/services/auth/session/session-service.js +1 -1
- package/core/server/services/automations/automations-api.js +2 -19
- package/core/server/services/automations/automations-api.ts +2 -31
- package/core/server/services/automations/automations-repository.ts +15 -0
- package/core/server/services/automations/database-automations-repository.js +30 -2
- package/core/server/services/automations/database-automations-repository.ts +33 -2
- package/core/server/services/automations/poll.js +16 -12
- package/core/server/services/automations/poll.ts +17 -15
- package/core/server/services/automations/service.js +1 -1
- package/core/server/services/automations/service.ts +3 -13
- package/core/server/services/automations/welcome-email-automation-poll.js +2 -1
- package/core/server/services/comments/index.js +1 -1
- package/core/server/services/custom-redirects/index.js +2 -2
- package/core/server/services/email-analytics/email-analytics-service-wrapper.js +14 -13
- package/core/server/services/email-analytics/email-analytics-service.js +1 -1
- package/core/server/services/email-analytics/events/start-email-analytics-job-event.js +11 -15
- package/core/server/services/email-analytics/events/start-email-analytics-job-event.ts +15 -0
- package/core/server/services/email-analytics/index.js +2 -3
- package/core/server/services/email-analytics/index.ts +1 -2
- package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.js +1 -6
- package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.ts +0 -9
- package/core/server/services/email-analytics/jobs/fetch-latest/index.js +1 -1
- package/core/server/services/email-analytics/jobs/index.js +0 -2
- package/core/server/services/email-service/email-service-wrapper.js +1 -1
- package/core/server/services/email-service/email-service.js +20 -4
- package/core/server/services/explore-ping/explore-ping-service.js +24 -39
- package/core/server/services/explore-ping/explore-ping-service.ts +198 -0
- package/core/server/services/explore-ping/index.js +11 -11
- package/core/server/services/explore-ping/index.ts +42 -0
- package/core/server/services/gifts/gift-reminder-scheduler.js +1 -1
- package/core/server/services/gifts/gift-reminder-scheduler.ts +1 -1
- package/core/server/services/gifts/gift-service-wrapper.js +1 -1
- package/core/server/services/identity-tokens/identity-token-service-wrapper.js +1 -1
- package/core/server/services/indexnow-ping/constants.js +30 -0
- package/core/server/services/indexnow-ping/constants.ts +32 -0
- package/core/server/services/indexnow-ping/index.js +29 -253
- package/core/server/services/indexnow-ping/index.ts +37 -0
- package/core/server/services/indexnow-ping/indexnow-ping-service.js +229 -0
- package/core/server/services/indexnow-ping/indexnow-ping-service.ts +319 -0
- package/core/server/services/invites/index.js +1 -1
- package/core/server/services/lib/mailgun-client.js +3 -3
- package/core/server/services/link-redirection/index.js +2 -2
- package/core/server/services/link-redirection/link-redirect-repository.js +1 -1
- package/core/server/services/link-redirection/link-redirect.js +12 -13
- package/core/server/services/link-redirection/link-redirect.ts +22 -0
- package/core/server/services/link-redirection/link-redirects-service.js +1 -1
- package/core/server/services/link-tracking/full-post-link.js +2 -2
- package/core/server/services/link-tracking/index.js +1 -1
- package/core/server/services/mail/ghost-mailer.js +1 -1
- package/core/server/services/mail/index.js +1 -1
- package/core/server/services/media-inliner/external-media-inliner.js +2 -2
- package/core/server/services/media-inliner/service.js +4 -3
- package/core/server/services/member-attribution/index.js +1 -1
- package/core/server/services/member-welcome-emails/service.js +1 -1
- package/core/server/services/members/api.js +8 -2
- package/core/server/services/members/csv/index.js +10 -0
- package/core/server/services/members/csv/index.ts +3 -0
- package/core/server/services/members/csv/parse.js +94 -0
- package/core/server/services/members/csv/parse.ts +111 -0
- package/core/server/services/members/csv/types.js +2 -0
- package/core/server/services/members/csv/types.ts +39 -0
- package/core/server/services/members/csv/unparse.js +69 -0
- package/core/server/services/members/csv/unparse.ts +79 -0
- package/core/server/services/members/exporter/query.js +35 -8
- package/core/server/services/members/importer/config.js +35 -0
- package/core/server/services/members/importer/config.ts +39 -0
- package/core/server/services/members/importer/members-csv-importer.js +31 -13
- package/core/server/services/members/members-api/members-api.js +4 -2
- package/core/server/services/members/members-api/repositories/event-repository.js +13 -2
- package/core/server/services/members/members-api/services/member-bread-service.js +42 -19
- package/core/server/services/members/middleware.js +1 -1
- package/core/server/services/members/service.js +15 -2
- package/core/server/services/members/stripe-connect.js +1 -1
- package/core/server/services/members-custom-fields/actions.js +3 -0
- package/core/server/services/members-custom-fields/actions.ts +6 -2
- package/core/server/services/members-custom-fields/config.js +34 -0
- package/core/server/services/members-custom-fields/config.ts +38 -0
- package/core/server/services/members-custom-fields/definitions-service.js +156 -21
- package/core/server/services/members-custom-fields/definitions-service.ts +170 -25
- package/core/server/services/members-custom-fields/index.js +16 -3
- package/core/server/services/members-custom-fields/index.ts +17 -3
- package/core/server/services/members-custom-fields/values-service.js +56 -10
- package/core/server/services/members-custom-fields/values-service.ts +62 -10
- package/core/server/services/mentions/mention-sending-service.js +22 -2
- package/core/server/services/mentions/service.js +21 -5
- package/core/server/services/newsletters/index.js +1 -1
- package/core/server/services/oembed/oembed-service.js +122 -33
- package/core/server/services/oembed/service.js +4 -2
- package/core/server/services/offers/service.js +1 -1
- package/core/server/services/post-scheduling/index.js +4 -3
- package/core/server/services/post-scheduling/index.ts +4 -3
- package/core/server/services/post-scheduling/post-scheduling.js +1 -1
- package/core/server/services/post-scheduling/post-scheduling.ts +1 -1
- package/core/server/services/posts/post-email-handler.js +13 -6
- package/core/server/services/posts/post-scheduling.js +1 -1
- package/core/server/services/posts/posts-service-instance.js +1 -1
- package/core/server/services/posts/posts-service.js +2 -2
- package/core/server/services/posts-public/service.js +1 -1
- package/core/server/services/public-config/site.js +1 -1
- package/core/server/services/recommendations/recommendation-service-wrapper.js +1 -1
- package/core/server/services/recommendations/service/libraries.d.ts +0 -2
- package/core/server/services/route-settings/dynamic-routing-service.js +2 -3
- package/core/server/services/route-settings/index.js +1 -1
- package/core/server/services/route-settings/route-settings-parser.js +134 -124
- package/core/server/services/route-settings/route-settings-parser.ts +160 -125
- package/core/server/services/route-settings/validation-errors.js +178 -0
- package/core/server/services/route-settings/validation-errors.ts +196 -0
- package/core/server/services/settings/settings-service.js +2 -2
- package/core/server/services/settings-helpers/index.js +1 -1
- package/core/server/services/slack-notifications/service.js +1 -1
- package/core/server/services/slack-ping/constants.js +16 -0
- package/core/server/services/slack-ping/constants.ts +15 -0
- package/core/server/services/slack-ping/index.js +26 -204
- package/core/server/services/slack-ping/index.ts +35 -0
- package/core/server/services/slack-ping/slack-ping-service.js +214 -0
- package/core/server/services/slack-ping/slack-ping-service.ts +296 -0
- package/core/server/services/staff/index.js +1 -1
- package/core/server/services/stats/posts-stats-service.js +1 -1
- package/core/server/services/stats/service.js +1 -1
- package/core/server/services/stripe/service.js +1 -1
- package/core/server/services/tags-public/service.js +1 -1
- package/core/server/services/themes/validate.js +1 -1
- package/core/server/services/update-check/index.js +1 -1
- package/core/server/services/url/lazy-url-service.js +66 -6
- package/core/server/services/url/lazy-url-service.ts +73 -6
- package/core/server/services/url/url-generator.js +1 -1
- package/core/server/services/url/url-service-facade.js +68 -3
- package/core/server/services/url/url-service-facade.ts +79 -4
- package/core/server/services/url/url-service.js +1 -1
- package/core/server/services/url/urls.js +1 -1
- package/core/server/services/webhooks/index.js +19 -2
- package/core/server/services/webhooks/listen.js +6 -11
- package/core/server/services/webhooks/payload.js +1 -3
- package/core/server/services/webhooks/serialize.js +16 -1
- package/core/server/web/admin/app.js +1 -1
- package/core/server/web/admin/middleware/redirect-admin-urls.js +1 -1
- package/core/server/web/api/endpoints/admin/routes.js +1 -0
- package/core/server/web/api/middleware/cors.js +1 -1
- package/core/server/web/api/middleware/upload.js +4 -0
- package/core/server/web/gift-preview/controller.js +1 -1
- package/core/server/web/shared/middleware/redirect-amp-urls.js +1 -1
- package/core/server/web/shared/middleware/uncapitalise.js +2 -2
- package/core/server/web/shared/middleware/url-redirects.js +1 -1
- package/core/shared/config/defaults.json +8 -1
- package/core/shared/config/overrides.json +4 -0
- package/core/shared/url-utils.js +19 -15
- package/core/shared/url-utils.ts +20 -0
- package/ghost.js +0 -1
- package/package.json +26 -31
- package/pnpm-lock.yaml +681 -2789
- package/pnpm-workspace.yaml +31 -17
- package/components/tryghost-adapter-base-scheduling-0.0.0.tgz +0 -0
- package/components/tryghost-adapter-base-sso-0.0.0.tgz +0 -0
- package/core/built/admin/assets/Combination--5EZGaDs.js +0 -43
- package/core/built/admin/assets/Growth-C0NoKcHQ.js +0 -3
- package/core/built/admin/assets/Newsletters-Ed8kDjdy.js +0 -1
- package/core/built/admin/assets/Overview-CArPgRZt.js +0 -1
- package/core/built/admin/assets/Web-CjjYoVM3.js +0 -2
- package/core/built/admin/assets/account-migration-mfa5mNI9.js +0 -1
- package/core/built/admin/assets/activitypub/inbox-B3rjKMTv.js +0 -1221
- package/core/built/admin/assets/activitypub/layout-jcurg3rU.js +0 -1
- package/core/built/admin/assets/activitypub/use-activity-pub-queries-yqGRcnLn.js +0 -2569
- package/core/built/admin/assets/activitypub/users-CfyHIsTG.js +0 -1316
- package/core/built/admin/assets/automations-DkUnxNdv.js +0 -1
- package/core/built/admin/assets/automations-vjXofmV_.js +0 -1
- package/core/built/admin/assets/bluesky-sharing-T-pO3RcP.js +0 -1
- package/core/built/admin/assets/breadcrumb-CekPYTCn.js +0 -1
- package/core/built/admin/assets/button--i2uMDDn.js +0 -4
- package/core/built/admin/assets/card-CSWz_BXq.js +0 -1
- package/core/built/admin/assets/chart-helpers-C_4Ka_vT.js +0 -1
- package/core/built/admin/assets/chunk.524.8ce2c741473e2f0929dc.js +0 -25
- package/core/built/admin/assets/chunk.582.453459d6228d2955408b.js +0 -27
- package/core/built/admin/assets/code-editor-view-BfkwQto2.js +0 -1
- package/core/built/admin/assets/command-K75Jzs0G.js +0 -1
- package/core/built/admin/assets/comments-BEIi1DH-.js +0 -1
- package/core/built/admin/assets/container-BNXvlcjA.js +0 -1
- package/core/built/admin/assets/data-list-BmK5QMab.js +0 -1
- package/core/built/admin/assets/date-range-select-5sKzwbt7.js +0 -1
- package/core/built/admin/assets/disabled-sources-indicator-L_ssJTNr.js +0 -1
- package/core/built/admin/assets/dist-BBIJuyPg.js +0 -1
- package/core/built/admin/assets/dist-BHE0dp6o.js +0 -1
- package/core/built/admin/assets/dist-DJ6c4_De.js +0 -1
- package/core/built/admin/assets/dist-DW0QXQO3.js +0 -1
- package/core/built/admin/assets/dist-DxFLceO5.js +0 -1
- package/core/built/admin/assets/dist-QcACAOAD.js +0 -1
- package/core/built/admin/assets/dist-duxRDcQu.js +0 -177
- package/core/built/admin/assets/domain-CLaPZ9Rc.js +0 -1
- package/core/built/admin/assets/dropzone-E0bSX4_a.js +0 -5
- package/core/built/admin/assets/edit-profile-DqNPKaA4.js +0 -1
- package/core/built/admin/assets/editor-CkLXQDRp.js +0 -8
- package/core/built/admin/assets/empty-indicator-BTtOlgIo.js +0 -1
- package/core/built/admin/assets/esm-TSfGW7nz.js +0 -2
- package/core/built/admin/assets/explore-BEstLxKr.js +0 -1
- package/core/built/admin/assets/feed-C58p2voG.js +0 -1
- package/core/built/admin/assets/field-BSbDUHPv.js +0 -1
- package/core/built/admin/assets/filters-BgYv8Gt7.js +0 -1
- package/core/built/admin/assets/filters-DvenFkmK.js +0 -1
- package/core/built/admin/assets/framework-provider-jQktxm9P.js +0 -4
- package/core/built/admin/assets/ghost-dark-8590dea6cd695ff90f27d262c4464538.css +0 -1
- package/core/built/admin/assets/gift-link-modal-BPjXkEFt.js +0 -1
- package/core/built/admin/assets/growth-D4JNiVTe.js +0 -1
- package/core/built/admin/assets/hooks-Cjxexi_I.js +0 -2
- package/core/built/admin/assets/index-BacwlcOy.js +0 -67
- package/core/built/admin/assets/index-DxRNHH0o.css +0 -1
- package/core/built/admin/assets/inline-C22rnPro.js +0 -1
- package/core/built/admin/assets/input-group-CKfrILLP.js +0 -1
- package/core/built/admin/assets/jsx-runtime-CtMZ-PAS.js +0 -1
- package/core/built/admin/assets/kpi-card-DZxQKAIb.js +0 -1
- package/core/built/admin/assets/kpi-card-FidQ5zg3.js +0 -1
- package/core/built/admin/assets/kpi-helpers-C5T8Vaf1.js +0 -1
- package/core/built/admin/assets/kpi-tabs-_VRK6hGV.js +0 -1
- package/core/built/admin/assets/label-Cza7hPgn.js +0 -1
- package/core/built/admin/assets/label-picker-DgC_zLaw.js +0 -1
- package/core/built/admin/assets/layout-BxsXnKFX.js +0 -1
- package/core/built/admin/assets/limit-service-CTurluJQ.js +0 -20
- package/core/built/admin/assets/link-helpers-C3Gqy2cz.js +0 -1
- package/core/built/admin/assets/list-page-BtqCnow_.js +0 -1
- package/core/built/admin/assets/member-custom-fields-9uXFBqSt.js +0 -1
- package/core/built/admin/assets/member-detail-Dq6ZDIxo.js +0 -1
- package/core/built/admin/assets/members-CUWD9jal.js +0 -10
- package/core/built/admin/assets/modals-CIdwHVga.js +0 -31
- package/core/built/admin/assets/moderation-DTt04UDA.js +0 -1
- package/core/built/admin/assets/newsletter-cC8vcc9h.js +0 -1
- package/core/built/admin/assets/note-DZU0IY9e.js +0 -1
- package/core/built/admin/assets/notifications-NoHpBHJ4.js +0 -1
- package/core/built/admin/assets/nql-lang-CvCSOQG3.js +0 -19
- package/core/built/admin/assets/onboarding-route-Deg2hNm8.js +0 -1
- package/core/built/admin/assets/overview-BQPt_9w3.js +0 -1
- package/core/built/admin/assets/page-header-D6bEqPo2.js +0 -1
- package/core/built/admin/assets/post-analytics-header-BPw_B2_D.js +0 -1
- package/core/built/admin/assets/post-analytics-kp2_--XO.js +0 -1
- package/core/built/admin/assets/post-share-modal-Cave3Z4W.js +0 -1
- package/core/built/admin/assets/preferences-C7h3j_uy.js +0 -5
- package/core/built/admin/assets/profile-B2x4q2oB.js +0 -1
- package/core/built/admin/assets/router-provider-5fsX1CYn.js +0 -1
- package/core/built/admin/assets/select-PhPjIBBT.js +0 -1
- package/core/built/admin/assets/settings-D5P9Gwgo.js +0 -6
- package/core/built/admin/assets/settings-zUOzQV5I.js +0 -1
- package/core/built/admin/assets/share-modal-EfpfbuWF.js +0 -1
- package/core/built/admin/assets/social-urls-DgAF08Xc.js +0 -18
- package/core/built/admin/assets/sort-button-WOQYJm2H.js +0 -1
- package/core/built/admin/assets/source-icon-hm8Cj-Gx.js +0 -1
- package/core/built/admin/assets/stats-CnQDb62m.js +0 -1
- package/core/built/admin/assets/stats-view-CCfTJgSe.js +0 -1
- package/core/built/admin/assets/step-1-BGlhY4DS.js +0 -1
- package/core/built/admin/assets/step-2-D3sDEyFH.js +0 -1
- package/core/built/admin/assets/step-3-CvZoUdsc.js +0 -2
- package/core/built/admin/assets/switch-CNjkOmwz.js +0 -1
- package/core/built/admin/assets/table-C5nZYPnW.js +0 -1
- package/core/built/admin/assets/tabs-dtOcExye.js +0 -1
- package/core/built/admin/assets/tags-Dhm0FB_g.js +0 -1
- package/core/built/admin/assets/textarea-CeKw3wmV.js +0 -1
- package/core/built/admin/assets/toggle-group-DfhZIMTW.js +0 -1
- package/core/built/admin/assets/topic-filter-Cxe1Il41.js +0 -1
- package/core/built/admin/assets/typeof-Ca-duI-z.js +0 -1
- package/core/built/admin/assets/use-filter-params-Bub6BqNy.js +0 -1
- package/core/built/admin/assets/use-growth-stats-BJORomv0.js +0 -1
- package/core/built/admin/assets/use-reply-chain-data-B89YjVoo.js +0 -1
- package/core/built/admin/assets/use-simple-pagination-BL2SYXKi.js +0 -1
- package/core/built/admin/assets/virtual-list-DNJOSK9I.js +0 -1
- package/core/built/admin/assets/web-BHUE3YQc.js +0 -1
- package/core/server/adapters/scheduling/scheduling-base.js +0 -5
- package/core/server/adapters/sso/SSOBase.js +0 -5
- package/core/server/adapters/storage/index.js +0 -17
|
@@ -2,7 +2,7 @@ const moment = require('moment-timezone');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const metrics = require('@tryghost/metrics');
|
|
5
|
-
const membersCSV = require('
|
|
5
|
+
const membersCSV = require('../csv');
|
|
6
6
|
const errors = require('@tryghost/errors');
|
|
7
7
|
const tpl = require('@tryghost/tpl');
|
|
8
8
|
const emailTemplate = require('./email-template');
|
|
@@ -61,9 +61,10 @@ module.exports = class MembersCSVImporter {
|
|
|
61
61
|
/**
|
|
62
62
|
* @param {MembersCSVImporterOptions} options
|
|
63
63
|
*/
|
|
64
|
-
constructor({storagePath, getTimezone, getMembersRepository, getDefaultTier, getTierByName, getGiftService, sendEmail, isSet, addJob, knex, urlFor, context, stripeUtils}) {
|
|
64
|
+
constructor({storagePath, getTimezone, getInlineThreshold, getMembersRepository, getDefaultTier, getTierByName, getGiftService, sendEmail, isSet, addJob, knex, urlFor, context, stripeUtils}) {
|
|
65
65
|
this._storagePath = storagePath;
|
|
66
66
|
this._getTimezone = getTimezone;
|
|
67
|
+
this._getInlineThreshold = getInlineThreshold;
|
|
67
68
|
this._getMembersRepository = getMembersRepository;
|
|
68
69
|
this._getDefaultTier = getDefaultTier;
|
|
69
70
|
this._getTierByName = getTierByName;
|
|
@@ -87,11 +88,10 @@ module.exports = class MembersCSVImporter {
|
|
|
87
88
|
*
|
|
88
89
|
* @param {string} inputFilePath - The path to the CSV to prepare
|
|
89
90
|
* @param {Object.<string, string>} [headerMapping] - An object whose keys are headers in the input CSV and values are the header to replace it with
|
|
90
|
-
* @param {Array<string>} [defaultLabels] - A list of labels to apply to every member
|
|
91
91
|
*
|
|
92
92
|
* @returns {Promise<{filePath: string, batches: number, metadata: Object.<string, any>}>} - A promise resolving to the data including filePath of "prepared" CSV
|
|
93
93
|
*/
|
|
94
|
-
async prepare(inputFilePath, headerMapping
|
|
94
|
+
async prepare(inputFilePath, headerMapping) {
|
|
95
95
|
headerMapping = headerMapping || DEFAULT_CSV_HEADER_MAPPING;
|
|
96
96
|
// @NOTE: investigate why is it "1" and do we even need this concept anymore?
|
|
97
97
|
const batchSize = 1;
|
|
@@ -108,10 +108,16 @@ module.exports = class MembersCSVImporter {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
// completely rely on explicit user input for header mappings
|
|
111
|
-
const rows = await membersCSV.parse(inputFilePath, headerMapping
|
|
112
|
-
|
|
111
|
+
const rows = await membersCSV.parse(inputFilePath, headerMapping);
|
|
112
|
+
// Columns come from every row, not the first. A row with fewer fields than
|
|
113
|
+
// the header parses to fewer keys, so reading the schema off one row drops
|
|
114
|
+
// the columns it happened to omit for the whole file. A file of headers and
|
|
115
|
+
// no rows has no columns, and serialising nothing has nothing to say.
|
|
116
|
+
const columns = [...new Set(rows.flatMap(row => Object.keys(row)))];
|
|
113
117
|
const numberOfBatches = Math.ceil(rows.length / batchSize);
|
|
114
|
-
|
|
118
|
+
// No formula escaping: this file is only ever read back by the import, not
|
|
119
|
+
// opened by a person, and escaping would be stored on the member verbatim.
|
|
120
|
+
const mappedCSV = columns.length ? membersCSV.unparse(rows, columns, {escapeFormulae: false}) : '';
|
|
115
121
|
|
|
116
122
|
const hasStripeData = !!(rows.find(function rowHasStripeData(row) {
|
|
117
123
|
return !!row.stripe_customer_id;
|
|
@@ -133,8 +139,17 @@ module.exports = class MembersCSVImporter {
|
|
|
133
139
|
*
|
|
134
140
|
* @param {string} filePath - the path to a "prepared" CSV file
|
|
135
141
|
*/
|
|
136
|
-
async perform(filePath) {
|
|
142
|
+
async perform(filePath, globalLabels = []) {
|
|
137
143
|
const performStart = Date.now();
|
|
144
|
+
// Copied per row, not shared: the member model stamps ids and trims names onto
|
|
145
|
+
// label objects in place, one of these is the caller's import label that
|
|
146
|
+
// process() looks up again once the import finishes, and each row runs in its
|
|
147
|
+
// own transaction that can roll back.
|
|
148
|
+
const cloneGlobalLabels = () => (globalLabels || [])
|
|
149
|
+
.map(label => (typeof label === 'string' ? {name: label} : {...label}))
|
|
150
|
+
// A caller can hand in a nameless label; the model would drop it, but the
|
|
151
|
+
// round-trip this replaced dropped it before the model ever saw it.
|
|
152
|
+
.filter(label => label.name);
|
|
138
153
|
const rows = await membersCSV.parse(filePath, DEFAULT_CSV_HEADER_MAPPING);
|
|
139
154
|
|
|
140
155
|
const defaultTier = await this._getDefaultTier();
|
|
@@ -182,7 +197,10 @@ module.exports = class MembersCSVImporter {
|
|
|
182
197
|
note: row.note,
|
|
183
198
|
subscribed: row.subscribed,
|
|
184
199
|
created_at: createdAt,
|
|
185
|
-
labels
|
|
200
|
+
// Form labels are applied here rather than folded into the parsed
|
|
201
|
+
// rows, so a name that contains a comma does not go through the
|
|
202
|
+
// prepared file's comma-separated labels column and split in two.
|
|
203
|
+
labels: [...row.labels, ...cloneGlobalLabels()]
|
|
186
204
|
};
|
|
187
205
|
const existingMember = await membersRepository.get({email: memberValues.email}, {
|
|
188
206
|
...options,
|
|
@@ -419,12 +437,12 @@ module.exports = class MembersCSVImporter {
|
|
|
419
437
|
*/
|
|
420
438
|
async process({pathToCSV, headerMapping, globalLabels, importLabel, user, LabelModel, forceInline, verificationTrigger}) {
|
|
421
439
|
const meta = {};
|
|
422
|
-
const job = await this.prepare(pathToCSV, headerMapping
|
|
440
|
+
const job = await this.prepare(pathToCSV, headerMapping);
|
|
423
441
|
|
|
424
442
|
meta.originalImportSize = job.batches;
|
|
425
443
|
|
|
426
|
-
if ((job.batches <=
|
|
427
|
-
const result = await this.perform(job.filePath);
|
|
444
|
+
if ((job.batches <= this._getInlineThreshold() && !job.metadata.hasStripeData) || forceInline) {
|
|
445
|
+
const result = await this.perform(job.filePath, globalLabels);
|
|
428
446
|
const importLabelModel = result.imported ? await LabelModel.findOne(importLabel) : null;
|
|
429
447
|
await verificationTrigger.testImportThreshold();
|
|
430
448
|
|
|
@@ -442,7 +460,7 @@ module.exports = class MembersCSVImporter {
|
|
|
442
460
|
this._addJob({
|
|
443
461
|
job: async () => {
|
|
444
462
|
try {
|
|
445
|
-
const result = await this.perform(job.filePath);
|
|
463
|
+
const result = await this.perform(job.filePath, globalLabels);
|
|
446
464
|
const importLabelModel = result.imported ? await LabelModel.findOne(importLabel) : null;
|
|
447
465
|
const emailContent = this.generateCompletionEmail(result, {
|
|
448
466
|
emailRecipient,
|
|
@@ -81,10 +81,11 @@ module.exports = function MembersAPI({
|
|
|
81
81
|
sentry,
|
|
82
82
|
settingsHelpers,
|
|
83
83
|
urlUtils,
|
|
84
|
+
urlService,
|
|
84
85
|
commentsService,
|
|
85
86
|
emailAddressService,
|
|
86
87
|
giftService,
|
|
87
|
-
|
|
88
|
+
customFieldValues
|
|
88
89
|
}) {
|
|
89
90
|
const tokenService = new TokenService({
|
|
90
91
|
privateKey,
|
|
@@ -123,6 +124,7 @@ module.exports = function MembersAPI({
|
|
|
123
124
|
});
|
|
124
125
|
|
|
125
126
|
const eventRepository = new EventRepository({
|
|
127
|
+
urlService,
|
|
126
128
|
DonationPaymentEvent,
|
|
127
129
|
EmailRecipient,
|
|
128
130
|
MemberSubscribeEvent,
|
|
@@ -167,7 +169,7 @@ module.exports = function MembersAPI({
|
|
|
167
169
|
nextPaymentCalculator,
|
|
168
170
|
commentsService,
|
|
169
171
|
giftService,
|
|
170
|
-
|
|
172
|
+
customFieldValues
|
|
171
173
|
});
|
|
172
174
|
|
|
173
175
|
const geolocationService = new GeolocationService();
|
|
@@ -34,6 +34,7 @@ module.exports = class EventRepository {
|
|
|
34
34
|
Comment,
|
|
35
35
|
labsService,
|
|
36
36
|
memberAttributionService,
|
|
37
|
+
urlService,
|
|
37
38
|
MemberEmailChangeEvent,
|
|
38
39
|
AutomatedEmailRecipient,
|
|
39
40
|
Gift
|
|
@@ -47,6 +48,7 @@ module.exports = class EventRepository {
|
|
|
47
48
|
this._EmailRecipient = EmailRecipient;
|
|
48
49
|
this._Comment = Comment;
|
|
49
50
|
this._labsService = labsService;
|
|
51
|
+
this._urlService = urlService;
|
|
50
52
|
this._MemberCreatedEvent = MemberCreatedEvent;
|
|
51
53
|
this._SubscriptionCreatedEvent = SubscriptionCreatedEvent;
|
|
52
54
|
this._MemberLinkClickEvent = MemberLinkClickEvent;
|
|
@@ -59,6 +61,12 @@ module.exports = class EventRepository {
|
|
|
59
61
|
this._knex = db.knex;
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
// the URL service needs the attributed post's relations (e.g. tags for a
|
|
65
|
+
// tag-filtered collection) to build its URL; prefix them onto the eager-load
|
|
66
|
+
#attributionPostRelations(prefix) {
|
|
67
|
+
return this._urlService.getRequiredRelations().map(relation => `${prefix}.${relation}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
62
70
|
async getEventTimeline(options = {}) {
|
|
63
71
|
if (!options.limit) {
|
|
64
72
|
options.limit = 10;
|
|
@@ -213,6 +221,7 @@ module.exports = class EventRepository {
|
|
|
213
221
|
withRelated: [
|
|
214
222
|
'member',
|
|
215
223
|
'subscriptionCreatedEvent.postAttribution',
|
|
224
|
+
...this.#attributionPostRelations('subscriptionCreatedEvent.postAttribution'),
|
|
216
225
|
'subscriptionCreatedEvent.userAttribution',
|
|
217
226
|
'subscriptionCreatedEvent.tagAttribution',
|
|
218
227
|
'subscriptionCreatedEvent.memberCreatedEvent',
|
|
@@ -343,6 +352,7 @@ module.exports = class EventRepository {
|
|
|
343
352
|
withRelated: [
|
|
344
353
|
'member',
|
|
345
354
|
'postAttribution',
|
|
355
|
+
...this.#attributionPostRelations('postAttribution'),
|
|
346
356
|
'userAttribution',
|
|
347
357
|
'tagAttribution',
|
|
348
358
|
'signupStatusEvent'
|
|
@@ -402,6 +412,7 @@ module.exports = class EventRepository {
|
|
|
402
412
|
withRelated: [
|
|
403
413
|
'member',
|
|
404
414
|
'postAttribution',
|
|
415
|
+
...this.#attributionPostRelations('postAttribution'),
|
|
405
416
|
'userAttribution',
|
|
406
417
|
'tagAttribution'
|
|
407
418
|
],
|
|
@@ -591,7 +602,7 @@ module.exports = class EventRepository {
|
|
|
591
602
|
async getCommentEvents(options = {}, filter) {
|
|
592
603
|
options = {
|
|
593
604
|
...options,
|
|
594
|
-
withRelated: ['member', 'post', 'post
|
|
605
|
+
withRelated: ['member', 'post', ...this.#attributionPostRelations('post'), 'parent'],
|
|
595
606
|
filter: 'member_id:-null+custom:true',
|
|
596
607
|
useBasicCount: true,
|
|
597
608
|
mongoTransformer: chainTransformers(
|
|
@@ -625,7 +636,7 @@ module.exports = class EventRepository {
|
|
|
625
636
|
async getClickEvents(options = {}, filter) {
|
|
626
637
|
options = {
|
|
627
638
|
...options,
|
|
628
|
-
withRelated: ['member', 'link', 'link.post', 'link.post
|
|
639
|
+
withRelated: ['member', 'link', 'link.post', ...this.#attributionPostRelations('link.post')],
|
|
629
640
|
filter: 'custom:true',
|
|
630
641
|
useBasicCount: true,
|
|
631
642
|
mongoTransformer: chainTransformers(
|
|
@@ -6,7 +6,8 @@ const moment = require('moment');
|
|
|
6
6
|
const messages = {
|
|
7
7
|
stripeNotConnected: 'Missing Stripe connection.',
|
|
8
8
|
memberAlreadyExists: 'Member already exists.',
|
|
9
|
-
memberNotFound: 'Member not found.'
|
|
9
|
+
memberNotFound: 'Member not found.',
|
|
10
|
+
customFieldsOnAdd: 'Custom field values cannot be set while creating a member. Create the member, then set values with an edit.'
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
// Stored in the action's `context.action_name`; Admin maps it to a display label.
|
|
@@ -36,15 +37,6 @@ const CUSTOM_FIELDS_EDITED_ACTION = 'custom_fields_edited';
|
|
|
36
37
|
* @prop {{getActiveByMembers: (memberIds: string[]) => Promise<Map<string, {cadence: 'month' | 'year', currency: string, amount: number}>>}} service
|
|
37
38
|
*/
|
|
38
39
|
|
|
39
|
-
/**
|
|
40
|
-
* @typedef {object} ICustomFieldsServiceWrapper
|
|
41
|
-
* @prop {{
|
|
42
|
-
* getValuesForMembers: (memberIds: string[]) => Promise<Map<string, Record<string, unknown>>>,
|
|
43
|
-
* planWrite: (values: unknown) => Promise<object[]>,
|
|
44
|
-
* applyWrite: (memberId: string, writes: object[]) => Promise<void>
|
|
45
|
-
* }} values
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
40
|
module.exports = class MemberBREADService {
|
|
49
41
|
/**
|
|
50
42
|
* @param {object} deps
|
|
@@ -58,9 +50,9 @@ module.exports = class MemberBREADService {
|
|
|
58
50
|
* @param {import('../../../settings-helpers/settings-helpers')} deps.settingsHelpers
|
|
59
51
|
* @param {import('./next-payment-calculator')} deps.nextPaymentCalculator
|
|
60
52
|
* @param {IGiftServiceWrapper} deps.giftService
|
|
61
|
-
* @param {
|
|
53
|
+
* @param {import('../../../members-custom-fields/values-service').CustomFieldValuesService} deps.customFieldValues Required: boot builds it before the members service
|
|
62
54
|
*/
|
|
63
|
-
constructor({memberRepository, labsService, emailService, stripeService, offersAPI, memberAttributionService, emailSuppressionList, settingsHelpers, nextPaymentCalculator, commentsService, giftService,
|
|
55
|
+
constructor({memberRepository, labsService, emailService, stripeService, offersAPI, memberAttributionService, emailSuppressionList, settingsHelpers, nextPaymentCalculator, commentsService, giftService, customFieldValues}) {
|
|
64
56
|
this.offersAPI = offersAPI;
|
|
65
57
|
/** @private */
|
|
66
58
|
this.memberRepository = memberRepository;
|
|
@@ -83,7 +75,7 @@ module.exports = class MemberBREADService {
|
|
|
83
75
|
/** @private */
|
|
84
76
|
this.giftService = giftService;
|
|
85
77
|
/** @private */
|
|
86
|
-
this.
|
|
78
|
+
this.customFieldValues = customFieldValues;
|
|
87
79
|
}
|
|
88
80
|
|
|
89
81
|
/**
|
|
@@ -112,7 +104,7 @@ module.exports = class MemberBREADService {
|
|
|
112
104
|
return null;
|
|
113
105
|
}
|
|
114
106
|
|
|
115
|
-
return this.
|
|
107
|
+
return this.customFieldValues.getValuesForMembers(memberIds);
|
|
116
108
|
}
|
|
117
109
|
|
|
118
110
|
/**
|
|
@@ -444,7 +436,36 @@ module.exports = class MemberBREADService {
|
|
|
444
436
|
return member;
|
|
445
437
|
}
|
|
446
438
|
|
|
439
|
+
/**
|
|
440
|
+
* @private
|
|
441
|
+
* The write-side flag gate, paired with `fetchCustomFieldValues` on the read
|
|
442
|
+
* side. The schema declares `custom_fields` for every site, so the key arrives
|
|
443
|
+
* whether or not the feature is on and this is what decides it goes no further.
|
|
444
|
+
* @param {object} data
|
|
445
|
+
*/
|
|
446
|
+
dropCustomFieldsWhenDisabled(data) {
|
|
447
|
+
if (!this.labsService.isSet('membersCustomFields')) {
|
|
448
|
+
delete data.custom_fields;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
447
452
|
async add(data, options) {
|
|
453
|
+
this.dropCustomFieldsWhenDisabled(data);
|
|
454
|
+
|
|
455
|
+
// Values cannot be set on create, only on a subsequent edit. `namesValues`
|
|
456
|
+
// both judges the body and rejects a malformed one, so a body refused here is
|
|
457
|
+
// refused on edit for the same reason.
|
|
458
|
+
if (this.customFieldValues.namesValues(data.custom_fields)) {
|
|
459
|
+
throw new errors.ValidationError({
|
|
460
|
+
message: tpl(messages.customFieldsOnAdd),
|
|
461
|
+
property: 'custom_fields'
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Not a member column, so it comes off before the repository sees it. Only
|
|
466
|
+
// an absent key or one naming no values gets this far.
|
|
467
|
+
delete data.custom_fields;
|
|
468
|
+
|
|
448
469
|
if (!this.stripeService.configured && (data.comped || data.stripe_customer_id)) {
|
|
449
470
|
const property = data.comped ? 'comped' : 'stripe_customer_id';
|
|
450
471
|
throw new errors.ValidationError({
|
|
@@ -527,10 +548,12 @@ module.exports = class MemberBREADService {
|
|
|
527
548
|
async edit(data, options) {
|
|
528
549
|
delete data.last_seen_at;
|
|
529
550
|
|
|
551
|
+
this.dropCustomFieldsWhenDisabled(data);
|
|
552
|
+
|
|
530
553
|
// Values live in their own table, so they come off the member data before
|
|
531
|
-
// the repository sees it — `custom_fields` is not a member column.
|
|
532
|
-
//
|
|
533
|
-
//
|
|
554
|
+
// the repository sees it — `custom_fields` is not a member column. The gate
|
|
555
|
+
// above has already dropped it when the feature is off, so by this point its
|
|
556
|
+
// presence is the signal to write.
|
|
534
557
|
const customFields = data.custom_fields;
|
|
535
558
|
const writeCustomFields = customFields !== undefined;
|
|
536
559
|
delete data.custom_fields;
|
|
@@ -540,7 +563,7 @@ module.exports = class MemberBREADService {
|
|
|
540
563
|
// plan to apply once below, so the values aren't resolved and validated
|
|
541
564
|
// twice.
|
|
542
565
|
const plannedCustomFields = writeCustomFields
|
|
543
|
-
? await this.
|
|
566
|
+
? await this.customFieldValues.planWrite(customFields)
|
|
544
567
|
: null;
|
|
545
568
|
|
|
546
569
|
let model;
|
|
@@ -589,7 +612,7 @@ module.exports = class MemberBREADService {
|
|
|
589
612
|
}
|
|
590
613
|
|
|
591
614
|
if (plannedCustomFields) {
|
|
592
|
-
await this.
|
|
615
|
+
await this.customFieldValues.applyWrite(model.id, plannedCustomFields);
|
|
593
616
|
|
|
594
617
|
// Custom fields aren't a member column or relation, so an edit touching
|
|
595
618
|
// only them leaves `model._changed` empty and the save fires nothing.
|
|
@@ -4,7 +4,7 @@ const logging = require('@tryghost/logging');
|
|
|
4
4
|
const membersService = require('./service');
|
|
5
5
|
const emailSuppressionList = require('../email-suppression-list');
|
|
6
6
|
const models = require('../../models');
|
|
7
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
7
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
8
8
|
const spamPrevention = require('../../web/shared/middleware/api/spam-prevention');
|
|
9
9
|
const {
|
|
10
10
|
formattedMemberResponse,
|
|
@@ -5,10 +5,11 @@ const MembersSSR = require('./members-ssr');
|
|
|
5
5
|
const db = require('../../data/db');
|
|
6
6
|
const MembersConfigProvider = require('./members-config-provider');
|
|
7
7
|
const makeMembersCSVImporter = require('./importer');
|
|
8
|
+
const {resolveInlineThreshold} = require('./importer/config');
|
|
8
9
|
const MembersStats = require('./stats/members-stats');
|
|
9
10
|
const memberJobs = require('./jobs');
|
|
10
11
|
const logging = require('@tryghost/logging');
|
|
11
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
12
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
12
13
|
const labsService = require('../../../shared/labs');
|
|
13
14
|
const settingsCache = require('../../../shared/settings-cache');
|
|
14
15
|
const config = require('../../../shared/config');
|
|
@@ -50,6 +51,9 @@ const initMembersCSVImporter = ({stripeAPIService}) => {
|
|
|
50
51
|
return makeMembersCSVImporter({
|
|
51
52
|
storagePath: config.getContentPath('data'),
|
|
52
53
|
getTimezone: () => settingsCache.get('timezone'),
|
|
54
|
+
// A getter rather than a value because the threshold is an operator
|
|
55
|
+
// setting that can change between requests
|
|
56
|
+
getInlineThreshold: () => resolveInlineThreshold(config.get('members:importer:inlineThreshold')),
|
|
53
57
|
getMembersRepository: async () => {
|
|
54
58
|
const api = await module.exports.api;
|
|
55
59
|
return api.members;
|
|
@@ -151,6 +155,14 @@ module.exports = {
|
|
|
151
155
|
module.exports.verificationTrigger = verificationTrigger;
|
|
152
156
|
|
|
153
157
|
const membersCSVImporter = initMembersCSVImporter({stripeAPIService: stripeService.api});
|
|
158
|
+
// Constructed here rather than required statically: the exporter needs the
|
|
159
|
+
// custom fields services, which boot builds before this one.
|
|
160
|
+
const customFields = require('../members-custom-fields');
|
|
161
|
+
module.exports.export = require('./exporter/query')({
|
|
162
|
+
definitions: customFields.definitions,
|
|
163
|
+
values: customFields.values
|
|
164
|
+
});
|
|
165
|
+
|
|
154
166
|
module.exports.processImport = async (options) => {
|
|
155
167
|
return await membersCSVImporter.process({...options, verificationTrigger});
|
|
156
168
|
};
|
|
@@ -196,7 +208,8 @@ module.exports = {
|
|
|
196
208
|
processImport: null,
|
|
197
209
|
|
|
198
210
|
stats: membersStats,
|
|
199
|
-
|
|
211
|
+
|
|
212
|
+
export: null
|
|
200
213
|
};
|
|
201
214
|
|
|
202
215
|
module.exports.middleware = require('./middleware');
|
|
@@ -4,7 +4,7 @@ const {Buffer} = require('buffer');
|
|
|
4
4
|
const {randomBytes} = require('crypto');
|
|
5
5
|
|
|
6
6
|
const config = require('../../../shared/config');
|
|
7
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
7
|
+
const urlUtils = require('../../../shared/url-utils').default;
|
|
8
8
|
|
|
9
9
|
const messages = {
|
|
10
10
|
incorrectState: 'State did not match.'
|
|
@@ -24,6 +24,9 @@ async function recordCustomFieldAction({ Action, context, verb, subject, details
|
|
|
24
24
|
await Action.add({
|
|
25
25
|
event: COMMANDS[verb],
|
|
26
26
|
resource_type: 'member_custom_field',
|
|
27
|
+
// The field's id: this column holds 24 characters, and a key minted from
|
|
28
|
+
// a publisher-chosen name is bounded by the far wider key column, so only
|
|
29
|
+
// the id fits every field.
|
|
27
30
|
resource_id: subject,
|
|
28
31
|
actor_type: context.actor.type,
|
|
29
32
|
actor_id: context.actor.id,
|
|
@@ -29,8 +29,9 @@ export type CustomFieldVerb = keyof typeof COMMANDS;
|
|
|
29
29
|
// `details` is stored in the action's `context` column (Ghost's slot for "diffs,
|
|
30
30
|
// meta"). We always pass the field's `primary_name` so the log reads as a human
|
|
31
31
|
// label, not a bare key — this is what keeps the timeline legible after a hard
|
|
32
|
-
// delete, when the row itself is gone.
|
|
33
|
-
|
|
32
|
+
// delete, when the row itself is gone. `key` rides alongside it because the key is
|
|
33
|
+
// how a field is addressed publicly — its id never leaves the API.
|
|
34
|
+
export type CustomFieldActionDetails = {primary_name: string; key: string; previous_name?: string};
|
|
34
35
|
|
|
35
36
|
export type RecordCustomFieldAction =
|
|
36
37
|
(input: {context: RequestContext; verb: CustomFieldVerb; subject: string; details: CustomFieldActionDetails}) => Promise<void>;
|
|
@@ -47,6 +48,9 @@ export async function recordCustomFieldAction(
|
|
|
47
48
|
await Action.add({
|
|
48
49
|
event: COMMANDS[verb],
|
|
49
50
|
resource_type: 'member_custom_field',
|
|
51
|
+
// The field's id: this column holds 24 characters, and a key minted from
|
|
52
|
+
// a publisher-chosen name is bounded by the far wider key column, so only
|
|
53
|
+
// the id fits every field.
|
|
50
54
|
resource_id: subject,
|
|
51
55
|
actor_type: context.actor.type,
|
|
52
56
|
actor_id: context.actor.id,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveMaxDefinitions = resolveMaxDefinitions;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Resolving Ghost's config into the values this service runs on.
|
|
7
|
+
*
|
|
8
|
+
* Config arrives untyped: defaults.json supplies the shipped value, and any
|
|
9
|
+
* higher layer — an operator's config file, an environment variable, argv — can
|
|
10
|
+
* replace it with anything at all. Turning that into something usable is a
|
|
11
|
+
* config concern, so it happens here, at the boundary. The service is handed an
|
|
12
|
+
* answer and never learns where it came from.
|
|
13
|
+
*/
|
|
14
|
+
// A ceiling in the form the service needs it. A numeric string is accepted
|
|
15
|
+
// because a value supplied through an environment variable can arrive as one.
|
|
16
|
+
const Ceiling = zod_1.z
|
|
17
|
+
.union([zod_1.z.number(), zod_1.z.string().trim().min(1)])
|
|
18
|
+
.transform(Number)
|
|
19
|
+
.pipe(zod_1.z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER));
|
|
20
|
+
// defaults.json is the single source of the shipped ceiling: it is the lowest
|
|
21
|
+
// config layer and the file an operator actually reads and edits, so it is read
|
|
22
|
+
// rather than restated. Parsed eagerly because a missing or malformed value
|
|
23
|
+
// there is our bug rather than an operator's, and should fail loudly at boot
|
|
24
|
+
// instead of quietly becoming the fallback for everything below.
|
|
25
|
+
const shippedCeiling = Ceiling.parse(require('../../../shared/config/defaults.json').members.customFields.maxDefinitions);
|
|
26
|
+
// A higher layer can override the shipped value with anything. Something
|
|
27
|
+
// unreadable falls back to the shipped ceiling rather than throwing, because an
|
|
28
|
+
// operator can correct this live and a bad value must not take the feature down
|
|
29
|
+
// with it — and rather than meaning "no ceiling", because a typo must not
|
|
30
|
+
// silently remove the safeguard.
|
|
31
|
+
const MaxDefinitions = Ceiling.catch(shippedCeiling);
|
|
32
|
+
function resolveMaxDefinitions(configured) {
|
|
33
|
+
return MaxDefinitions.parse(configured);
|
|
34
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {z} from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolving Ghost's config into the values this service runs on.
|
|
5
|
+
*
|
|
6
|
+
* Config arrives untyped: defaults.json supplies the shipped value, and any
|
|
7
|
+
* higher layer — an operator's config file, an environment variable, argv — can
|
|
8
|
+
* replace it with anything at all. Turning that into something usable is a
|
|
9
|
+
* config concern, so it happens here, at the boundary. The service is handed an
|
|
10
|
+
* answer and never learns where it came from.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// A ceiling in the form the service needs it. A numeric string is accepted
|
|
14
|
+
// because a value supplied through an environment variable can arrive as one.
|
|
15
|
+
const Ceiling = z
|
|
16
|
+
.union([z.number(), z.string().trim().min(1)])
|
|
17
|
+
.transform(Number)
|
|
18
|
+
.pipe(z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER));
|
|
19
|
+
|
|
20
|
+
// defaults.json is the single source of the shipped ceiling: it is the lowest
|
|
21
|
+
// config layer and the file an operator actually reads and edits, so it is read
|
|
22
|
+
// rather than restated. Parsed eagerly because a missing or malformed value
|
|
23
|
+
// there is our bug rather than an operator's, and should fail loudly at boot
|
|
24
|
+
// instead of quietly becoming the fallback for everything below.
|
|
25
|
+
const shippedCeiling: number = Ceiling.parse(
|
|
26
|
+
require('../../../shared/config/defaults.json').members.customFields.maxDefinitions
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// A higher layer can override the shipped value with anything. Something
|
|
30
|
+
// unreadable falls back to the shipped ceiling rather than throwing, because an
|
|
31
|
+
// operator can correct this live and a bad value must not take the feature down
|
|
32
|
+
// with it — and rather than meaning "no ceiling", because a typo must not
|
|
33
|
+
// silently remove the safeguard.
|
|
34
|
+
const MaxDefinitions = Ceiling.catch(shippedCeiling);
|
|
35
|
+
|
|
36
|
+
export function resolveMaxDefinitions(configured: unknown): number {
|
|
37
|
+
return MaxDefinitions.parse(configured);
|
|
38
|
+
}
|