ghost 6.55.0 → 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-custom-field-types-0.0.0.tgz +0 -0
- package/components/tryghost-kg-default-cards-10.3.3.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/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-sjHLx5dy.js → account-migration-D3O_yVck.js} +1 -1
- package/core/built/admin/assets/activitypub/{account-migration-DoYXtnZ8.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-Bxeh6MKW.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-D8sFfdpC.js → dist-BEfX-0aW.js} +12 -12
- package/core/built/admin/assets/activitypub/{domain-CWueFW6q.js → domain-AaDlZlrA.js} +9 -9
- package/core/built/admin/assets/activitypub/{edit-profile-BGxPU7N5.js → edit-profile-DPi8Tl5M.js} +945 -945
- package/core/built/admin/assets/activitypub/{explore-DBK-u0Ch.js → explore-CxTzjILQ.js} +8 -8
- package/core/built/admin/assets/activitypub/{feed-Bcir5RQZ.js → feed-DPv5x2MX.js} +33 -33
- package/core/built/admin/assets/activitypub/{field-BV-CIT3d.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-yC0nfvzl.js → inbox-DSrF_i1O.js} +85 -85
- package/core/built/admin/assets/activitypub/{label-DTRS9TDk.js → label-CPjFBbo7.js} +3 -3
- package/core/built/admin/assets/activitypub/layout-CTgrezN7.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-Dwl9t0pb.js → moderation-BkDC1XVZ.js} +11 -11
- package/core/built/admin/assets/activitypub/{note-B-zKsZ7r.js → note-xEyH4xT-.js} +7 -7
- package/core/built/admin/assets/activitypub/{notifications-DjJZD54t.js → notifications-DClaL3ui.js} +9 -9
- package/core/built/admin/assets/activitypub/{preferences-CoU8vs6d.js → preferences-DpnOa-4Z.js} +20 -20
- package/core/built/admin/assets/activitypub/{profile-BAsaJekx.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-CLH3OVTP.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-DA6pNJ-Q.js → settings-CV2fFu6D.js} +13 -13
- package/core/built/admin/assets/activitypub/{site-CQD42Pw5.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-Cg0saow1.js → tabs-BUbz7tea.js} +317 -315
- 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-Br4aOWOh.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-DjEWNhp3.js → audience-CkBb2LlO.js} +1 -1
- package/core/built/admin/assets/{automated-emails-DRy7qY-J.js → automated-emails-6t2bIRWf.js} +1 -1
- package/core/built/admin/assets/{automations-Bx3VcFIL.js → automations-cMllU545.js} +1 -1
- package/core/built/admin/assets/{bluesky-sharing-ClMd0-Ft.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-BD0U2ygg.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-fjQKRVyY.js → chart-helpers-DV0FkdcD.js} +1 -1
- package/core/built/admin/assets/{checkbox-CWa28lgO.js → checkbox-BIl077a0.js} +1 -1
- package/core/built/admin/assets/{chunk.481.6c7395a49484bb4583aa.js → chunk.332.05991a101d67f732dec3.js} +43 -42
- 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-CCr0rBWS.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-BFp58EMk.js → date-range-select-dXc-GsVe.js} +1 -1
- package/core/built/admin/assets/{disabled-sources-indicator-CUxMfiPa.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-B5ogXUBa.js +1 -0
- package/core/built/admin/assets/{dropzone-DlK-K2DQ.js → dropzone-BnFG7dDP.js} +1 -1
- package/core/built/admin/assets/{edit-profile-BKT-REJw.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-ClUpJZOp.js → explore-Ca1y8HW_.js} +1 -1
- package/core/built/admin/assets/{feed-DF92dUMP.js → feed-x4iFMBP4.js} +1 -1
- package/core/built/admin/assets/{field-Do7lieBA.js → field-ChCAabZg.js} +1 -1
- package/core/built/admin/assets/filter-sources-LdtH1e-T.js +1 -0
- package/core/built/admin/assets/filters-CLehPo_D.js +1 -0
- package/core/built/admin/assets/filters-CjVKRP8U.js +1 -0
- package/core/built/admin/assets/{ghost-c4057474943effc568c5659ccc4909d7.js → ghost-7f01131115186d1af84ead76e79646dd.js} +149 -129
- package/core/built/admin/assets/{ghost-a9c788f6f0b1ea6cf0f14ca4b13f4496.css → ghost-d38c30b866e59f2e06a357b5eb844fe5.css} +1 -1
- package/core/built/admin/assets/{ghost-dark-db36d795d21c61426837df40af270966.css → ghost-dark-1bffd5099ba7a749303133efacf8480b.css} +1 -1
- package/core/built/admin/assets/{gift-link-modal-f9VIMNDv.js → gift-link-modal-Buqh2vXh.js} +1 -1
- package/core/built/admin/assets/{growth-B3I6gNLm.js → growth-DajOBdN0.js} +1 -1
- package/core/built/admin/assets/{growth-CVw1My4S.js → growth-Dy2UOSay.js} +2 -2
- package/core/built/admin/assets/{inbox-CFBSu4Ed.js → inbox-BUOLDoji.js} +12 -12
- 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 +9535 -9527
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +124 -124
- package/core/built/admin/assets/{koenig-lexical-f8vHRYvz.js → koenig-lexical-BFc4yFed.js} +86 -86
- package/core/built/admin/assets/{kpi-card-DSap9rAy.js → kpi-card-BN-E6WYX.js} +1 -1
- package/core/built/admin/assets/{kpi-card-DU0rn9Cj.js → kpi-card-CCt-qeWD.js} +1 -1
- package/core/built/admin/assets/{kpi-helpers-Dz33AV6h.js → kpi-helpers-DlxTbTs4.js} +1 -1
- package/core/built/admin/assets/{kpi-tabs-BtTTrKvJ.js → kpi-tabs-BlcUttpn.js} +1 -1
- package/core/built/admin/assets/{label-DS8Mi6G5.js → label-AVrxwmsz.js} +1 -1
- package/core/built/admin/assets/{label-picker-1DvSuLA1.js → label-picker-DVnpu_IF.js} +1 -1
- 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-CQpVFJu4.js → members-oLPiSkXD.js} +2 -2
- package/core/built/admin/assets/modals-CB7v-k3T.js +31 -0
- package/core/built/admin/assets/{moderation-DySbgyUS.js → moderation-CQ3urTFE.js} +1 -1
- package/core/built/admin/assets/newsletter-rbeDX9Wk.js +1 -0
- package/core/built/admin/assets/newsletters-vt3Ni1Ov.js +1 -0
- package/core/built/admin/assets/{note-C8kxrz6w.js → note-Dk877BTv.js} +1 -1
- package/core/built/admin/assets/{notifications-CgtSfX7t.js → notifications-CPlLjPxO.js} +1 -1
- package/core/built/admin/assets/{onboarding-route-4qtziA9d.js → onboarding-route-DdStOtjy.js} +1 -1
- package/core/built/admin/assets/{overview-Bf2sbznq.js → overview--4V-kx9c.js} +1 -1
- package/core/built/admin/assets/overview-DSLv30oz.js +1 -0
- package/core/built/admin/assets/{page-header-B3Wb9Jqv.js → page-header-pp4dWmOS.js} +1 -1
- package/core/built/admin/assets/{post-analytics-We-ko5Cb.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-B6UynTGb.js → post-analytics-provider-Btml5vJI.js} +1 -1
- package/core/built/admin/assets/{post-share-modal-DFfO93_0.js → post-share-modal-AcUZkbfL.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/{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-WXNeWyU1.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-DsgW3wbg.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-Bb_FCl7e.js → sort-button-Df4t2AL8.js} +1 -1
- package/core/built/admin/assets/{source-icon-BeaRxUn9.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-Bjj_kmJ1.js → stats-C_lfxZAw.js} +1 -1
- package/core/built/admin/assets/{stats-view-BxPbW6K1.js → stats-view-Cxot1iD8.js} +1 -1
- package/core/built/admin/assets/{step-1-B1e3-1F8.js → step-1-ogAA4lDr.js} +1 -1
- package/core/built/admin/assets/{step-2-C5WaeBJo.js → step-2-C5Xini-7.js} +1 -1
- package/core/built/admin/assets/{step-3-B46iVPwu.js → step-3-CZv1FV81.js} +2 -2
- package/core/built/admin/assets/{switch-z5Y6Uzt6.js → switch-CyQcwMAv.js} +1 -1
- package/core/built/admin/assets/{table-CB-4_HBJ.js → table-DFj1wiYv.js} +1 -1
- package/core/built/admin/assets/{tabs-CCEgKYzq.js → tabs-D4y1gqUd.js} +1 -1
- package/core/built/admin/assets/{tags-Cg2VJGmG.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/{toggle-group-b3IlxvhV.js → toggle-group-R2QMFvXW.js} +1 -1
- package/core/built/admin/assets/{topic-filter-DAFT87tQ.js → topic-filter-DGDxDalo.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data-S0FTd43s.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-CIaiHOVb.js → use-growth-stats-aNXJOmQr.js} +1 -1
- package/core/built/admin/assets/{use-post-referrers-Cq2vBPrA.js → use-post-referrers-CG0SZioj.js} +1 -1
- package/core/built/admin/assets/{use-reply-chain-data-DBDRtGu-.js → use-reply-chain-data-RLdPKRmS.js} +1 -1
- package/core/built/admin/assets/{use-simple-pagination-CjYNxdwe.js → use-simple-pagination-DgcF69KI.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-query-falHAtuK.js → use-tinybird-query-C1R_Kbmy.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-D7-8ND1y.js → use-tinybird-token-C9fPjVM_.js} +1 -1
- package/core/built/admin/assets/{virtual-list-CvnC9zF2.js → virtual-list-BmTUzeoF.js} +1 -1
- package/core/built/admin/assets/{web-B_5GZRvH.js → web-BqW0b0_C.js} +1 -1
- package/core/built/admin/assets/web-Cy5GKMWM.js +2 -0
- package/core/built/admin/index.html +16 -16
- package/core/frontend/services/data/fetch-data.js +10 -5
- 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 +9 -13
- package/core/frontend/services/routing/static-routes-router.js +4 -4
- package/core/frontend/services/routing/taxonomy-router.js +6 -2
- 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/fixtures/fixtures.json +2 -2
- package/core/server/data/schema/schema.js +1 -0
- package/core/server/models/post.js +10 -1
- package/core/server/services/automations/automations-repository.ts +3 -1
- package/core/server/services/automations/database-automations-repository.js +33 -14
- package/core/server/services/automations/database-automations-repository.ts +41 -15
- 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 +3 -1
- package/core/server/services/automations/poll.ts +4 -1
- package/core/server/services/automations/service.js +5 -1
- package/core/server/services/automations/service.ts +5 -1
- 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/link-tracking/link-click-repository.js +6 -1
- package/core/server/services/link-tracking/link-click-tracking-service.js +12 -3
- package/core/server/services/member-welcome-emails/member-welcome-email-renderer.js +4 -3
- package/core/server/services/member-welcome-emails/service.js +7 -3
- package/core/server/services/members/api.js +1 -2
- package/core/server/services/members/import-export/import/importer.ts +3 -2
- package/core/server/services/members/import-export/index.js +10 -2
- package/core/server/services/members/import-export/index.ts +14 -4
- 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-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 +118 -2
- package/core/server/services/members-custom-fields/values-service.ts +134 -4
- 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 +1 -3
- 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/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/web/gift-preview/controller.js +10 -25
- package/core/shared/labs.js +2 -2
- package/package.json +10 -9
- package/pnpm-lock.yaml +28 -18
- package/pnpm-workspace.yaml +5 -4
- package/components/tryghost-kg-default-nodes-2.1.3.tgz +0 -0
- package/core/built/admin/assets/activitypub/layout-qx-bUL1k.js +0 -1
- package/core/built/admin/assets/chunk.524.cffd399783a519e404a9.js +0 -25
- package/core/built/admin/assets/chunk.582.eebf0d0b2d202bb746a5.js +0 -27
- package/core/built/admin/assets/comments-DyUSMUdj.js +0 -1
- package/core/built/admin/assets/dist-CjY-f5Z1.js +0 -1
- package/core/built/admin/assets/domain-C0bV2UV8.js +0 -1
- package/core/built/admin/assets/editor-Dp865O-4.js +0 -8
- package/core/built/admin/assets/filter-sources-BV2rnpfA.js +0 -1
- package/core/built/admin/assets/filters-CUXJ2Nm9.js +0 -1
- package/core/built/admin/assets/filters-DfbIWc_l.js +0 -1
- package/core/built/admin/assets/index-9Cw8z3rA.css +0 -1
- package/core/built/admin/assets/index-BGG7NckO.js +0 -67
- package/core/built/admin/assets/input-group-BSgG_lVw.js +0 -1
- package/core/built/admin/assets/labels-CDSUt4J_.js +0 -1
- package/core/built/admin/assets/layout-yQEi2qDM.js +0 -1
- package/core/built/admin/assets/link-helpers-7EYqvvHs.js +0 -1
- package/core/built/admin/assets/member-custom-fields-yOMHyAg9.js +0 -1
- package/core/built/admin/assets/member-detail-BAq7gDaa.js +0 -1
- package/core/built/admin/assets/modals-ReORvWnu.js +0 -31
- package/core/built/admin/assets/newsletter-CJQvtHqN.js +0 -1
- package/core/built/admin/assets/newsletters-B3QQXfGT.js +0 -1
- package/core/built/admin/assets/nql-BsgFMd93.js +0 -1
- package/core/built/admin/assets/overview-CBfePxcr.js +0 -1
- package/core/built/admin/assets/post-analytics-header-Bmc9su6q.js +0 -1
- package/core/built/admin/assets/preferences-DJPfHEGu.js +0 -5
- package/core/built/admin/assets/profile-DqBQp-gT.js +0 -1
- package/core/built/admin/assets/select-C5_xEt5b.js +0 -1
- package/core/built/admin/assets/settings-BwiVIXau.js +0 -4
- package/core/built/admin/assets/social-urls-BQPFEk1_.js +0 -8
- package/core/built/admin/assets/textarea-Bjccvh_E.js +0 -1
- package/core/built/admin/assets/use-filter-params-Gpoq2E1L.js +0 -1
- package/core/built/admin/assets/web-jFYWCKDn.js +0 -2
- 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 -174
- package/core/server/services/route-settings/activation-bridge.ts +0 -250
|
@@ -23,12 +23,13 @@ class GiftServiceWrapper {
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const {Gift: GiftModel} = require('../../models');
|
|
26
|
+
const {Gift: GiftModel, MemberStripeCustomer: StripeCustomerModel} = require('../../models');
|
|
27
27
|
const {GiftBookshelfRepository} = require('./gift-bookshelf-repository');
|
|
28
28
|
const {GiftService} = require('./gift-service');
|
|
29
29
|
const {GiftReminderScheduler} = require('./gift-reminder-scheduler');
|
|
30
30
|
const {GiftEmailService} = require('./gift-email-service');
|
|
31
31
|
const {GiftController} = require('./gift-controller');
|
|
32
|
+
const GiftCheckoutAdapter = require('./gift-checkout-adapter');
|
|
32
33
|
const membersService = require('../members');
|
|
33
34
|
const tiersService = require('../tiers');
|
|
34
35
|
const staffService = require('../staff');
|
|
@@ -41,6 +42,7 @@ class GiftServiceWrapper {
|
|
|
41
42
|
|
|
42
43
|
const {GhostMailer} = require('../mail');
|
|
43
44
|
const settingsCache = require('../../../shared/settings-cache');
|
|
45
|
+
const labsService = require('../../../shared/labs');
|
|
44
46
|
const urlUtils = require('../../../shared/url-utils').default;
|
|
45
47
|
const settingsHelpers = require('../settings-helpers');
|
|
46
48
|
const EmailAddressParser = require('../email-address/email-address-parser');
|
|
@@ -50,6 +52,10 @@ class GiftServiceWrapper {
|
|
|
50
52
|
const repository = new GiftBookshelfRepository({
|
|
51
53
|
GiftModel
|
|
52
54
|
});
|
|
55
|
+
const checkoutAdapter = new GiftCheckoutAdapter({
|
|
56
|
+
StripeCustomerModel,
|
|
57
|
+
getStripeApi: () => require('../stripe').api
|
|
58
|
+
});
|
|
53
59
|
|
|
54
60
|
const giftEmailService = new GiftEmailService({
|
|
55
61
|
mailer: new GhostMailer(),
|
|
@@ -77,23 +83,19 @@ class GiftServiceWrapper {
|
|
|
77
83
|
get staffServiceEmails() {
|
|
78
84
|
return staffService.api.emails;
|
|
79
85
|
},
|
|
80
|
-
giftReminderScheduler
|
|
86
|
+
giftReminderScheduler,
|
|
87
|
+
checkoutAdapter,
|
|
88
|
+
labsService,
|
|
89
|
+
settingsCache
|
|
81
90
|
});
|
|
82
91
|
|
|
83
92
|
this.controller = new GiftController({
|
|
84
|
-
service: this.service
|
|
85
|
-
tiersService
|
|
93
|
+
service: this.service
|
|
86
94
|
});
|
|
87
95
|
|
|
88
96
|
DomainEvents.subscribe(SubscriptionActivatedEvent, async (event) => {
|
|
89
97
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (!gift) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
await this.service.consume(gift.token);
|
|
98
|
+
await this.service.handlePaidSubscriptionActivation(event.data.memberId);
|
|
97
99
|
} catch (err) {
|
|
98
100
|
logging.error(err, 'Failed to consume gift on paid subscription activation');
|
|
99
101
|
}
|
|
@@ -7,9 +7,12 @@ exports.GiftService = void 0;
|
|
|
7
7
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
8
|
const errors_1 = __importDefault(require("@tryghost/errors"));
|
|
9
9
|
const logging_1 = __importDefault(require("@tryghost/logging"));
|
|
10
|
+
const zod_1 = require("zod");
|
|
10
11
|
const gift_1 = require("./gift");
|
|
12
|
+
const gift_schema_1 = require("./gift-schema");
|
|
11
13
|
const tpl_1 = __importDefault(require("@tryghost/tpl"));
|
|
12
14
|
const constants_1 = require("./constants");
|
|
15
|
+
const gift_checkout_offer_1 = require("./gift-checkout-offer");
|
|
13
16
|
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
14
17
|
const GIFT_REMINDER_LEAD_MS = constants_1.GIFT_REMINDER_LEAD_DAYS * MS_PER_DAY;
|
|
15
18
|
const GIFT_REMINDER_FLOOR_MS = constants_1.GIFT_REMINDER_FLOOR_DAYS * MS_PER_DAY;
|
|
@@ -26,11 +29,119 @@ const errorMessages = {
|
|
|
26
29
|
giftMissingConsumesAt: 'This gift is missing a "consumes at" date.',
|
|
27
30
|
giftMemberAlreadyHasGift: 'Member already has a different active gift attached.'
|
|
28
31
|
};
|
|
32
|
+
const GiftPurchaseDataSchema = zod_1.z.object({
|
|
33
|
+
token: zod_1.z.string().min(1),
|
|
34
|
+
buyerEmail: zod_1.z.string().min(1),
|
|
35
|
+
stripeCustomerId: zod_1.z.string().min(1).nullable(),
|
|
36
|
+
tierId: zod_1.z.string().min(1),
|
|
37
|
+
cadence: gift_schema_1.GiftCadenceSchema,
|
|
38
|
+
duration: zod_1.z.number().int().positive(),
|
|
39
|
+
currency: zod_1.z.string().min(1),
|
|
40
|
+
amount: zod_1.z.number().int().nonnegative(),
|
|
41
|
+
stripeCheckoutSessionId: zod_1.z.string().min(1),
|
|
42
|
+
stripePaymentIntentId: zod_1.z.string().min(1)
|
|
43
|
+
});
|
|
29
44
|
class GiftService {
|
|
30
45
|
deps;
|
|
31
46
|
constructor(deps) {
|
|
32
47
|
this.deps = deps;
|
|
33
48
|
}
|
|
49
|
+
async startCheckout(input) {
|
|
50
|
+
if (input.offerId) {
|
|
51
|
+
throw new errors_1.default.BadRequestError({
|
|
52
|
+
message: 'Bad Request.',
|
|
53
|
+
context: 'Offers cannot be applied to gift subscriptions'
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (!input.tierId) {
|
|
57
|
+
throw new errors_1.default.BadRequestError({
|
|
58
|
+
message: 'Bad Request.',
|
|
59
|
+
context: 'Expected offerId or tierId, received none'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
let resolvedDuration = null;
|
|
63
|
+
let cadence;
|
|
64
|
+
if (this.deps.labsService.isSet('giftSubCustomization')) {
|
|
65
|
+
resolvedDuration = (0, gift_checkout_offer_1.resolveGiftDuration)(input);
|
|
66
|
+
cadence = resolvedDuration.cadence;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
if (input.cadence !== 'month' && input.cadence !== 'year') {
|
|
70
|
+
const receivedCadence = input.cadence ? `"${input.cadence}"` : input.cadence;
|
|
71
|
+
throw new errors_1.default.BadRequestError({
|
|
72
|
+
message: 'Bad Request.',
|
|
73
|
+
context: `Expected cadence to be "month" or "year", received ${receivedCadence}`
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
cadence = input.cadence;
|
|
77
|
+
}
|
|
78
|
+
let tier;
|
|
79
|
+
try {
|
|
80
|
+
tier = await this.deps.tiersService.api.read(input.tierId);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
logging_1.default.error(err);
|
|
84
|
+
tier = null;
|
|
85
|
+
}
|
|
86
|
+
if (!tier) {
|
|
87
|
+
throw new errors_1.default.BadRequestError({
|
|
88
|
+
message: 'This tier does not exist.',
|
|
89
|
+
context: `Tier with id "${input.tierId}" not found`
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (tier.status === 'archived') {
|
|
93
|
+
throw new errors_1.default.NoPermissionError({
|
|
94
|
+
message: 'This tier is archived.'
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
let duration = 1;
|
|
98
|
+
let totalMonths;
|
|
99
|
+
let amount = tier.getPrice(cadence);
|
|
100
|
+
if (resolvedDuration) {
|
|
101
|
+
const plan = (0, gift_checkout_offer_1.validateGiftCheckoutOffer)({
|
|
102
|
+
tier,
|
|
103
|
+
portalPlans: this.deps.settingsCache.get('portal_plans'),
|
|
104
|
+
offer: resolvedDuration
|
|
105
|
+
});
|
|
106
|
+
cadence = plan.cadence;
|
|
107
|
+
duration = plan.duration;
|
|
108
|
+
totalMonths = plan.totalMonths;
|
|
109
|
+
amount = plan.amount;
|
|
110
|
+
}
|
|
111
|
+
const tierId = typeof tier.id === 'string' ? tier.id : tier.id.toHexString();
|
|
112
|
+
const token = this.generateToken();
|
|
113
|
+
const successUrl = new URL(input.successUrl);
|
|
114
|
+
successUrl.searchParams.set('stripe', 'gift-purchase-success');
|
|
115
|
+
successUrl.searchParams.set('gift_token', token);
|
|
116
|
+
successUrl.searchParams.set('gift_tier', tierId);
|
|
117
|
+
successUrl.searchParams.set('gift_cadence', cadence);
|
|
118
|
+
if (totalMonths !== undefined) {
|
|
119
|
+
successUrl.searchParams.set('gift_duration', String(totalMonths));
|
|
120
|
+
}
|
|
121
|
+
const customerId = input.buyer.isAuthenticated
|
|
122
|
+
? await this.deps.checkoutAdapter.getCustomerId(input.buyer)
|
|
123
|
+
: null;
|
|
124
|
+
const url = await this.deps.checkoutAdapter.createSession({
|
|
125
|
+
amount,
|
|
126
|
+
currency: tier.currency.toLowerCase(),
|
|
127
|
+
tierName: tier.name,
|
|
128
|
+
cadence,
|
|
129
|
+
duration,
|
|
130
|
+
metadata: {
|
|
131
|
+
...input.metadata,
|
|
132
|
+
ghost_gift: 'true',
|
|
133
|
+
gift_token: token,
|
|
134
|
+
tier_id: tierId,
|
|
135
|
+
cadence,
|
|
136
|
+
duration: String(duration)
|
|
137
|
+
},
|
|
138
|
+
successUrl: successUrl.toString(),
|
|
139
|
+
cancelUrl: input.cancelUrl,
|
|
140
|
+
customerId,
|
|
141
|
+
customerEmail: customerId ? null : input.buyer.email
|
|
142
|
+
});
|
|
143
|
+
return { url };
|
|
144
|
+
}
|
|
34
145
|
generateToken() {
|
|
35
146
|
/**
|
|
36
147
|
* Combinations: 62^12 ≈ 3.23 × 10^21 (~3.23 sextillion)
|
|
@@ -43,11 +154,17 @@ class GiftService {
|
|
|
43
154
|
}
|
|
44
155
|
return token;
|
|
45
156
|
}
|
|
46
|
-
async
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
|
|
157
|
+
async completePurchase(input) {
|
|
158
|
+
const parsed = GiftPurchaseDataSchema.safeParse(input);
|
|
159
|
+
if (!parsed.success) {
|
|
160
|
+
const issue = parsed.error.issues[0];
|
|
161
|
+
throw new errors_1.default.ValidationError({
|
|
162
|
+
message: 'Invalid gift purchase data.',
|
|
163
|
+
property: issue.path.join('.'),
|
|
164
|
+
context: issue.message
|
|
165
|
+
});
|
|
50
166
|
}
|
|
167
|
+
const data = parsed.data;
|
|
51
168
|
if (await this.deps.giftRepository.existsByCheckoutSessionId(data.stripeCheckoutSessionId)) {
|
|
52
169
|
return false;
|
|
53
170
|
}
|
|
@@ -60,7 +177,7 @@ class GiftService {
|
|
|
60
177
|
buyerMemberId: member?.id ?? null,
|
|
61
178
|
tierId: data.tierId,
|
|
62
179
|
cadence: data.cadence,
|
|
63
|
-
duration,
|
|
180
|
+
duration: data.duration,
|
|
64
181
|
currency: data.currency,
|
|
65
182
|
amount: data.amount,
|
|
66
183
|
stripeCheckoutSessionId: data.stripeCheckoutSessionId,
|
|
@@ -80,7 +197,7 @@ class GiftService {
|
|
|
80
197
|
currency: data.currency,
|
|
81
198
|
tierName: tier.name,
|
|
82
199
|
cadence: data.cadence,
|
|
83
|
-
duration
|
|
200
|
+
duration: data.duration
|
|
84
201
|
});
|
|
85
202
|
}
|
|
86
203
|
catch (err) {
|
|
@@ -92,7 +209,7 @@ class GiftService {
|
|
|
92
209
|
token: data.token,
|
|
93
210
|
tierName: tier.name,
|
|
94
211
|
cadence: data.cadence,
|
|
95
|
-
duration,
|
|
212
|
+
duration: data.duration,
|
|
96
213
|
expiresAt: gift.expiresAt
|
|
97
214
|
});
|
|
98
215
|
}
|
|
@@ -101,10 +218,7 @@ class GiftService {
|
|
|
101
218
|
}
|
|
102
219
|
return true;
|
|
103
220
|
}
|
|
104
|
-
|
|
105
|
-
return this.deps.giftRepository.getByToken(token);
|
|
106
|
-
}
|
|
107
|
-
async assertRedeemable(gift, memberStatus) {
|
|
221
|
+
assertRedeemable(gift, memberStatus) {
|
|
108
222
|
const redeemableCheck = gift.checkRedeemable(memberStatus);
|
|
109
223
|
if (!redeemableCheck.redeemable) {
|
|
110
224
|
switch (redeemableCheck.reason) {
|
|
@@ -143,45 +257,25 @@ class GiftService {
|
|
|
143
257
|
}
|
|
144
258
|
return gift;
|
|
145
259
|
}
|
|
146
|
-
async getRedeemable(
|
|
147
|
-
const gift = await this.deps.giftRepository.getByToken(token);
|
|
260
|
+
async getRedeemable(input) {
|
|
261
|
+
const gift = await this.deps.giftRepository.getByToken(input.token);
|
|
148
262
|
if (!gift) {
|
|
149
263
|
throw new errors_1.default.NotFoundError({ message: (0, tpl_1.default)(errorMessages.giftNotFound) });
|
|
150
264
|
}
|
|
151
|
-
|
|
152
|
-
return gift;
|
|
265
|
+
this.assertRedeemable(gift, input.memberStatus);
|
|
266
|
+
return this.serializeRedemption(gift);
|
|
153
267
|
}
|
|
154
|
-
async redeem(
|
|
268
|
+
async redeem(input) {
|
|
155
269
|
const run = async (transacting) => {
|
|
156
|
-
const member = await this.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
throw new errors_1.default.NotFoundError({ message: (0, tpl_1.default)(errorMessages.giftNotFound) });
|
|
163
|
-
}
|
|
164
|
-
if (options.newMember) {
|
|
165
|
-
await this.assertRedeemable(gift, null);
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
await this.assertRedeemable(gift, member.get('status'));
|
|
169
|
-
}
|
|
170
|
-
const redeemed = gift.redeem({ memberId });
|
|
171
|
-
await this.deps.memberRepository.update({
|
|
172
|
-
products: [{
|
|
173
|
-
id: redeemed.tierId,
|
|
174
|
-
expiry_at: redeemed.consumesAt
|
|
175
|
-
}],
|
|
176
|
-
status: 'gift'
|
|
177
|
-
}, { id: memberId, transacting });
|
|
178
|
-
await this.deps.giftRepository.update(redeemed, { transacting });
|
|
179
|
-
// Gift members receive the paid welcome email, as they receive access to paid content
|
|
180
|
-
await this.deps.memberRepository.triggerMemberSignupAutomation(memberId, member.get('email'), 'paid', { transacting });
|
|
181
|
-
return { redeemed, member };
|
|
270
|
+
const { redeemed, member } = await this.redeemGift(input.token, input.memberId, {
|
|
271
|
+
transacting,
|
|
272
|
+
newMember: input.newMember
|
|
273
|
+
});
|
|
274
|
+
const redemption = await this.serializeRedemption(redeemed);
|
|
275
|
+
return { redeemed, member, redemption };
|
|
182
276
|
};
|
|
183
|
-
const { redeemed, member } =
|
|
184
|
-
? await run(
|
|
277
|
+
const { redeemed, member, redemption } = input.transacting
|
|
278
|
+
? await run(input.transacting)
|
|
185
279
|
: await this.deps.giftRepository.transaction(run);
|
|
186
280
|
const notify = async () => {
|
|
187
281
|
try {
|
|
@@ -204,14 +298,43 @@ class GiftService {
|
|
|
204
298
|
}
|
|
205
299
|
await this.deps.giftReminderScheduler.scheduleFor(redeemed);
|
|
206
300
|
};
|
|
207
|
-
if (
|
|
301
|
+
if (input.transacting) {
|
|
208
302
|
// Only notify once the transaction has finished
|
|
209
|
-
|
|
303
|
+
input.transacting.executionPromise.then(notify, () => { });
|
|
210
304
|
}
|
|
211
305
|
else {
|
|
212
306
|
await notify();
|
|
213
307
|
}
|
|
214
|
-
return
|
|
308
|
+
return redemption;
|
|
309
|
+
}
|
|
310
|
+
async redeemGift(token, memberId, options) {
|
|
311
|
+
const { transacting } = options;
|
|
312
|
+
const member = await this.deps.memberRepository.get({ id: memberId }, { transacting, forUpdate: true });
|
|
313
|
+
if (!member) {
|
|
314
|
+
throw new errors_1.default.NotFoundError({ message: `Member not found: ${memberId}` });
|
|
315
|
+
}
|
|
316
|
+
const gift = await this.deps.giftRepository.getByToken(token, { transacting, forUpdate: true });
|
|
317
|
+
if (!gift) {
|
|
318
|
+
throw new errors_1.default.NotFoundError({ message: (0, tpl_1.default)(errorMessages.giftNotFound) });
|
|
319
|
+
}
|
|
320
|
+
if (options.newMember) {
|
|
321
|
+
this.assertRedeemable(gift, null);
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
this.assertRedeemable(gift, member.get('status'));
|
|
325
|
+
}
|
|
326
|
+
const redeemed = gift.redeem({ memberId });
|
|
327
|
+
await this.deps.memberRepository.update({
|
|
328
|
+
products: [{
|
|
329
|
+
id: redeemed.tierId,
|
|
330
|
+
expiry_at: redeemed.consumesAt
|
|
331
|
+
}],
|
|
332
|
+
status: 'gift'
|
|
333
|
+
}, { id: memberId, transacting });
|
|
334
|
+
await this.deps.giftRepository.update(redeemed, { transacting });
|
|
335
|
+
// Gift members receive the paid welcome email, as they receive access to paid content
|
|
336
|
+
await this.deps.memberRepository.triggerMemberSignupAutomation(memberId, member.get('email'), 'paid', { transacting });
|
|
337
|
+
return { redeemed, member };
|
|
215
338
|
}
|
|
216
339
|
async getActiveByMember(memberId, options = {}) {
|
|
217
340
|
if (!memberId) {
|
|
@@ -232,7 +355,66 @@ class GiftService {
|
|
|
232
355
|
const diffDays = Math.ceil((gift.consumesAt.getTime() - now.getTime()) / MS_PER_DAY);
|
|
233
356
|
return Math.max(0, diffDays);
|
|
234
357
|
}
|
|
235
|
-
async
|
|
358
|
+
async preparePaidContinuation({ memberId, memberStatus }) {
|
|
359
|
+
if (memberStatus !== 'gift') {
|
|
360
|
+
throw new errors_1.default.BadRequestError({
|
|
361
|
+
message: 'Bad Request.',
|
|
362
|
+
context: 'Member does not have an active gift subscription'
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
const gift = await this.getActiveByMember(memberId);
|
|
366
|
+
if (!gift) {
|
|
367
|
+
throw new errors_1.default.BadRequestError({
|
|
368
|
+
message: 'Bad Request.',
|
|
369
|
+
context: 'No active gift subscription found for member'
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
const remainingDays = this.getRemainingActiveDays(gift);
|
|
373
|
+
return {
|
|
374
|
+
tierId: gift.tierId,
|
|
375
|
+
cadence: gift.cadence,
|
|
376
|
+
trialDays: remainingDays > 0 ? Math.min(remainingDays, 730) : null
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
async getMemberPresentations(memberIds) {
|
|
380
|
+
const gifts = await this.getActiveByMembers(memberIds);
|
|
381
|
+
const presentations = new Map();
|
|
382
|
+
for (const [memberId, gift] of gifts) {
|
|
383
|
+
presentations.set(memberId, {
|
|
384
|
+
cadence: gift.cadence,
|
|
385
|
+
currency: gift.currency,
|
|
386
|
+
amount: gift.amount
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
return presentations;
|
|
390
|
+
}
|
|
391
|
+
async getPreview(token) {
|
|
392
|
+
const gift = await this.deps.giftRepository.getByToken(token);
|
|
393
|
+
if (!gift) {
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
const tier = await this.deps.tiersService.api.read(gift.tierId);
|
|
397
|
+
if (!tier) {
|
|
398
|
+
throw new errors_1.default.NotFoundError({ message: `Tier not found for gift: ${gift.token}` });
|
|
399
|
+
}
|
|
400
|
+
const tierJSON = tier.toJSON();
|
|
401
|
+
return {
|
|
402
|
+
cadence: gift.cadence,
|
|
403
|
+
duration: gift.duration,
|
|
404
|
+
tier: {
|
|
405
|
+
id: tierJSON.id,
|
|
406
|
+
name: tierJSON.name
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
browsePurchaseEvents(options, filter) {
|
|
411
|
+
return this.deps.giftRepository.browsePurchaseEvents(options, filter);
|
|
412
|
+
}
|
|
413
|
+
browseRedemptionEvents(options, filter) {
|
|
414
|
+
return this.deps.giftRepository.browseRedemptionEvents(options, filter);
|
|
415
|
+
}
|
|
416
|
+
async reassignRedeemer(input) {
|
|
417
|
+
const { giftId, memberId } = input;
|
|
236
418
|
const run = async (transacting) => {
|
|
237
419
|
const gift = await this.deps.giftRepository.getById(giftId, { transacting, forUpdate: true });
|
|
238
420
|
if (!gift) {
|
|
@@ -284,11 +466,11 @@ class GiftService {
|
|
|
284
466
|
await this.deps.giftRepository.update(reassignedGift, { transacting });
|
|
285
467
|
return reassignedGift;
|
|
286
468
|
};
|
|
287
|
-
|
|
288
|
-
? run(
|
|
289
|
-
: this.deps.giftRepository.transaction(run);
|
|
469
|
+
await (input.transacting
|
|
470
|
+
? run(input.transacting)
|
|
471
|
+
: this.deps.giftRepository.transaction(run));
|
|
290
472
|
}
|
|
291
|
-
async
|
|
473
|
+
async handlePaymentRefund({ paymentIntentId }) {
|
|
292
474
|
const gift = await this.deps.giftRepository.getByPaymentIntentId(paymentIntentId);
|
|
293
475
|
if (!gift) {
|
|
294
476
|
return false;
|
|
@@ -311,6 +493,13 @@ class GiftService {
|
|
|
311
493
|
});
|
|
312
494
|
return true;
|
|
313
495
|
}
|
|
496
|
+
async handlePaidSubscriptionActivation(memberId) {
|
|
497
|
+
const gift = await this.getActiveByMember(memberId);
|
|
498
|
+
if (!gift) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
return Boolean(await this.consume(gift.token));
|
|
502
|
+
}
|
|
314
503
|
async consume(token, options = {}) {
|
|
315
504
|
const run = async (transacting) => {
|
|
316
505
|
// Fetch with a row lock to prevent race conditions under concurrency
|
|
@@ -465,5 +654,29 @@ class GiftService {
|
|
|
465
654
|
});
|
|
466
655
|
return true;
|
|
467
656
|
}
|
|
657
|
+
async serializeRedemption(gift) {
|
|
658
|
+
const tier = await this.deps.tiersService.api.read(gift.tierId);
|
|
659
|
+
if (!tier) {
|
|
660
|
+
throw new errors_1.default.InternalServerError({
|
|
661
|
+
message: `Tier ${gift.tierId} not found for gift: ${gift.token}`
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
const tierJSON = tier.toJSON();
|
|
665
|
+
return {
|
|
666
|
+
token: gift.token,
|
|
667
|
+
cadence: gift.cadence,
|
|
668
|
+
duration: gift.duration,
|
|
669
|
+
currency: gift.currency,
|
|
670
|
+
amount: gift.amount,
|
|
671
|
+
expires_at: gift.expiresAt,
|
|
672
|
+
consumes_at: gift.consumesAt,
|
|
673
|
+
tier: {
|
|
674
|
+
id: tierJSON.id,
|
|
675
|
+
name: tierJSON.name,
|
|
676
|
+
description: tierJSON.description,
|
|
677
|
+
benefits: tierJSON.benefits
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
}
|
|
468
681
|
}
|
|
469
682
|
exports.GiftService = GiftService;
|