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
|
@@ -129,7 +129,8 @@ const processStep = async ({ automationsApi, memberWelcomeEmailService, schedule
|
|
|
129
129
|
memberStatus,
|
|
130
130
|
trackOpens,
|
|
131
131
|
trackClicks,
|
|
132
|
-
automationActionRevisionId: step.automation_action_revision_id
|
|
132
|
+
automationActionRevisionId: step.automation_action_revision_id,
|
|
133
|
+
automationRunStepId: step.id
|
|
133
134
|
});
|
|
134
135
|
const mailgunMessageId = (0, mailgun_message_id_1.getMailgunMessageId)(sendResult);
|
|
135
136
|
// Only Mailgun sends can produce open events for automation emails
|
|
@@ -137,6 +138,7 @@ const processStep = async ({ automationsApi, memberWelcomeEmailService, schedule
|
|
|
137
138
|
try {
|
|
138
139
|
await automationsApi.recordEmailSent({
|
|
139
140
|
automationActionRevisionId: step.automation_action_revision_id,
|
|
141
|
+
automationRunStepId: step.id,
|
|
140
142
|
...(mailgunMessageId ? { mailgunMessageId } : {}),
|
|
141
143
|
memberEmail: member.get('email'),
|
|
142
144
|
memberId: step.member_id,
|
|
@@ -28,6 +28,7 @@ type MemberWelcomeEmailService = {
|
|
|
28
28
|
trackOpens: boolean;
|
|
29
29
|
trackClicks: boolean;
|
|
30
30
|
automationActionRevisionId: string;
|
|
31
|
+
automationRunStepId: string;
|
|
31
32
|
}) => Promise<unknown>;
|
|
32
33
|
};
|
|
33
34
|
};
|
|
@@ -202,7 +203,8 @@ const processStep = async ({
|
|
|
202
203
|
memberStatus,
|
|
203
204
|
trackOpens,
|
|
204
205
|
trackClicks,
|
|
205
|
-
automationActionRevisionId: step.automation_action_revision_id
|
|
206
|
+
automationActionRevisionId: step.automation_action_revision_id,
|
|
207
|
+
automationRunStepId: step.id
|
|
206
208
|
});
|
|
207
209
|
const mailgunMessageId = getMailgunMessageId(sendResult);
|
|
208
210
|
// Only Mailgun sends can produce open events for automation emails
|
|
@@ -210,6 +212,7 @@ const processStep = async ({
|
|
|
210
212
|
try {
|
|
211
213
|
await automationsApi.recordEmailSent({
|
|
212
214
|
automationActionRevisionId: step.automation_action_revision_id,
|
|
215
|
+
automationRunStepId: step.id,
|
|
213
216
|
...(mailgunMessageId ? {mailgunMessageId} : {}),
|
|
214
217
|
memberEmail: member.get('email'),
|
|
215
218
|
memberId: step.member_id,
|
|
@@ -41,6 +41,7 @@ const strict_1 = __importDefault(require("node:assert/strict"));
|
|
|
41
41
|
const one_at_a_time_1 = require("../../../shared/one-at-a-time");
|
|
42
42
|
const poll_1 = require("./poll");
|
|
43
43
|
const automationsApi = __importStar(require("./automations-api"));
|
|
44
|
+
const get_scheduler_idempotency_key_1 = require("./get-scheduler-idempotency-key");
|
|
44
45
|
const promises_1 = require("node:timers/promises");
|
|
45
46
|
const soonest_timer_1 = require("../../lib/soonest-timer");
|
|
46
47
|
const scheduler_poll_time_1 = require("./scheduler-poll-time");
|
|
@@ -101,7 +102,10 @@ class AutomationsService {
|
|
|
101
102
|
schedulerAdapter.schedule({
|
|
102
103
|
time: schedulerPollTime.getTime(),
|
|
103
104
|
url: url.toString(),
|
|
104
|
-
extra: {
|
|
105
|
+
extra: {
|
|
106
|
+
httpMethod: 'PUT',
|
|
107
|
+
idempotencyKey: (0, get_scheduler_idempotency_key_1.getSchedulerIdempotencyKey)(date, url)
|
|
108
|
+
}
|
|
105
109
|
});
|
|
106
110
|
}
|
|
107
111
|
catch (err) {
|
|
@@ -6,6 +6,7 @@ import type DomainEvents from '@tryghost/domain-events';
|
|
|
6
6
|
import {oneAtATime} from '../../../shared/one-at-a-time';
|
|
7
7
|
import {poll} from './poll';
|
|
8
8
|
import * as automationsApi from './automations-api';
|
|
9
|
+
import {getSchedulerIdempotencyKey} from './get-scheduler-idempotency-key';
|
|
9
10
|
import {setImmediate as flushEventLoop} from 'node:timers/promises';
|
|
10
11
|
import {SoonestTimer} from '../../lib/soonest-timer';
|
|
11
12
|
import {getSchedulerPollTime} from './scheduler-poll-time';
|
|
@@ -85,7 +86,10 @@ export class AutomationsService {
|
|
|
85
86
|
schedulerAdapter.schedule({
|
|
86
87
|
time: schedulerPollTime.getTime(),
|
|
87
88
|
url: url.toString(),
|
|
88
|
-
extra: {
|
|
89
|
+
extra: {
|
|
90
|
+
httpMethod: 'PUT',
|
|
91
|
+
idempotencyKey: getSchedulerIdempotencyKey(date, url)
|
|
92
|
+
}
|
|
89
93
|
});
|
|
90
94
|
} catch (err) {
|
|
91
95
|
logging.error({event: {name: 'automations.enqueue-poll.error'}, err, at: date.toISOString()}, 'Failed to enqueue automations poll');
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Gift Links
|
|
2
|
+
|
|
3
|
+
Gift Links covers shareable access to individual protected posts and pages without creating a membership.
|
|
4
|
+
|
|
5
|
+
## Language
|
|
6
|
+
|
|
7
|
+
**Gift Link**:
|
|
8
|
+
A revocable link that grants its holder access to one protected post or page. It does not create or redeem a gift subscription.
|
|
9
|
+
_Avoid_: Redemption link, gift-subscription link
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Gift Subscriptions
|
|
2
|
+
|
|
3
|
+
Gift Subscriptions covers prepaid, fixed-duration membership access intended to be shared and claimed. Its language spans gift purchase, gift redemption, gift expiration, gift consumption, and gift continuation into a paid subscription.
|
|
4
|
+
|
|
5
|
+
## Language
|
|
6
|
+
|
|
7
|
+
### Roles
|
|
8
|
+
|
|
9
|
+
**Buyer**:
|
|
10
|
+
The person who pays for a gift subscription. A buyer need not be a member and may also become the redeemer if eligible.
|
|
11
|
+
_Avoid_: Purchaser, recipient, redeemer
|
|
12
|
+
|
|
13
|
+
**Redeemer**:
|
|
14
|
+
The member who claims a gift subscription and receives its access. The redeemer is determined at redemption, not purchase.
|
|
15
|
+
_Avoid_: Recipient, buyer
|
|
16
|
+
|
|
17
|
+
### Purchase and claim
|
|
18
|
+
|
|
19
|
+
**Gift subscription**:
|
|
20
|
+
A prepaid, non-renewing entitlement to one membership tier for a fixed period. It begins when claimed rather than when purchased.
|
|
21
|
+
_Avoid_: Gift membership, recurring subscription
|
|
22
|
+
|
|
23
|
+
**Gift purchase**:
|
|
24
|
+
A one-time purchase that creates a gift subscription for the buyer to share.
|
|
25
|
+
_Avoid_: Gift checkout
|
|
26
|
+
|
|
27
|
+
**Redemption link**:
|
|
28
|
+
A single-use, time-limited link through which a purchased gift subscription can be claimed.
|
|
29
|
+
_Avoid_: Gift Link
|
|
30
|
+
|
|
31
|
+
**Gift redemption**:
|
|
32
|
+
The act of claiming an eligible gift subscription. The member who claims it becomes the redeemer and gifted access begins at that point.
|
|
33
|
+
_Avoid_: Gift activation
|
|
34
|
+
|
|
35
|
+
### Time and lifecycle
|
|
36
|
+
|
|
37
|
+
**Gift duration**:
|
|
38
|
+
The total length of gifted access, measured from redemption.
|
|
39
|
+
_Avoid_: Gift cadence, billing period
|
|
40
|
+
|
|
41
|
+
**Gift cadence**:
|
|
42
|
+
The monthly or yearly membership price basis used to value a gift subscription. It does not make the gift recurring.
|
|
43
|
+
_Avoid_: Gift duration, renewal interval
|
|
44
|
+
|
|
45
|
+
**Gift expiration**:
|
|
46
|
+
The end of the claim window for a purchased gift subscription that was never redeemed.
|
|
47
|
+
_Avoid_: Gift consumption
|
|
48
|
+
|
|
49
|
+
**Gift consumption**:
|
|
50
|
+
The end of a redeemed gift subscription's role in providing access, either when its duration finishes or a paid subscription takes over.
|
|
51
|
+
_Avoid_: Gift expiration, cancellation
|
|
52
|
+
|
|
53
|
+
**Gift continuation**:
|
|
54
|
+
Starting a paid subscription from gifted access while carrying the remaining gifted time forward before billing begins.
|
|
55
|
+
_Avoid_: Gift renewal
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Gifts
|
|
2
|
+
|
|
3
|
+
This module owns the gift-subscription journey. Its interface is
|
|
4
|
+
capability-oriented; callers do not receive `Gift` entities, Bookshelf models,
|
|
5
|
+
transactions, or Stripe objects.
|
|
6
|
+
|
|
7
|
+
## Interface
|
|
8
|
+
|
|
9
|
+
- `startCheckout(input)` owns the `giftSubCustomization` flag, duration
|
|
10
|
+
catalogue, Portal plan gate, tier/cadence validation, authoritative price,
|
|
11
|
+
token, success parameters, metadata, customer, and one-time payment.
|
|
12
|
+
- `preparePaidContinuation(input)` validates an active gift and returns the
|
|
13
|
+
stable tier/cadence/trial decision consumed by the normal subscription
|
|
14
|
+
checkout path.
|
|
15
|
+
- `getRedeemable(input)` and `redeem(input)` return the public redemption DTO.
|
|
16
|
+
- `completePurchase(input)` and `handlePaymentRefund(input)` accept normalized
|
|
17
|
+
payment outcomes.
|
|
18
|
+
- `handlePaidSubscriptionActivation(memberId)` consumes gift time when a paid
|
|
19
|
+
subscription takes over.
|
|
20
|
+
- `getMemberPresentations(memberIds)`, `getPreview(token)`,
|
|
21
|
+
`browsePurchaseEvents(...)`, and `browseRedemptionEvents(...)` expose
|
|
22
|
+
stable read models.
|
|
23
|
+
- `processReminders()`, `processConsumed()`, and `processExpired()` own due
|
|
24
|
+
lifecycle work; scheduler and HTTP triggers remain adapters.
|
|
25
|
+
- `reassignRedeemer(...)` is the import capability.
|
|
26
|
+
|
|
27
|
+
The `Gift`, repository, Bookshelf query, Stripe checkout, email, scheduling,
|
|
28
|
+
and notification collaborators are internal adapters.
|
|
@@ -5,7 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.GiftBookshelfRepository = void 0;
|
|
7
7
|
const errors_1 = __importDefault(require("@tryghost/errors"));
|
|
8
|
-
const
|
|
8
|
+
const mongo_utils_1 = require("@tryghost/mongo-utils");
|
|
9
|
+
const gift_codec_1 = require("./gift-codec");
|
|
9
10
|
class GiftBookshelfRepository {
|
|
10
11
|
model;
|
|
11
12
|
constructor({ GiftModel }) {
|
|
@@ -60,6 +61,26 @@ class GiftBookshelfRepository {
|
|
|
60
61
|
}
|
|
61
62
|
return map;
|
|
62
63
|
}
|
|
64
|
+
browsePurchaseEvents(options = {}, filter) {
|
|
65
|
+
return this.browseEvents({
|
|
66
|
+
options,
|
|
67
|
+
filter,
|
|
68
|
+
type: 'gift_purchase_event',
|
|
69
|
+
relation: 'buyer',
|
|
70
|
+
memberIdColumn: 'buyer_member_id',
|
|
71
|
+
dateColumn: 'purchased_at'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
browseRedemptionEvents(options = {}, filter) {
|
|
75
|
+
return this.browseEvents({
|
|
76
|
+
options,
|
|
77
|
+
filter,
|
|
78
|
+
type: 'gift_redemption_event',
|
|
79
|
+
relation: 'redeemer',
|
|
80
|
+
memberIdColumn: 'redeemer_member_id',
|
|
81
|
+
dateColumn: 'redeemed_at'
|
|
82
|
+
});
|
|
83
|
+
}
|
|
63
84
|
async findPendingConsumption() {
|
|
64
85
|
const now = new Date();
|
|
65
86
|
const collection = await this.model.findAll({
|
|
@@ -111,53 +132,52 @@ class GiftBookshelfRepository {
|
|
|
111
132
|
return await this.model.transaction(callback);
|
|
112
133
|
}
|
|
113
134
|
toRow(gift) {
|
|
114
|
-
return
|
|
115
|
-
token: gift.token,
|
|
116
|
-
buyer_email: gift.buyerEmail,
|
|
117
|
-
buyer_member_id: gift.buyerMemberId,
|
|
118
|
-
redeemer_member_id: gift.redeemerMemberId,
|
|
119
|
-
tier_id: gift.tierId,
|
|
120
|
-
cadence: gift.cadence,
|
|
121
|
-
duration: gift.duration,
|
|
122
|
-
currency: gift.currency,
|
|
123
|
-
amount: gift.amount,
|
|
124
|
-
stripe_checkout_session_id: gift.stripeCheckoutSessionId,
|
|
125
|
-
stripe_payment_intent_id: gift.stripePaymentIntentId,
|
|
126
|
-
consumes_at: gift.consumesAt,
|
|
127
|
-
expires_at: gift.expiresAt,
|
|
128
|
-
status: gift.status,
|
|
129
|
-
purchased_at: gift.purchasedAt,
|
|
130
|
-
redeemed_at: gift.redeemedAt,
|
|
131
|
-
consumed_at: gift.consumedAt,
|
|
132
|
-
expired_at: gift.expiredAt,
|
|
133
|
-
refunded_at: gift.refundedAt,
|
|
134
|
-
consumes_soon_reminder_sent_at: gift.consumesSoonReminderSentAt
|
|
135
|
-
};
|
|
135
|
+
return (0, gift_codec_1.encodeGift)(gift);
|
|
136
136
|
}
|
|
137
137
|
toGift(model) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
redeemerMemberId: json.redeemer_member_id,
|
|
144
|
-
tierId: json.tier_id,
|
|
145
|
-
cadence: json.cadence,
|
|
146
|
-
duration: json.duration,
|
|
147
|
-
currency: json.currency,
|
|
148
|
-
amount: json.amount,
|
|
149
|
-
stripeCheckoutSessionId: json.stripe_checkout_session_id,
|
|
150
|
-
stripePaymentIntentId: json.stripe_payment_intent_id,
|
|
151
|
-
consumesAt: json.consumes_at,
|
|
152
|
-
expiresAt: json.expires_at,
|
|
153
|
-
status: json.status,
|
|
154
|
-
purchasedAt: json.purchased_at,
|
|
155
|
-
redeemedAt: json.redeemed_at,
|
|
156
|
-
consumedAt: json.consumed_at,
|
|
157
|
-
expiredAt: json.expired_at,
|
|
158
|
-
refundedAt: json.refunded_at,
|
|
159
|
-
consumesSoonReminderSentAt: json.consumes_soon_reminder_sent_at ?? null
|
|
138
|
+
return (0, gift_codec_1.decodeGiftRow)(model.toJSON());
|
|
139
|
+
}
|
|
140
|
+
async browseEvents({ options, filter, type, relation, memberIdColumn, dateColumn }) {
|
|
141
|
+
const replaceCustomFilter = (existingFilter) => (0, mongo_utils_1.replaceFilters)(existingFilter, {
|
|
142
|
+
custom: filter
|
|
160
143
|
});
|
|
144
|
+
const queryOptions = {
|
|
145
|
+
...options,
|
|
146
|
+
withRelated: [relation, 'tier'],
|
|
147
|
+
filter: `${memberIdColumn}:-null+custom:true`,
|
|
148
|
+
useBasicCount: true,
|
|
149
|
+
mongoTransformer: (0, mongo_utils_1.chainTransformers)(replaceCustomFilter, ...(0, mongo_utils_1.mapKeys)({
|
|
150
|
+
'data.created_at': dateColumn,
|
|
151
|
+
'data.member_id': memberIdColumn
|
|
152
|
+
}))
|
|
153
|
+
};
|
|
154
|
+
if (typeof queryOptions.order === 'string') {
|
|
155
|
+
queryOptions.order = queryOptions.order.replace(/created_at/g, dateColumn);
|
|
156
|
+
}
|
|
157
|
+
if (!this.model.findPage) {
|
|
158
|
+
throw new errors_1.default.InternalServerError({ message: 'Gift model does not support paginated event queries.' });
|
|
159
|
+
}
|
|
160
|
+
const { data: models, meta } = await this.model.findPage(queryOptions);
|
|
161
|
+
return {
|
|
162
|
+
data: models.map((model) => {
|
|
163
|
+
const json = model.toJSON(queryOptions);
|
|
164
|
+
return {
|
|
165
|
+
type,
|
|
166
|
+
data: {
|
|
167
|
+
id: json.id,
|
|
168
|
+
member: json[relation] || null,
|
|
169
|
+
member_id: json[memberIdColumn],
|
|
170
|
+
tier_name: json.tier?.name,
|
|
171
|
+
cadence: json.cadence,
|
|
172
|
+
duration: json.duration,
|
|
173
|
+
amount: json.amount,
|
|
174
|
+
currency: json.currency,
|
|
175
|
+
created_at: json[dateColumn]
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}),
|
|
179
|
+
meta
|
|
180
|
+
};
|
|
161
181
|
}
|
|
162
182
|
}
|
|
163
183
|
exports.GiftBookshelfRepository = GiftBookshelfRepository;
|
|
@@ -1,10 +1,100 @@
|
|
|
1
1
|
import errors from '@tryghost/errors';
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
2
|
+
import {chainTransformers, mapKeys, replaceFilters} from '@tryghost/mongo-utils';
|
|
3
|
+
import type {Knex} from 'knex';
|
|
4
|
+
import {Gift} from './gift';
|
|
5
|
+
import {decodeGiftRow, encodeGift} from './gift-codec';
|
|
6
|
+
import type {GiftCadence, GiftRow} from './gift-schema';
|
|
7
|
+
|
|
8
|
+
type ParsedNqlFilter = unknown;
|
|
9
|
+
|
|
10
|
+
export interface GiftEventBrowseOptions {
|
|
11
|
+
filter?: string;
|
|
12
|
+
limit?: number | 'all';
|
|
13
|
+
order?: string;
|
|
14
|
+
page?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Pagination {
|
|
18
|
+
page: number;
|
|
19
|
+
pages: number;
|
|
20
|
+
limit: number | 'all';
|
|
21
|
+
total: number;
|
|
22
|
+
prev: number | null;
|
|
23
|
+
next: number | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface GiftEventData {
|
|
27
|
+
id: string;
|
|
28
|
+
member: Record<string, unknown> | null;
|
|
29
|
+
member_id: string | null;
|
|
30
|
+
tier_name?: string;
|
|
31
|
+
cadence: GiftCadence;
|
|
32
|
+
duration: number;
|
|
33
|
+
amount: number;
|
|
34
|
+
currency: string;
|
|
35
|
+
created_at: Date | string | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface GiftEventPage {
|
|
39
|
+
data: Array<{
|
|
40
|
+
type: 'gift_purchase_event' | 'gift_redemption_event';
|
|
41
|
+
data: GiftEventData;
|
|
42
|
+
}>;
|
|
43
|
+
meta: {
|
|
44
|
+
pagination?: Pagination;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface RepositoryTransactionOptions {
|
|
49
|
+
transacting?: Knex.Transaction;
|
|
50
|
+
forUpdate?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface FindPendingReminderOptions {
|
|
54
|
+
now: Date;
|
|
55
|
+
reminderLeadMs: number;
|
|
56
|
+
reminderFloorMs: number;
|
|
57
|
+
transacting?: Knex.Transaction;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface GiftRepository {
|
|
61
|
+
existsByCheckoutSessionId(checkoutSessionId: string): Promise<boolean>;
|
|
62
|
+
getById(id: string, options?: RepositoryTransactionOptions): Promise<Gift | null>;
|
|
63
|
+
getByToken(token: string, options?: RepositoryTransactionOptions): Promise<Gift | null>;
|
|
64
|
+
getByPaymentIntentId(paymentIntentId: string): Promise<Gift | null>;
|
|
65
|
+
findPendingConsumption(): Promise<Gift[]>;
|
|
66
|
+
findPendingExpiration(): Promise<Gift[]>;
|
|
67
|
+
findPendingReminder(options: FindPendingReminderOptions): Promise<Gift[]>;
|
|
68
|
+
findUnsentReminders(): Promise<Gift[]>;
|
|
69
|
+
getActiveByMember(memberId: string, options?: RepositoryTransactionOptions): Promise<Gift | null>;
|
|
70
|
+
getActiveByMembers(memberIds: string[], options?: RepositoryTransactionOptions): Promise<Map<string, Gift>>;
|
|
71
|
+
browsePurchaseEvents(options?: GiftEventBrowseOptions, filter?: ParsedNqlFilter): Promise<GiftEventPage>;
|
|
72
|
+
browseRedemptionEvents(options?: GiftEventBrowseOptions, filter?: ParsedNqlFilter): Promise<GiftEventPage>;
|
|
73
|
+
create(gift: Gift, options?: RepositoryTransactionOptions): Promise<void>;
|
|
74
|
+
update(gift: Gift, options?: RepositoryTransactionOptions): Promise<void>;
|
|
75
|
+
transaction<T>(callback: (transacting: Knex.Transaction) => Promise<T>): Promise<T>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type BookshelfSaveOptions = RepositoryTransactionOptions & {
|
|
79
|
+
autoRefresh?: boolean;
|
|
80
|
+
method?: 'update';
|
|
81
|
+
patch?: boolean;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
type GiftEventQueryOptions = GiftEventBrowseOptions & {
|
|
85
|
+
withRelated: Array<'buyer' | 'redeemer' | 'tier'>;
|
|
86
|
+
filter: string;
|
|
87
|
+
useBasicCount: boolean;
|
|
88
|
+
mongoTransformer: (filter: ParsedNqlFilter) => ParsedNqlFilter;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
type BookshelfFindOptions = RepositoryTransactionOptions & {
|
|
92
|
+
filter?: string;
|
|
93
|
+
require?: boolean;
|
|
94
|
+
};
|
|
4
95
|
|
|
5
96
|
type BookshelfDocument<T> = {
|
|
6
|
-
save(data: Partial<T>, options?:
|
|
7
|
-
set(data: Partial<T>): void;
|
|
97
|
+
save(data: Partial<T>, options?: BookshelfSaveOptions): Promise<BookshelfDocument<T>>;
|
|
8
98
|
toJSON(): T;
|
|
9
99
|
};
|
|
10
100
|
|
|
@@ -12,35 +102,31 @@ type BookshelfCollection<T> = {
|
|
|
12
102
|
models: BookshelfDocument<T>[];
|
|
13
103
|
};
|
|
14
104
|
|
|
15
|
-
type
|
|
16
|
-
add(data: Partial<T>, unfilteredOptions?: unknown): Promise<T>;
|
|
17
|
-
transaction<R>(callback: (transacting: unknown) => Promise<R>): Promise<R>;
|
|
18
|
-
findOne(data: Record<string, unknown>, unfilteredOptions?: unknown): Promise<BookshelfDocument<T> | null>;
|
|
19
|
-
findAll(unfilteredOptions?: unknown): Promise<BookshelfCollection<T>>;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
type GiftRow = {
|
|
105
|
+
type GiftEventBookshelfRow = {
|
|
23
106
|
id: string;
|
|
24
|
-
token: string;
|
|
25
|
-
buyer_email: string;
|
|
26
107
|
buyer_member_id: string | null;
|
|
27
108
|
redeemer_member_id: string | null;
|
|
28
|
-
|
|
109
|
+
buyer?: Record<string, unknown> | null;
|
|
110
|
+
redeemer?: Record<string, unknown> | null;
|
|
111
|
+
tier?: {name?: string} | null;
|
|
29
112
|
cadence: GiftCadence;
|
|
30
113
|
duration: number;
|
|
31
|
-
currency: string;
|
|
32
114
|
amount: number;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
115
|
+
currency: string;
|
|
116
|
+
purchased_at: Date | string;
|
|
117
|
+
redeemed_at: Date | string | null;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
type GiftEventBookshelfDocument = {
|
|
121
|
+
toJSON(options?: GiftEventQueryOptions): GiftEventBookshelfRow;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
type BookshelfModel<T> = {
|
|
125
|
+
add(data: Partial<T>, options?: RepositoryTransactionOptions): Promise<BookshelfDocument<T>>;
|
|
126
|
+
transaction<R>(callback: (transacting: Knex.Transaction) => Promise<R>): Promise<R>;
|
|
127
|
+
findOne(data: Partial<T> & {id?: string}, options?: BookshelfFindOptions): Promise<BookshelfDocument<T> | null>;
|
|
128
|
+
findAll(options?: BookshelfFindOptions): Promise<BookshelfCollection<T>>;
|
|
129
|
+
findPage(options: GiftEventQueryOptions): Promise<{data: GiftEventBookshelfDocument[]; meta: GiftEventPage['meta']}>;
|
|
44
130
|
};
|
|
45
131
|
|
|
46
132
|
type GiftBookshelfModel = BookshelfModel<GiftRow>;
|
|
@@ -116,6 +202,28 @@ export class GiftBookshelfRepository implements GiftRepository {
|
|
|
116
202
|
return map;
|
|
117
203
|
}
|
|
118
204
|
|
|
205
|
+
browsePurchaseEvents(options: GiftEventBrowseOptions = {}, filter?: ParsedNqlFilter): Promise<GiftEventPage> {
|
|
206
|
+
return this.browseEvents({
|
|
207
|
+
options,
|
|
208
|
+
filter,
|
|
209
|
+
type: 'gift_purchase_event',
|
|
210
|
+
relation: 'buyer',
|
|
211
|
+
memberIdColumn: 'buyer_member_id',
|
|
212
|
+
dateColumn: 'purchased_at'
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
browseRedemptionEvents(options: GiftEventBrowseOptions = {}, filter?: ParsedNqlFilter): Promise<GiftEventPage> {
|
|
217
|
+
return this.browseEvents({
|
|
218
|
+
options,
|
|
219
|
+
filter,
|
|
220
|
+
type: 'gift_redemption_event',
|
|
221
|
+
relation: 'redeemer',
|
|
222
|
+
memberIdColumn: 'redeemer_member_id',
|
|
223
|
+
dateColumn: 'redeemed_at'
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
119
227
|
async findPendingConsumption(): Promise<Gift[]> {
|
|
120
228
|
const now = new Date();
|
|
121
229
|
|
|
@@ -179,59 +287,80 @@ export class GiftBookshelfRepository implements GiftRepository {
|
|
|
179
287
|
});
|
|
180
288
|
}
|
|
181
289
|
|
|
182
|
-
async transaction<T>(callback: (transacting:
|
|
290
|
+
async transaction<T>(callback: (transacting: Knex.Transaction) => Promise<T>): Promise<T> {
|
|
183
291
|
return await this.model.transaction(callback);
|
|
184
292
|
}
|
|
185
293
|
|
|
186
|
-
private toRow(gift: Gift):
|
|
187
|
-
return
|
|
188
|
-
token: gift.token,
|
|
189
|
-
buyer_email: gift.buyerEmail,
|
|
190
|
-
buyer_member_id: gift.buyerMemberId,
|
|
191
|
-
redeemer_member_id: gift.redeemerMemberId,
|
|
192
|
-
tier_id: gift.tierId,
|
|
193
|
-
cadence: gift.cadence,
|
|
194
|
-
duration: gift.duration,
|
|
195
|
-
currency: gift.currency,
|
|
196
|
-
amount: gift.amount,
|
|
197
|
-
stripe_checkout_session_id: gift.stripeCheckoutSessionId,
|
|
198
|
-
stripe_payment_intent_id: gift.stripePaymentIntentId,
|
|
199
|
-
consumes_at: gift.consumesAt,
|
|
200
|
-
expires_at: gift.expiresAt,
|
|
201
|
-
status: gift.status,
|
|
202
|
-
purchased_at: gift.purchasedAt,
|
|
203
|
-
redeemed_at: gift.redeemedAt,
|
|
204
|
-
consumed_at: gift.consumedAt,
|
|
205
|
-
expired_at: gift.expiredAt,
|
|
206
|
-
refunded_at: gift.refundedAt,
|
|
207
|
-
consumes_soon_reminder_sent_at: gift.consumesSoonReminderSentAt
|
|
208
|
-
};
|
|
294
|
+
private toRow(gift: Gift): GiftRow {
|
|
295
|
+
return encodeGift(gift);
|
|
209
296
|
}
|
|
210
297
|
|
|
211
298
|
private toGift(model: BookshelfDocument<GiftRow>): Gift {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
expiredAt: json.expired_at,
|
|
233
|
-
refundedAt: json.refunded_at,
|
|
234
|
-
consumesSoonReminderSentAt: json.consumes_soon_reminder_sent_at ?? null
|
|
299
|
+
return decodeGiftRow(model.toJSON());
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private async browseEvents({
|
|
303
|
+
options,
|
|
304
|
+
filter,
|
|
305
|
+
type,
|
|
306
|
+
relation,
|
|
307
|
+
memberIdColumn,
|
|
308
|
+
dateColumn
|
|
309
|
+
}: {
|
|
310
|
+
options: GiftEventBrowseOptions;
|
|
311
|
+
filter?: ParsedNqlFilter;
|
|
312
|
+
type: 'gift_purchase_event' | 'gift_redemption_event';
|
|
313
|
+
relation: 'buyer' | 'redeemer';
|
|
314
|
+
memberIdColumn: 'buyer_member_id' | 'redeemer_member_id';
|
|
315
|
+
dateColumn: 'purchased_at' | 'redeemed_at';
|
|
316
|
+
}): Promise<GiftEventPage> {
|
|
317
|
+
const replaceCustomFilter = (existingFilter: ParsedNqlFilter): ParsedNqlFilter => replaceFilters(existingFilter, {
|
|
318
|
+
custom: filter
|
|
235
319
|
});
|
|
320
|
+
const queryOptions: GiftEventQueryOptions = {
|
|
321
|
+
...options,
|
|
322
|
+
withRelated: [relation, 'tier'],
|
|
323
|
+
filter: `${memberIdColumn}:-null+custom:true`,
|
|
324
|
+
useBasicCount: true,
|
|
325
|
+
mongoTransformer: chainTransformers(
|
|
326
|
+
replaceCustomFilter,
|
|
327
|
+
...mapKeys({
|
|
328
|
+
'data.created_at': dateColumn,
|
|
329
|
+
'data.member_id': memberIdColumn
|
|
330
|
+
})
|
|
331
|
+
)
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
if (typeof queryOptions.order === 'string') {
|
|
335
|
+
queryOptions.order = queryOptions.order.replace(/created_at/g, dateColumn);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (!this.model.findPage) {
|
|
339
|
+
throw new errors.InternalServerError({message: 'Gift model does not support paginated event queries.'});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const {data: models, meta} = await this.model.findPage(queryOptions);
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
data: models.map((model) => {
|
|
346
|
+
const json = model.toJSON(queryOptions);
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
type,
|
|
350
|
+
data: {
|
|
351
|
+
id: json.id,
|
|
352
|
+
member: json[relation] || null,
|
|
353
|
+
member_id: json[memberIdColumn],
|
|
354
|
+
tier_name: json.tier?.name,
|
|
355
|
+
cadence: json.cadence,
|
|
356
|
+
duration: json.duration,
|
|
357
|
+
amount: json.amount,
|
|
358
|
+
currency: json.currency,
|
|
359
|
+
created_at: json[dateColumn]
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}),
|
|
363
|
+
meta
|
|
364
|
+
};
|
|
236
365
|
}
|
|
237
366
|
}
|