ghost 6.54.1 → 6.56.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/tryghost-adapter-base-scheduling-0.2.0.tgz +0 -0
- package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
- package/components/tryghost-kg-default-nodes-2.1.4.tgz +0 -0
- package/components/tryghost-kg-default-transforms-1.3.3.tgz +0 -0
- package/components/tryghost-kg-html-to-lexical-1.3.3.tgz +0 -0
- package/components/tryghost-kg-lexical-html-renderer-1.4.3.tgz +0 -0
- package/components/tryghost-nql-string-0.0.0.tgz +0 -0
- package/core/boot.js +3 -6
- package/core/built/admin/assets/{Combination-CJG7Flp-.js → Combination-BCm9FL4o.js} +1 -1
- package/core/built/admin/assets/{PolarAngleAxis-BGjf7sBu.js → PolarAngleAxis-C4qtHy1B.js} +1 -1
- package/core/built/admin/assets/{RadialBarChart-zeFf9mBz.js → RadialBarChart-Bh09Stsj.js} +1 -1
- package/core/built/admin/assets/{account-migration-BklF2I_I.js → account-migration-D3O_yVck.js} +1 -1
- package/core/built/admin/assets/activitypub/{account-migration-CNovr6W-.js → account-migration-D8FbP-Z-.js} +7 -7
- package/core/built/admin/assets/activitypub/activitypub.js +6 -6
- package/core/built/admin/assets/activitypub/{avatar-B3DEDB1l.js → avatar-11EA1VSs.js} +2 -2
- package/core/built/admin/assets/activitypub/{avatar-flipboard-Cqrg0XMx.js → avatar-flipboard-jfbLG-xe.js} +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-Ceslb1_M.js → bluesky-sharing-f1jTQe2P.js} +16 -16
- package/core/built/admin/assets/activitypub/{content-formatters-BpQARh28.js → content-formatters-nmTOPY9M.js} +3 -3
- package/core/built/admin/assets/activitypub/{copy-D9UWIAan.js → copy-BCwo9ep3.js} +2 -2
- package/core/built/admin/assets/activitypub/{dist-DHAjBcV3.js → dist-BEfX-0aW.js} +12 -12
- package/core/built/admin/assets/activitypub/{domain-C1qQvJ8C.js → domain-AaDlZlrA.js} +9 -9
- package/core/built/admin/assets/activitypub/{edit-profile-BcH-jEfM.js → edit-profile-DPi8Tl5M.js} +945 -945
- package/core/built/admin/assets/activitypub/{explore-AxwBh9dI.js → explore-CxTzjILQ.js} +8 -8
- package/core/built/admin/assets/activitypub/{feed-BaOlbh7a.js → feed-DPv5x2MX.js} +33 -33
- package/core/built/admin/assets/activitypub/{field-B7mYYQpN.js → field-DbgA8lat.js} +3 -3
- package/core/built/admin/assets/activitypub/{hash-BC9Q0N4c.js → hash-BWuZoYkA.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-DQ4ZnC1m.js → inbox-35VDQ2K2.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-vXez-5uJ.js → inbox-DSrF_i1O.js} +85 -85
- package/core/built/admin/assets/activitypub/{label-Chv5T8bw.js → label-CPjFBbo7.js} +3 -3
- package/core/built/admin/assets/activitypub/layout-CTgrezN7.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-DtSM2i1I.js → moderation-BkDC1XVZ.js} +11 -11
- package/core/built/admin/assets/activitypub/{note-Dckp4S-2.js → note-xEyH4xT-.js} +7 -7
- package/core/built/admin/assets/activitypub/{notifications-CG5T22vg.js → notifications-DClaL3ui.js} +9 -9
- package/core/built/admin/assets/activitypub/{preferences-D_799jdl.js → preferences-DpnOa-4Z.js} +20 -20
- package/core/built/admin/assets/activitypub/{profile-D2JfXBQl.js → profile-Dvi9mz-6.js} +237 -237
- package/core/built/admin/assets/activitypub/{reply-CpdMeAO5.js → reply-Cs9ySd6Z.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-CCHe2dQp.js → routes-DFBeTnfn.js} +1139 -1150
- package/core/built/admin/assets/activitypub/{separator-BI1FLsYM.js → separator-C5u_VjzY.js} +3 -3
- package/core/built/admin/assets/activitypub/{settings-kx-9Enkz.js → settings-CV2fFu6D.js} +13 -13
- package/core/built/admin/assets/activitypub/{site-x4_IjVJ0.js → site-_TgDd_EM.js} +81 -81
- package/core/built/admin/assets/activitypub/{step-1-DIDg4aHb.js → step-1-BfnNL2oF.js} +5 -5
- package/core/built/admin/assets/activitypub/{step-2-BfGe8BYt.js → step-2-DLndZkO-.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-3-mE9spAqw.js → step-3-A-PZTtRE.js} +10 -10
- package/core/built/admin/assets/activitypub/{tabs-CyPRQQ1N.js → tabs-BUbz7tea.js} +321 -319
- package/core/built/admin/assets/activitypub/{topic-filter-DLHBZT93.js → topic-filter-BdX_xYYT.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-VzbN99u_.js → use-activity-pub-queries-EwuRemHh.js} +2 -2
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-CAwXTmqH.js → use-navigate-with-base-path-cy4ACBc4.js} +92 -90
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-BAB6fNGt.js → use-reply-chain-data-CyFcGfan.js} +5 -5
- package/core/built/admin/assets/activitypub/{x-C8tAnXly.js → x-7zk8mV2p.js} +2 -2
- package/core/built/admin/assets/audience-CkBb2LlO.js +1 -0
- package/core/built/admin/assets/{automated-emails-of1MvVsv.js → automated-emails-6t2bIRWf.js} +2 -2
- package/core/built/admin/assets/{automations-B7-y3dXt.js → automations-DhKeS_U5.js} +1 -1
- package/core/built/admin/assets/{automations-DRFjW5fw.js → automations-cMllU545.js} +1 -1
- package/core/built/admin/assets/{bluesky-sharing-BbbjWdzs.js → bluesky-sharing-DPGpyD-G.js} +1 -1
- package/core/built/admin/assets/{box-BWbhXh21.js → box-By_EgGtm.js} +1 -1
- package/core/built/admin/assets/{breadcrumb-B-M9Ip_2.js → breadcrumb-DIfcF5ow.js} +1 -1
- package/core/built/admin/assets/build-CsiH26uS.js +1 -0
- package/core/built/admin/assets/{card-DGoDJzrn.js → card-aUHX0hyR.js} +1 -1
- package/core/built/admin/assets/{chart-BuRT2Y6p.js → chart-BnXyfH11.js} +1 -1
- package/core/built/admin/assets/{chart-helpers-xiSsW8r0.js → chart-helpers-DV0FkdcD.js} +1 -1
- package/core/built/admin/assets/{checkbox-EhJKHFdZ.js → checkbox-BIl077a0.js} +1 -1
- package/core/built/admin/assets/{chunk.361.3cdb584b973959e52ccc.js → chunk.332.05991a101d67f732dec3.js} +16 -12
- package/core/built/admin/assets/chunk.524.87b52f4fada529df2c4c.js +25 -0
- package/core/built/admin/assets/chunk.582.340bcca873e806cbd4bb.js +27 -0
- package/core/built/admin/assets/{code-editor-view-CZtJFGhR.js → code-editor-view-C0aWNwdl.js} +1 -1
- package/core/built/admin/assets/comments-qwhIjH3c.js +1 -0
- package/core/built/admin/assets/{container-BYz2Ed39.js → container-LiZf3XdY.js} +1 -1
- package/core/built/admin/assets/{data-list-16rkJYYi.js → data-list-CupF7bjM.js} +1 -1
- package/core/built/admin/assets/{date-range-select-CTlyo8zW.js → date-range-select-dXc-GsVe.js} +1 -1
- package/core/built/admin/assets/{disabled-sources-indicator-qs2GfLvl.js → disabled-sources-indicator-DYAXW-6V.js} +1 -1
- package/core/built/admin/assets/dist-BUKmD51u.js +1 -0
- package/core/built/admin/assets/{dist-2Tnz2Yfq.js → dist-CNlMj7ML.js} +1 -1
- package/core/built/admin/assets/{dist-DGzPJ_bO.js → dist-Cb5RSHSg.js} +1 -1
- package/core/built/admin/assets/{dist-P_ohUlTi.js → dist-CqO2lWS0.js} +1 -1
- package/core/built/admin/assets/{domain-CPNXKVOV.js → domain-B5ogXUBa.js} +1 -1
- package/core/built/admin/assets/{dropzone-BmCXnw6J.js → dropzone-BnFG7dDP.js} +1 -1
- package/core/built/admin/assets/{edit-profile-SGrJve5M.js → edit-profile-B07jCZy9.js} +1 -1
- package/core/built/admin/assets/editor-DDYSOXGN.js +8 -0
- package/core/built/admin/assets/{empty-indicator-oX1u1Pkn.js → empty-indicator-WB1WgT9h.js} +1 -1
- package/core/built/admin/assets/{explore-CUYLv9G9.js → explore-Ca1y8HW_.js} +1 -1
- package/core/built/admin/assets/{feed-CPdJMttL.js → feed-x4iFMBP4.js} +1 -1
- package/core/built/admin/assets/field-ChCAabZg.js +1 -0
- package/core/built/admin/assets/filter-sources-LdtH1e-T.js +1 -0
- package/core/built/admin/assets/{filters-bXkkWro8.js → filters-CLehPo_D.js} +1 -1
- package/core/built/admin/assets/filters-CjVKRP8U.js +1 -0
- package/core/built/admin/assets/{ghost-05f9a7182ed56903dba05878a5b8422b.js → ghost-7f01131115186d1af84ead76e79646dd.js} +275 -255
- package/core/built/admin/assets/{ghost-3063eae29e6c9cc6d6e7131928a27da0.css → ghost-d38c30b866e59f2e06a357b5eb844fe5.css} +1 -1
- package/core/built/admin/assets/{ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css → ghost-dark-1bffd5099ba7a749303133efacf8480b.css} +1 -1
- package/core/built/admin/assets/gift-link-modal-Buqh2vXh.js +1 -0
- package/core/built/admin/assets/{gift-links-nBxJjZiQ.js → gift-links-CsUhefWG.js} +1 -1
- package/core/built/admin/assets/growth-DajOBdN0.js +1 -0
- package/core/built/admin/assets/growth-Dy2UOSay.js +3 -0
- package/core/built/admin/assets/{hooks-BApwwBE0.js → hooks-CixO01lL.js} +1 -1
- package/core/built/admin/assets/{inbox-Xx1CdnfO.js → inbox-BUOLDoji.js} +13 -13
- package/core/built/admin/assets/index-08n05-rc.js +67 -0
- package/core/built/admin/assets/index-DgUzgFvS.css +1 -0
- package/core/built/admin/assets/{inline-EMAm3okk.js → inline-Cw-gigDW.js} +1 -1
- package/core/built/admin/assets/input-group-uSK3XT7b.js +1 -0
- package/core/built/admin/assets/{input-surface-BpAjZXY5.js → input-surface-BdOe4KzO.js} +1 -1
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +9132 -9087
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +121 -121
- package/core/built/admin/assets/koenig-lexical/style.css +1 -1
- package/core/built/admin/assets/{koenig-lexical-B61IALf5.js → koenig-lexical-BFc4yFed.js} +82 -82
- package/core/built/admin/assets/{kpi-card-DCdlyaSS.js → kpi-card-BN-E6WYX.js} +1 -1
- package/core/built/admin/assets/{kpi-card-BlZaG1Lo.js → kpi-card-CCt-qeWD.js} +1 -1
- package/core/built/admin/assets/{kpi-helpers-DpAuS1Nb.js → kpi-helpers-DlxTbTs4.js} +1 -1
- package/core/built/admin/assets/{kpi-tabs-Dme44bQS.js → kpi-tabs-BlcUttpn.js} +1 -1
- package/core/built/admin/assets/{label-dSs5aepE.js → label-AVrxwmsz.js} +1 -1
- package/core/built/admin/assets/label-picker-DVnpu_IF.js +1 -0
- package/core/built/admin/assets/labels-DAIqKed7.js +1 -0
- package/core/built/admin/assets/layout-B0YLh7R9.js +1 -0
- package/core/built/admin/assets/link-helpers-D9LsDOkG.js +1 -0
- package/core/built/admin/assets/{list-page-B6ANtzkd.js → list-page-CdsnQR9N.js} +1 -1
- package/core/built/admin/assets/member-custom-fields-C8NpZYza.js +1 -0
- package/core/built/admin/assets/member-detail-CIVAdKXf.js +1 -0
- package/core/built/admin/assets/members-oLPiSkXD.js +10 -0
- package/core/built/admin/assets/modals-CB7v-k3T.js +31 -0
- package/core/built/admin/assets/moderation-CQ3urTFE.js +1 -0
- package/core/built/admin/assets/newsletter-rbeDX9Wk.js +1 -0
- package/core/built/admin/assets/{newsletters-D1jbtV-h.js → newsletters-BXJbJgA-.js} +1 -1
- package/core/built/admin/assets/newsletters-vt3Ni1Ov.js +1 -0
- package/core/built/admin/assets/note-Dk877BTv.js +1 -0
- package/core/built/admin/assets/notifications-CPlLjPxO.js +1 -0
- package/core/built/admin/assets/{offers-CrY6nSRR.js → offers-DEniVRD5.js} +1 -1
- package/core/built/admin/assets/onboarding-route-DdStOtjy.js +1 -0
- package/core/built/admin/assets/overview--4V-kx9c.js +1 -0
- package/core/built/admin/assets/overview-DSLv30oz.js +1 -0
- package/core/built/admin/assets/{page-header-op0eN36I.js → page-header-pp4dWmOS.js} +1 -1
- package/core/built/admin/assets/{pages-BbNWFcGj.js → pages-B4goRPUn.js} +1 -1
- package/core/built/admin/assets/{post-analytics-WwRDEnrV.js → post-analytics-BMJrI81R.js} +1 -1
- package/core/built/admin/assets/post-analytics-header-pU2m9ZuV.js +1 -0
- package/core/built/admin/assets/post-analytics-provider-Btml5vJI.js +1 -0
- package/core/built/admin/assets/{post-share-modal-Dx-MEjhI.js → post-share-modal-AcUZkbfL.js} +1 -1
- package/core/built/admin/assets/{posts-EWpZIjkr.js → posts-DhXE7b6r.js} +1 -1
- package/core/built/admin/assets/preferences-Ru4CRPHC.js +5 -0
- package/core/built/admin/assets/profile-BNb1oj7D.js +1 -0
- package/core/built/admin/assets/{referrers-BCfFYSHc.js → referrers-pmJT4k3-.js} +1 -1
- package/core/built/admin/assets/{router-provider-C1R4AZ2o.js → router-provider-BmEZf6c6.js} +1 -1
- package/core/built/admin/assets/select-B0HteHrp.js +1 -0
- package/core/built/admin/assets/settings-B1C9Q3wo.js +4 -0
- package/core/built/admin/assets/{settings-H6HxFgfI.js → settings-BGgk7oCI.js} +1 -1
- package/core/built/admin/assets/{shade-app-B3heOAfz-CGXQwWeO.js → shade-app-B3heOAfz-BhQXxNkT.js} +1 -1
- package/core/built/admin/assets/{share-modal-BJCadJyp.js → share-modal-BeuydaBf.js} +1 -1
- package/core/built/admin/assets/social-urls-DA2lXrhW.js +8 -0
- package/core/built/admin/assets/{sort-button-DyYlfYp7.js → sort-button-Df4t2AL8.js} +1 -1
- package/core/built/admin/assets/{source-icon-_ubRDbg_.js → source-icon-ajoaKb41.js} +1 -1
- package/core/built/admin/assets/{stack-xiN0eQ6Z.js → stack-CIfOAAVf.js} +1 -1
- package/core/built/admin/assets/{stats-BQZMGMvn.js → stats-C_lfxZAw.js} +1 -1
- package/core/built/admin/assets/{stats-view-Doei-qCX.js → stats-view-Cxot1iD8.js} +1 -1
- package/core/built/admin/assets/{step-1-IKiLBPoC.js → step-1-ogAA4lDr.js} +1 -1
- package/core/built/admin/assets/{step-2-jJ41PsDN.js → step-2-C5Xini-7.js} +1 -1
- package/core/built/admin/assets/{step-3-CaqFAEqf.js → step-3-CZv1FV81.js} +2 -2
- package/core/built/admin/assets/{switch-t-WyENU2.js → switch-CyQcwMAv.js} +1 -1
- package/core/built/admin/assets/{table-DxUL78jU.js → table-DFj1wiYv.js} +1 -1
- package/core/built/admin/assets/tabs-D4y1gqUd.js +1 -0
- package/core/built/admin/assets/{tags-CNujGwkT.js → tags-Dmft-Y4O.js} +1 -1
- package/core/built/admin/assets/{text-DwtjwGkh.js → text-DU9Hv33_.js} +1 -1
- package/core/built/admin/assets/textarea-d9qEkMOP.js +1 -0
- package/core/built/admin/assets/{tiers-BgYLWRJv.js → tiers-DYsa4DCo.js} +1 -1
- package/core/built/admin/assets/{toggle-group-BeEpQ69p.js → toggle-group-R2QMFvXW.js} +1 -1
- package/core/built/admin/assets/{topic-filter-Bb5MOD-1.js → topic-filter-DGDxDalo.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data-Cds6XDjg.js → use-analytics-data-C76v4LIp.js} +1 -1
- package/core/built/admin/assets/use-filter-params-WrdhAISv.js +1 -0
- package/core/built/admin/assets/{use-growth-stats-D8uf98-G.js → use-growth-stats-aNXJOmQr.js} +1 -1
- package/core/built/admin/assets/{use-post-referrers-CRtgyuXB.js → use-post-referrers-CG0SZioj.js} +1 -1
- package/core/built/admin/assets/{use-reply-chain-data-DbKYX50v.js → use-reply-chain-data-RLdPKRmS.js} +1 -1
- package/core/built/admin/assets/{use-simple-pagination-DC01kpo0.js → use-simple-pagination-DgcF69KI.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-query-C7bQRJWw.js → use-tinybird-query-C1R_Kbmy.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-Az4tam7_.js → use-tinybird-token-C9fPjVM_.js} +1 -1
- package/core/built/admin/assets/{users-CcSCQFcQ.js → users-Dkv8NQZe.js} +1 -1
- package/core/built/admin/assets/{virtual-list-Dhuh9fGx.js → virtual-list-BmTUzeoF.js} +1 -1
- package/core/built/admin/assets/web-BqW0b0_C.js +1 -0
- package/core/built/admin/assets/web-Cy5GKMWM.js +2 -0
- package/core/built/admin/index.html +18 -18
- package/core/frontend/services/data/fetch-data.js +10 -5
- package/core/frontend/services/proxy.js +7 -8
- package/core/frontend/services/routing/api-adapter.js +115 -0
- package/core/frontend/services/routing/api-adapter.ts +157 -0
- package/core/frontend/services/routing/collection-router.js +5 -3
- package/core/frontend/services/routing/controllers/index.js +1 -1
- package/core/frontend/services/routing/controllers/rss.js +26 -31
- package/core/frontend/services/routing/controllers/rss.ts +66 -0
- package/core/frontend/services/routing/controllers/static.js +8 -7
- package/core/frontend/services/routing/parent-router.js +17 -4
- package/core/frontend/services/routing/permalink-adapter.js +26 -0
- package/core/frontend/services/routing/permalink-adapter.ts +23 -0
- package/core/frontend/services/routing/registry.js +59 -33
- package/core/frontend/services/routing/router-manager.js +14 -18
- package/core/frontend/services/routing/static-routes-router.js +11 -13
- package/core/frontend/services/routing/taxonomy-router.js +6 -2
- package/core/server/api/endpoints/automation-action-links.js +68 -0
- package/core/server/api/endpoints/automation-action-links.ts +46 -0
- package/core/server/api/endpoints/index.js +4 -0
- package/core/server/api/endpoints/settings.js +0 -2
- package/core/server/api/endpoints/utils/serializers/output/utils/url.js +11 -1
- package/core/server/data/migrations/versions/6.55/2026-07-27-11-25-44-add-to-hash-to-redirects.js +51 -0
- package/core/server/data/migrations/versions/6.55/2026-07-28-12-08-00-remove-routes-hash-from-settings.js +5 -0
- package/core/server/data/migrations/versions/6.56/2026-08-03-19-27-51-add-automation-run-step-id-to-automated-email-recipients.js +8 -0
- package/core/server/data/migrations/versions/6.56/2026-08-04-14-42-39-restrict-notification-add-permission-to-administrators.js +12 -0
- package/core/server/data/schema/commands.js +5 -0
- package/core/server/data/schema/default-settings/default-settings.json +0 -4
- package/core/server/data/schema/fixtures/fixtures.json +2 -2
- package/core/server/data/schema/schema.js +6 -1
- package/core/server/models/post.js +10 -1
- package/core/server/services/automations/automations-api.js +15 -0
- package/core/server/services/automations/automations-api.ts +19 -0
- package/core/server/services/automations/automations-repository.ts +20 -0
- package/core/server/services/automations/database-automations-repository.js +132 -30
- package/core/server/services/automations/database-automations-repository.ts +141 -12
- package/core/server/services/automations/database-date.js +10 -0
- package/core/server/services/automations/database-date.ts +5 -0
- package/core/server/services/automations/get-scheduler-idempotency-key.js +13 -0
- package/core/server/services/automations/get-scheduler-idempotency-key.ts +8 -0
- package/core/server/services/automations/poll.js +7 -2
- package/core/server/services/automations/poll.ts +10 -2
- package/core/server/services/automations/scheduler-poll-time.js +40 -0
- package/core/server/services/automations/scheduler-poll-time.ts +38 -0
- package/core/server/services/automations/service.js +19 -3
- package/core/server/services/automations/service.ts +20 -3
- package/core/server/services/comments/comments-service-emails.js +10 -7
- package/core/server/services/comments/comments-service.js +9 -4
- package/core/server/services/email-rendering/partials/email-wrapper.hbs +3 -1
- package/core/server/services/email-service/email-service-wrapper.js +6 -1
- package/core/server/services/email-service/email-templates/partials/styles.hbs +8 -0
- package/core/server/services/email-service/newsletter-email-event-storage.js +41 -10
- package/core/server/services/gift-links/CONTEXT.md +9 -0
- package/core/server/services/gifts/CONTEXT.md +55 -0
- package/core/server/services/gifts/README.md +28 -0
- package/core/server/services/gifts/gift-bookshelf-repository.js +65 -45
- package/core/server/services/gifts/gift-bookshelf-repository.ts +203 -74
- package/core/server/services/gifts/gift-checkout-adapter.js +59 -0
- package/core/server/services/gifts/gift-checkout-offer.js +74 -0
- package/core/server/services/gifts/gift-checkout-offer.ts +127 -0
- package/core/server/services/gifts/gift-codec.js +63 -0
- package/core/server/services/gifts/gift-codec.ts +62 -0
- package/core/server/services/gifts/gift-controller.js +6 -31
- package/core/server/services/gifts/gift-controller.ts +6 -69
- package/core/server/services/gifts/gift-email-service.ts +3 -2
- package/core/server/services/gifts/gift-schema.js +34 -0
- package/core/server/services/gifts/gift-schema.ts +39 -0
- package/core/server/services/gifts/gift-service-wrapper.js +13 -11
- package/core/server/services/gifts/gift-service.js +265 -52
- package/core/server/services/gifts/gift-service.ts +431 -97
- package/core/server/services/gifts/gift.ts +16 -39
- package/core/server/services/lib/dynamic-redirect-manager.js +12 -3
- package/core/server/services/link-redirection/link-redirect-repository.js +41 -4
- package/core/server/services/link-redirection/link-redirect.js +2 -0
- package/core/server/services/link-redirection/link-redirect.ts +3 -1
- package/core/server/services/link-redirection/link-redirects-service.js +38 -2
- package/core/server/services/link-tracking/click-event.js +3 -0
- package/core/server/services/link-tracking/index.js +38 -6
- package/core/server/services/link-tracking/link-click-repository.js +35 -9
- package/core/server/services/link-tracking/link-click-tracking-service.js +54 -4
- package/core/server/services/member-attribution/outbound-link-tagger.js +3 -1
- package/core/server/services/member-welcome-emails/member-welcome-email-renderer.js +20 -4
- package/core/server/services/member-welcome-emails/service.js +15 -3
- package/core/server/services/members/api.js +1 -2
- package/core/server/services/members/import-export/csv/formula.js +16 -0
- package/core/server/services/members/import-export/csv/formula.ts +14 -0
- package/core/server/services/members/import-export/csv/index.js +3 -1
- package/core/server/services/members/import-export/csv/index.ts +1 -0
- package/core/server/services/members/import-export/import/completion-email.js +22 -3
- package/core/server/services/members/import-export/import/completion-email.ts +29 -7
- package/core/server/services/members/import-export/import/importer.js +25 -4
- package/core/server/services/members/import-export/import/importer.ts +44 -5
- package/core/server/services/members/import-export/index.js +18 -1
- package/core/server/services/members/import-export/index.ts +32 -3
- package/core/server/services/members/members-api/controllers/router-controller.js +38 -36
- package/core/server/services/members/members-api/members-api.js +13 -7
- package/core/server/services/members/members-api/repositories/event-repository.js +4 -94
- package/core/server/services/members/members-api/services/member-bread-service.js +3 -3
- package/core/server/services/members/members-api/services/payments-service.js +6 -68
- package/core/server/services/members/service.js +8 -1
- package/core/server/services/members-custom-fields/schema.js +8 -1
- package/core/server/services/members-custom-fields/schema.ts +8 -0
- package/core/server/services/members-custom-fields/values-service.js +136 -8
- package/core/server/services/members-custom-fields/values-service.ts +152 -10
- package/core/server/services/mentions/service.js +5 -1
- package/core/server/services/oembed/oembed-service.js +44 -3
- package/core/server/services/posts/posts-service.js +11 -0
- package/core/server/services/route-settings/dynamic-routing-service.js +21 -52
- package/core/server/services/route-settings/index.js +1 -16
- package/core/server/services/route-settings/route-settings-parser.js +25 -25
- package/core/server/services/route-settings/route-settings-parser.ts +27 -27
- package/core/server/services/route-settings/validation-errors.js +68 -4
- package/core/server/services/route-settings/validation-errors.ts +79 -4
- package/core/server/services/settings/settings-service.js +0 -18
- package/core/server/services/stats/posts-stats-service.js +27 -23
- package/core/server/services/stripe/services/webhook/charge-refunded-event-service.js +1 -1
- package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +16 -4
- package/core/server/services/stripe/stripe-api.js +10 -0
- package/core/server/services/url/url-service-facade.js +1 -1
- package/core/server/services/url/url-service-facade.ts +8 -1
- package/core/server/web/api/endpoints/admin/routes.js +1 -0
- package/core/server/web/gift-preview/controller.js +10 -25
- package/core/shared/labs.js +2 -2
- package/package.json +8 -7
- package/pnpm-lock.yaml +28 -18
- package/pnpm-workspace.yaml +6 -4
- package/components/tryghost-kg-default-nodes-2.1.3.tgz +0 -0
- package/core/built/admin/assets/Growth-BTP1LthE.js +0 -3
- package/core/built/admin/assets/Newsletters-CSEX0myc.js +0 -1
- package/core/built/admin/assets/Overview-BjACEsJF.js +0 -1
- package/core/built/admin/assets/Web-CxxxjCcv.js +0 -2
- package/core/built/admin/assets/activitypub/layout-CziktJXo.js +0 -1
- package/core/built/admin/assets/audience-X_XsZivI.js +0 -1
- package/core/built/admin/assets/chunk.524.8365cd9280405c0f6216.js +0 -25
- package/core/built/admin/assets/chunk.582.61d078937e6102769f2c.js +0 -27
- package/core/built/admin/assets/comments-CvyXxOyN.js +0 -1
- package/core/built/admin/assets/constants-c-JNF9c2.js +0 -1
- package/core/built/admin/assets/dist-CjY-f5Z1.js +0 -1
- package/core/built/admin/assets/editor-BOG2YPUm.js +0 -8
- package/core/built/admin/assets/field-D0XISCK2.js +0 -1
- package/core/built/admin/assets/filter-sources-Bieps75g.js +0 -1
- package/core/built/admin/assets/filters-CuB-A7ma.js +0 -1
- package/core/built/admin/assets/gift-link-modal-su8MsRdg.js +0 -1
- package/core/built/admin/assets/growth-Ba6S5FQX.js +0 -1
- package/core/built/admin/assets/index-D8PbzuT9.css +0 -1
- package/core/built/admin/assets/index-ukW_0Uie.js +0 -67
- package/core/built/admin/assets/input-group-CGOXcy4l.js +0 -1
- package/core/built/admin/assets/label-picker-Uq91atex.js +0 -1
- package/core/built/admin/assets/labels-Cyayfd-e.js +0 -1
- package/core/built/admin/assets/layout-WUcz6tu1.js +0 -1
- package/core/built/admin/assets/link-helpers-tOlxmuH5.js +0 -1
- package/core/built/admin/assets/member-custom-fields-NCzrMuba.js +0 -1
- package/core/built/admin/assets/member-detail-DPWDtYnN.js +0 -1
- package/core/built/admin/assets/members-B9rO7qr4.js +0 -10
- package/core/built/admin/assets/modals-CxRaan1J.js +0 -31
- package/core/built/admin/assets/moderation-D8zon60E.js +0 -1
- package/core/built/admin/assets/multi-select-combobox-1wYm3nle.js +0 -1
- package/core/built/admin/assets/newsletter-DbYMRxRS.js +0 -1
- package/core/built/admin/assets/note-PiWPnnrh.js +0 -1
- package/core/built/admin/assets/notifications-DEgqqB9G.js +0 -1
- package/core/built/admin/assets/nql-BsgFMd93.js +0 -1
- package/core/built/admin/assets/onboarding-route-BzF6HeVn.js +0 -1
- package/core/built/admin/assets/overview-DixLeIqY.js +0 -1
- package/core/built/admin/assets/post-analytics-header-DsMoLx0R.js +0 -1
- package/core/built/admin/assets/post-analytics-provider-BJCPLMIb.js +0 -1
- package/core/built/admin/assets/preferences-D7-j6A4C.js +0 -5
- package/core/built/admin/assets/profile-Dl69QPp0.js +0 -1
- package/core/built/admin/assets/select-C1qDZnW4.js +0 -1
- package/core/built/admin/assets/settings-BbmC_Iqq.js +0 -4
- package/core/built/admin/assets/social-urls-BPL1nADp.js +0 -8
- package/core/built/admin/assets/tabs-BQcJQ1ke.js +0 -1
- package/core/built/admin/assets/textarea-Bjccvh_E.js +0 -1
- package/core/built/admin/assets/use-filter-params-DjXkhO54.js +0 -1
- package/core/built/admin/assets/web-LtHNiNBV.js +0 -1
- package/core/server/services/gifts/gift-repository.js +0 -2
- package/core/server/services/gifts/gift-repository.ts +0 -29
- package/core/server/services/route-settings/activation-bridge.js +0 -164
- package/core/server/services/route-settings/activation-bridge.ts +0 -210
- package/core/server/services/route-settings/default-settings-manager.js +0 -63
- package/core/server/services/route-settings/route-settings.js +0 -170
- package/core/server/services/route-settings/settings-loader.js +0 -60
- package/core/server/services/route-settings/settings-path-manager.js +0 -47
- package/core/server/services/route-settings/validate.js +0 -440
|
@@ -525,7 +525,7 @@ module.exports = class RouterController {
|
|
|
525
525
|
* @param {string} options.cancelUrl URL to redirect to after cancelled checkout
|
|
526
526
|
* @param {string} [options.email] Email address of the customer
|
|
527
527
|
* @param {object} [options.member] Currently authenticated member OR member associated with the email address
|
|
528
|
-
* @param {
|
|
528
|
+
* @param {number|null} [options.giftTrialDays] Stable continuation decision from gift subscriptions
|
|
529
529
|
* @param {boolean} options.isAuthenticated
|
|
530
530
|
* @param {object} options.metadata Metadata to be passed to Stripe
|
|
531
531
|
* @returns
|
|
@@ -680,9 +680,11 @@ module.exports = class RouterController {
|
|
|
680
680
|
|
|
681
681
|
/**
|
|
682
682
|
* @param {object} options
|
|
683
|
-
* @param {
|
|
684
|
-
* @param {
|
|
685
|
-
* @param {string} options.
|
|
683
|
+
* @param {string} options.tierId
|
|
684
|
+
* @param {string} [options.offerId]
|
|
685
|
+
* @param {string} [options.cadence]
|
|
686
|
+
* @param {number} [options.duration]
|
|
687
|
+
* @param {string} [options.email]
|
|
686
688
|
* @param {string} options.successUrl
|
|
687
689
|
* @param {string} options.cancelUrl
|
|
688
690
|
* @param {object} options.metadata
|
|
@@ -698,10 +700,26 @@ module.exports = class RouterController {
|
|
|
698
700
|
}
|
|
699
701
|
|
|
700
702
|
try {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
703
|
+
return await this._giftService.service.startCheckout({
|
|
704
|
+
tierId: options.tierId,
|
|
705
|
+
offerId: options.offerId,
|
|
706
|
+
cadence: options.cadence,
|
|
707
|
+
duration: options.duration,
|
|
708
|
+
metadata: options.metadata,
|
|
709
|
+
successUrl: options.successUrl,
|
|
710
|
+
cancelUrl: options.cancelUrl,
|
|
711
|
+
buyer: {
|
|
712
|
+
memberId: options.member?.id ?? null,
|
|
713
|
+
email: options.member?.get('email') ?? options.email ?? null,
|
|
714
|
+
name: options.member?.get('name') ?? null,
|
|
715
|
+
isAuthenticated: options.isAuthenticated
|
|
716
|
+
}
|
|
717
|
+
});
|
|
704
718
|
} catch (err) {
|
|
719
|
+
if (err instanceof BadRequestError || err instanceof NoPermissionError) {
|
|
720
|
+
throw err;
|
|
721
|
+
}
|
|
722
|
+
|
|
705
723
|
logging.error(err);
|
|
706
724
|
this._sentry?.captureException?.(err);
|
|
707
725
|
throw new BadRequestError({
|
|
@@ -788,7 +806,7 @@ module.exports = class RouterController {
|
|
|
788
806
|
let tier;
|
|
789
807
|
let cadence;
|
|
790
808
|
let offer;
|
|
791
|
-
let
|
|
809
|
+
let giftTrialDays;
|
|
792
810
|
|
|
793
811
|
if (req.body.continueFromGift) {
|
|
794
812
|
if (!isAuthenticated || !member) {
|
|
@@ -796,25 +814,16 @@ module.exports = class RouterController {
|
|
|
796
814
|
message: tpl(messages.signInRequired)
|
|
797
815
|
});
|
|
798
816
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
});
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
gift = await this._giftService.service.getActiveByMember(member.id);
|
|
807
|
-
if (!gift) {
|
|
808
|
-
throw new BadRequestError({
|
|
809
|
-
message: tpl(messages.badRequest),
|
|
810
|
-
context: 'No active gift subscription found for member'
|
|
811
|
-
});
|
|
812
|
-
}
|
|
817
|
+
const continuation = await this._giftService.service.preparePaidContinuation({
|
|
818
|
+
memberId: member.id,
|
|
819
|
+
memberStatus: member.get('status')
|
|
820
|
+
});
|
|
813
821
|
|
|
814
822
|
({tier, cadence} = await this._getSubscriptionCheckoutData({
|
|
815
|
-
tierId:
|
|
816
|
-
cadence:
|
|
823
|
+
tierId: continuation.tierId,
|
|
824
|
+
cadence: continuation.cadence
|
|
817
825
|
}));
|
|
826
|
+
giftTrialDays = continuation.trialDays;
|
|
818
827
|
} else {
|
|
819
828
|
({tier, cadence, offer} = await this._getSubscriptionCheckoutData(req.body));
|
|
820
829
|
}
|
|
@@ -825,7 +834,7 @@ module.exports = class RouterController {
|
|
|
825
834
|
tier,
|
|
826
835
|
cadence,
|
|
827
836
|
offer,
|
|
828
|
-
|
|
837
|
+
giftTrialDays
|
|
829
838
|
});
|
|
830
839
|
|
|
831
840
|
// Add welcome_page_url to the response if available and member is authenticated
|
|
@@ -842,19 +851,12 @@ module.exports = class RouterController {
|
|
|
842
851
|
});
|
|
843
852
|
}
|
|
844
853
|
|
|
845
|
-
if (req.body.offerId) {
|
|
846
|
-
throw new BadRequestError({
|
|
847
|
-
message: tpl(messages.badRequest),
|
|
848
|
-
context: 'Offers cannot be applied to gift subscriptions'
|
|
849
|
-
});
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
const data = await this._getSubscriptionCheckoutData(req.body);
|
|
853
|
-
|
|
854
854
|
response = await this._createGiftCheckoutSession({
|
|
855
855
|
...options,
|
|
856
|
-
|
|
857
|
-
|
|
856
|
+
tierId: req.body.tierId,
|
|
857
|
+
offerId: req.body.offerId,
|
|
858
|
+
cadence: req.body.cadence,
|
|
859
|
+
duration: req.body.duration,
|
|
858
860
|
successUrl: siteUrl,
|
|
859
861
|
cancelUrl: options.cancelUrl || siteUrl
|
|
860
862
|
});
|
|
@@ -67,8 +67,7 @@ module.exports = function MembersAPI({
|
|
|
67
67
|
MemberFeedback,
|
|
68
68
|
Automation,
|
|
69
69
|
WelcomeEmailAutomationRun,
|
|
70
|
-
AutomatedEmailRecipient
|
|
71
|
-
Gift
|
|
70
|
+
AutomatedEmailRecipient
|
|
72
71
|
},
|
|
73
72
|
tiersService,
|
|
74
73
|
stripeAPIService,
|
|
@@ -142,7 +141,7 @@ module.exports = function MembersAPI({
|
|
|
142
141
|
memberAttributionService,
|
|
143
142
|
MemberEmailChangeEvent,
|
|
144
143
|
AutomatedEmailRecipient,
|
|
145
|
-
|
|
144
|
+
giftSubscriptions: giftService
|
|
146
145
|
});
|
|
147
146
|
|
|
148
147
|
const nextPaymentCalculator = new NextPaymentCalculator();
|
|
@@ -192,8 +191,7 @@ module.exports = function MembersAPI({
|
|
|
192
191
|
Offer,
|
|
193
192
|
offersAPI,
|
|
194
193
|
stripeAPIService,
|
|
195
|
-
settingsCache
|
|
196
|
-
giftService
|
|
194
|
+
settingsCache
|
|
197
195
|
});
|
|
198
196
|
|
|
199
197
|
const memberController = new MemberController({
|
|
@@ -283,7 +281,10 @@ module.exports = function MembersAPI({
|
|
|
283
281
|
}
|
|
284
282
|
|
|
285
283
|
if (giftToken) {
|
|
286
|
-
await giftService.service.redeem(
|
|
284
|
+
await giftService.service.redeem({
|
|
285
|
+
token: giftToken,
|
|
286
|
+
memberId: member.id
|
|
287
|
+
});
|
|
287
288
|
}
|
|
288
289
|
|
|
289
290
|
await MemberLoginEvent.add({member_id: member.id});
|
|
@@ -316,7 +317,12 @@ module.exports = function MembersAPI({
|
|
|
316
317
|
{name, email, labels, newsletters, attribution, geolocation, status: 'gift'},
|
|
317
318
|
{transacting}
|
|
318
319
|
);
|
|
319
|
-
await giftService.service.redeem(
|
|
320
|
+
await giftService.service.redeem({
|
|
321
|
+
token: giftToken,
|
|
322
|
+
memberId: created.id,
|
|
323
|
+
transacting,
|
|
324
|
+
newMember: true
|
|
325
|
+
});
|
|
320
326
|
return created;
|
|
321
327
|
});
|
|
322
328
|
} else {
|
|
@@ -37,7 +37,7 @@ module.exports = class EventRepository {
|
|
|
37
37
|
urlService,
|
|
38
38
|
MemberEmailChangeEvent,
|
|
39
39
|
AutomatedEmailRecipient,
|
|
40
|
-
|
|
40
|
+
giftSubscriptions
|
|
41
41
|
}) {
|
|
42
42
|
this._DonationPaymentEvent = DonationPaymentEvent;
|
|
43
43
|
this._MemberSubscribeEvent = MemberSubscribeEvent;
|
|
@@ -57,7 +57,7 @@ module.exports = class EventRepository {
|
|
|
57
57
|
this._memberAttributionService = memberAttributionService;
|
|
58
58
|
this._MemberEmailChangeEvent = MemberEmailChangeEvent;
|
|
59
59
|
this._AutomatedEmailRecipient = AutomatedEmailRecipient;
|
|
60
|
-
this.
|
|
60
|
+
this._giftSubscriptions = giftSubscriptions;
|
|
61
61
|
this._knex = db.knex;
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -462,101 +462,11 @@ module.exports = class EventRepository {
|
|
|
462
462
|
}
|
|
463
463
|
|
|
464
464
|
async getGiftPurchaseEvents(options = {}, filter) {
|
|
465
|
-
options
|
|
466
|
-
...options,
|
|
467
|
-
withRelated: ['buyer', 'tier'],
|
|
468
|
-
filter: 'buyer_member_id:-null+custom:true',
|
|
469
|
-
useBasicCount: true,
|
|
470
|
-
mongoTransformer: chainTransformers(
|
|
471
|
-
// First set the filter manually
|
|
472
|
-
replaceCustomFilterTransformer(filter),
|
|
473
|
-
|
|
474
|
-
// Map the used keys in that filter
|
|
475
|
-
...mapKeys({
|
|
476
|
-
'data.created_at': 'purchased_at',
|
|
477
|
-
'data.member_id': 'buyer_member_id'
|
|
478
|
-
})
|
|
479
|
-
)
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
if (options.order) {
|
|
483
|
-
options.order = options.order.replace(/created_at/g, 'purchased_at');
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
const {data: models, meta} = await this._Gift.findPage(options);
|
|
487
|
-
|
|
488
|
-
const data = models.map((model) => {
|
|
489
|
-
const json = model.toJSON(options);
|
|
490
|
-
|
|
491
|
-
return {
|
|
492
|
-
type: 'gift_purchase_event',
|
|
493
|
-
data: {
|
|
494
|
-
id: json.id,
|
|
495
|
-
member: json.buyer || null,
|
|
496
|
-
member_id: json.buyer_member_id,
|
|
497
|
-
tier_name: json.tier?.name,
|
|
498
|
-
cadence: json.cadence,
|
|
499
|
-
duration: json.duration,
|
|
500
|
-
amount: json.amount,
|
|
501
|
-
currency: json.currency,
|
|
502
|
-
created_at: json.purchased_at
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
return {
|
|
508
|
-
data,
|
|
509
|
-
meta
|
|
510
|
-
};
|
|
465
|
+
return this._giftSubscriptions.service.browsePurchaseEvents(options, filter);
|
|
511
466
|
}
|
|
512
467
|
|
|
513
468
|
async getGiftRedemptionEvents(options = {}, filter) {
|
|
514
|
-
options
|
|
515
|
-
...options,
|
|
516
|
-
withRelated: ['redeemer', 'tier'],
|
|
517
|
-
filter: 'redeemer_member_id:-null+custom:true',
|
|
518
|
-
useBasicCount: true,
|
|
519
|
-
mongoTransformer: chainTransformers(
|
|
520
|
-
// First set the filter manually
|
|
521
|
-
replaceCustomFilterTransformer(filter),
|
|
522
|
-
|
|
523
|
-
// Map the used keys in that filter
|
|
524
|
-
...mapKeys({
|
|
525
|
-
'data.created_at': 'redeemed_at',
|
|
526
|
-
'data.member_id': 'redeemer_member_id'
|
|
527
|
-
})
|
|
528
|
-
)
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
if (options.order) {
|
|
532
|
-
options.order = options.order.replace(/created_at/g, 'redeemed_at');
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
const {data: models, meta} = await this._Gift.findPage(options);
|
|
536
|
-
|
|
537
|
-
const data = models.map((model) => {
|
|
538
|
-
const json = model.toJSON(options);
|
|
539
|
-
|
|
540
|
-
return {
|
|
541
|
-
type: 'gift_redemption_event',
|
|
542
|
-
data: {
|
|
543
|
-
id: json.id,
|
|
544
|
-
member: json.redeemer || null,
|
|
545
|
-
member_id: json.redeemer_member_id,
|
|
546
|
-
tier_name: json.tier?.name,
|
|
547
|
-
cadence: json.cadence,
|
|
548
|
-
duration: json.duration,
|
|
549
|
-
amount: json.amount,
|
|
550
|
-
currency: json.currency,
|
|
551
|
-
created_at: json.redeemed_at
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
return {
|
|
557
|
-
data,
|
|
558
|
-
meta
|
|
559
|
-
};
|
|
469
|
+
return this._giftSubscriptions.service.browseRedemptionEvents(options, filter);
|
|
560
470
|
}
|
|
561
471
|
|
|
562
472
|
async getGiftEndedEvents(options = {}, filter) {
|
|
@@ -34,7 +34,7 @@ const CUSTOM_FIELDS_EDITED_ACTION = 'custom_fields_edited';
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* @typedef {object} IGiftServiceWrapper
|
|
37
|
-
* @prop {{
|
|
37
|
+
* @prop {{getMemberPresentations: (memberIds: string[]) => Promise<Map<string, {cadence: 'month' | 'year', currency: string, amount: number}>>}} service
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
module.exports = class MemberBREADService {
|
|
@@ -347,7 +347,7 @@ module.exports = class MemberBREADService {
|
|
|
347
347
|
* @private
|
|
348
348
|
* Fetches active redeemed gifts for any gift-status members in the input list.
|
|
349
349
|
* @param {import('bookshelf').Model[]} members - Bookshelf member models
|
|
350
|
-
* @returns {Promise<Map<string, {cadence: 'month' | 'year', currency: string, amount: number}>>} keyed by member.id →
|
|
350
|
+
* @returns {Promise<Map<string, {cadence: 'month' | 'year', currency: string, amount: number}>>} keyed by member.id → stable gift presentation
|
|
351
351
|
*/
|
|
352
352
|
async fetchActiveGiftsForMembers(members) {
|
|
353
353
|
const giftMemberIds = members
|
|
@@ -359,7 +359,7 @@ module.exports = class MemberBREADService {
|
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
try {
|
|
362
|
-
return await this.giftService.service.
|
|
362
|
+
return await this.giftService.service.getMemberPresentations(giftMemberIds);
|
|
363
363
|
} catch (e) {
|
|
364
364
|
logging.error(`Failed to load active gifts for members - ${giftMemberIds.join(', ')}.`);
|
|
365
365
|
logging.error(e);
|
|
@@ -14,7 +14,6 @@ class PaymentsService {
|
|
|
14
14
|
* @param {import('../../../offers/application/offers-api')} deps.offersAPI
|
|
15
15
|
* @param {import('../../../stripe/stripe-api')} deps.stripeAPIService
|
|
16
16
|
* @param {{get(key: string): any}} deps.settingsCache
|
|
17
|
-
* @param {{service: import('../../../gifts/gift-service').GiftService}} deps.giftService
|
|
18
17
|
*/
|
|
19
18
|
constructor(deps) {
|
|
20
19
|
/** @private */
|
|
@@ -31,9 +30,6 @@ class PaymentsService {
|
|
|
31
30
|
this.stripeAPIService = deps.stripeAPIService;
|
|
32
31
|
/** @private */
|
|
33
32
|
this.settingsCache = deps.settingsCache;
|
|
34
|
-
/** @private */
|
|
35
|
-
this.giftService = deps.giftService;
|
|
36
|
-
|
|
37
33
|
DomainEvents.subscribe(OfferCreatedEvent, async (event) => {
|
|
38
34
|
await this.getCouponForOffer(event.data.offer.id);
|
|
39
35
|
});
|
|
@@ -65,7 +61,7 @@ class PaymentsService {
|
|
|
65
61
|
* @param {Tier.Cadence} params.cadence
|
|
66
62
|
* @param {Offer} [params.offer]
|
|
67
63
|
* @param {Member} [params.member]
|
|
68
|
-
* @param {
|
|
64
|
+
* @param {number|null} [params.giftTrialDays]
|
|
69
65
|
* @param {Object.<string, any>} [params.metadata]
|
|
70
66
|
* @param {string} params.successUrl
|
|
71
67
|
* @param {string} params.cancelUrl
|
|
@@ -73,7 +69,7 @@ class PaymentsService {
|
|
|
73
69
|
*
|
|
74
70
|
* @returns {Promise<URL>}
|
|
75
71
|
*/
|
|
76
|
-
async getPaymentLink({tier, cadence, offer, member,
|
|
72
|
+
async getPaymentLink({tier, cadence, offer, member, giftTrialDays, metadata, successUrl, cancelUrl, email}) {
|
|
77
73
|
let coupon = null;
|
|
78
74
|
let trialDays = null;
|
|
79
75
|
if (offer) {
|
|
@@ -94,12 +90,10 @@ class PaymentsService {
|
|
|
94
90
|
}
|
|
95
91
|
}
|
|
96
92
|
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
trialDays = Math.min(remainingDays, 730); // Stripe max trial period
|
|
102
|
-
}
|
|
93
|
+
// Gift subscriptions owns the continuation calculation. This adapter only
|
|
94
|
+
// translates the stable decision into the recurring Stripe checkout.
|
|
95
|
+
if (trialDays === null && giftTrialDays !== undefined) {
|
|
96
|
+
trialDays = giftTrialDays;
|
|
103
97
|
}
|
|
104
98
|
|
|
105
99
|
let customer = null;
|
|
@@ -163,62 +157,6 @@ class PaymentsService {
|
|
|
163
157
|
return session.url;
|
|
164
158
|
}
|
|
165
159
|
|
|
166
|
-
/**
|
|
167
|
-
* @param {object} params
|
|
168
|
-
* @param {import('../../../tiers/tier')} params.tier
|
|
169
|
-
* @param {'month'|'year'} params.cadence
|
|
170
|
-
* @param {number} params.duration
|
|
171
|
-
* @param {string} params.successUrl
|
|
172
|
-
* @param {string} params.cancelUrl
|
|
173
|
-
* @param {object} params.metadata
|
|
174
|
-
* @param {object} [params.member]
|
|
175
|
-
* @param {boolean} params.isAuthenticated
|
|
176
|
-
* @param {string} [params.email]
|
|
177
|
-
*
|
|
178
|
-
* @returns {Promise<string>}
|
|
179
|
-
*/
|
|
180
|
-
async getGiftPaymentLink({tier, cadence, duration, metadata, successUrl, cancelUrl, member, isAuthenticated, email}) {
|
|
181
|
-
let customer = null;
|
|
182
|
-
if (member && isAuthenticated) {
|
|
183
|
-
customer = await this.getCustomerForMember(member);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const amount = tier.getPrice(cadence);
|
|
187
|
-
const currency = tier.currency.toLowerCase();
|
|
188
|
-
|
|
189
|
-
const token = this.giftService.service.generateToken();
|
|
190
|
-
|
|
191
|
-
const successUrlObj = new URL(successUrl);
|
|
192
|
-
successUrlObj.searchParams.set('stripe', 'gift-purchase-success');
|
|
193
|
-
successUrlObj.searchParams.set('gift_token', token);
|
|
194
|
-
successUrlObj.searchParams.set('gift_tier', tier.id.toHexString());
|
|
195
|
-
successUrlObj.searchParams.set('gift_cadence', cadence);
|
|
196
|
-
|
|
197
|
-
const data = {
|
|
198
|
-
amount,
|
|
199
|
-
currency,
|
|
200
|
-
tierName: tier.name,
|
|
201
|
-
cadence,
|
|
202
|
-
duration,
|
|
203
|
-
metadata: {
|
|
204
|
-
...metadata,
|
|
205
|
-
ghost_gift: 'true',
|
|
206
|
-
gift_token: token,
|
|
207
|
-
tier_id: tier.id.toHexString(),
|
|
208
|
-
cadence,
|
|
209
|
-
duration: String(duration)
|
|
210
|
-
},
|
|
211
|
-
successUrl: successUrlObj.toString(),
|
|
212
|
-
cancelUrl,
|
|
213
|
-
customer,
|
|
214
|
-
customerEmail: !customer && email ? email : null
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
const session = await this.stripeAPIService.createGiftCheckoutSession(data);
|
|
218
|
-
|
|
219
|
-
return session.url;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
160
|
async getCustomerForMember(member) {
|
|
223
161
|
const rows = await this.StripeCustomerModel.where({
|
|
224
162
|
member_id: member.id
|
|
@@ -47,6 +47,9 @@ let membersApi;
|
|
|
47
47
|
let verificationTrigger;
|
|
48
48
|
|
|
49
49
|
const buildImporterDeps = ({stripeAPIService}) => {
|
|
50
|
+
// Required here, not statically: boot builds the custom fields services before this
|
|
51
|
+
// one (the exporter below relies on the same).
|
|
52
|
+
const customFields = require('../members-custom-fields');
|
|
50
53
|
return {
|
|
51
54
|
getTimezone: () => settingsCache.get('timezone'),
|
|
52
55
|
// A getter rather than a value because the threshold is an operator
|
|
@@ -81,7 +84,11 @@ const buildImporterDeps = ({stripeAPIService}) => {
|
|
|
81
84
|
knex: db.knex,
|
|
82
85
|
urlFor: urlUtils.urlFor.bind(urlUtils),
|
|
83
86
|
stripeAPIService,
|
|
84
|
-
productRepository: membersApi.productRepository
|
|
87
|
+
productRepository: membersApi.productRepository,
|
|
88
|
+
customFields: {
|
|
89
|
+
definitions: customFields.definitions,
|
|
90
|
+
values: customFields.values
|
|
91
|
+
}
|
|
85
92
|
};
|
|
86
93
|
};
|
|
87
94
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DbCustomFieldValueWithField = exports.DbCustomFieldValue = exports.DbCustomField = exports.FieldStatusSchema = exports.FIELD_STATUS = void 0;
|
|
3
|
+
exports.DbCustomFieldValueWithField = exports.StoredCompositeValue = exports.DbCustomFieldValue = exports.DbCustomField = exports.FieldStatusSchema = exports.FIELD_STATUS = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const custom_field_types_1 = require("@tryghost/custom-field-types");
|
|
6
6
|
const db_date_1 = require("../../lib/db-date");
|
|
@@ -37,6 +37,13 @@ exports.DbCustomFieldValue = zod_1.z.object({
|
|
|
37
37
|
created_at: db_date_1.DbDate,
|
|
38
38
|
updated_at: db_date_1.DbDate.nullable()
|
|
39
39
|
});
|
|
40
|
+
// A composite value once decoded: sub-field keys to values, and no narrower. Which
|
|
41
|
+
// sub-fields a composite has is its field type's business, not the row's.
|
|
42
|
+
//
|
|
43
|
+
// It doubles as the guard on a stored blob. A JSON column can just as easily hold an
|
|
44
|
+
// array, a null or a bare number, and a record rejects all three — so parsing against
|
|
45
|
+
// this is what narrows the type, with no assertion needed.
|
|
46
|
+
exports.StoredCompositeValue = zod_1.z.record(zod_1.z.string(), zod_1.z.unknown());
|
|
40
47
|
// The value join a read needs: the field's identity and type travel with the
|
|
41
48
|
// stored columns, so a row can be decoded without a second lookup. `type` is
|
|
42
49
|
// parsed as the field-type enum, which narrows it with no cast.
|
|
@@ -44,6 +44,14 @@ export const DbCustomFieldValue = z.object({
|
|
|
44
44
|
|
|
45
45
|
type CustomFieldValueRow = z.infer<typeof DbCustomFieldValue>;
|
|
46
46
|
|
|
47
|
+
// A composite value once decoded: sub-field keys to values, and no narrower. Which
|
|
48
|
+
// sub-fields a composite has is its field type's business, not the row's.
|
|
49
|
+
//
|
|
50
|
+
// It doubles as the guard on a stored blob. A JSON column can just as easily hold an
|
|
51
|
+
// array, a null or a bare number, and a record rejects all three — so parsing against
|
|
52
|
+
// this is what narrows the type, with no assertion needed.
|
|
53
|
+
export const StoredCompositeValue = z.record(z.string(), z.unknown());
|
|
54
|
+
|
|
47
55
|
// The value join a read needs: the field's identity and type travel with the
|
|
48
56
|
// stored columns, so a row can be decoded without a second lookup. `type` is
|
|
49
57
|
// parsed as the field-type enum, which narrows it with no cast.
|