ghost 6.60.0 → 6.61.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.3.tgz +0 -0
- package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
- package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
- package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
- package/core/boot.js +13 -4
- package/core/built/admin/assets/{Combination-gnJO3vIw.js → Combination-5fYEzgbs.js} +1 -1
- package/core/built/admin/assets/{PolarAngleAxis-C4qtHy1B.js → PolarAngleAxis-pkMyqz8g.js} +1 -1
- package/core/built/admin/assets/{RadialBarChart-Bh09Stsj.js → RadialBarChart-JAKoS4KT.js} +1 -1
- package/core/built/admin/assets/{about-BgpmhCuM.js → about-Bve7IJS2.js} +1 -1
- package/core/built/admin/assets/{account-migration-8qTEI1i1.js → account-migration-DRhAehfw.js} +1 -1
- package/core/built/admin/assets/{action-list-lGzZLHc8.js → action-list-C4v0-du8.js} +1 -1
- package/core/built/admin/assets/activitypub/{account-migration-DMHuPnJn.js → account-migration-C-aej4x_.js} +7 -7
- package/core/built/admin/assets/activitypub/activitypub.js +3 -4
- package/core/built/admin/assets/activitypub/{avatar-DhTo5D1B.js → avatar-DLPL3Abs.js} +59 -68
- package/core/built/admin/assets/activitypub/{avatar-flipboard-DnVgbEfa.js → avatar-flipboard-C9iDY-QV.js} +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-BT4zAlW7.js → bluesky-sharing-BXkA5mqV.js} +8 -8
- package/core/built/admin/assets/activitypub/{content-formatters-BeDZ-DIa.js → content-formatters-CHcyMFk4.js} +17 -17
- package/core/built/admin/assets/activitypub/{copy-8sqxUuNd.js → copy-DIAOQoCZ.js} +2 -2
- package/core/built/admin/assets/activitypub/{domain-xQDDu1CS.js → domain-B3ihkPde.js} +8 -8
- package/core/built/admin/assets/activitypub/{edit-profile-BXdF_r2G.js → edit-profile-DsZM3rTX.js} +5 -5
- package/core/built/admin/assets/activitypub/{explore-CMt7gKlL.js → explore-BodNrZgR.js} +8 -8
- package/core/built/admin/assets/activitypub/{feed-Bwqdddp_.js → feed-PwH1iJ84.js} +9 -9
- package/core/built/admin/assets/activitypub/{field-4co_8FVg.js → field-D06-kmOJ.js} +3 -3
- package/core/built/admin/assets/activitypub/{hash-DwakMs4X.js → hash-Bm3WxYN4.js} +2 -2
- package/core/built/admin/assets/activitypub/{inbox-DQ5CwLma.js → inbox-BluD2ucT.js} +16 -16
- package/core/built/admin/assets/activitypub/{inbox-ckD4wo_r.js → inbox-d8oJRTf4.js} +2 -2
- package/core/built/admin/assets/activitypub/{label-B72sfvEU.js → label-FHSh6ZAw.js} +3 -3
- package/core/built/admin/assets/activitypub/layout-Cq4NG0Xr.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-KCCO7L2J.js → moderation-D1Yapsod.js} +9 -9
- package/core/built/admin/assets/activitypub/{note-BX_Bz5A0.js → note-C5zjqq5C.js} +8 -8
- package/core/built/admin/assets/activitypub/{notifications-BQOYGvRv.js → notifications-B9p8eCHD.js} +9 -9
- package/core/built/admin/assets/activitypub/{preferences-6h43G9_q.js → preferences-BCqUdC3v.js} +9 -9
- package/core/built/admin/assets/activitypub/{profile-BMN9VVZ2.js → profile-BRCWoFem.js} +178 -178
- package/core/built/admin/assets/activitypub/{reply-ZNo04xsO.js → reply-DYK5vVqb.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-3B9mUQ7i.js → routes-BSXT992i.js} +81 -84
- package/core/built/admin/assets/activitypub/{separator-D9taVCCa.js → separator-BbQqTm-p.js} +3 -3
- package/core/built/admin/assets/activitypub/{settings-71gCm3SO.js → settings-DQDkr06X.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-1-BsGGnBuT.js → step-1-B-YfsVeO.js} +5 -5
- package/core/built/admin/assets/activitypub/{step-2-teosIS0k.js → step-2-DtPQzlTH.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-3-BjD5TokC.js → step-3-D6BFMXL_.js} +10 -10
- package/core/built/admin/assets/activitypub/{tabs-Cvwl1wXU.js → tabs-GpNecvfB.js} +6 -6
- package/core/built/admin/assets/activitypub/{topic-filter-C3LZJc2X.js → topic-filter-BPDeQQys.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-Dp9f0gov.js → use-activity-pub-queries-BoVOxXkV.js} +2 -2
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-C4RI0sa9.js → use-navigate-with-base-path-Bmk5h4lW.js} +220 -220
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-C2oNDMUH.js → use-reply-chain-data-wVBX7swM.js} +5 -5
- package/core/built/admin/assets/activitypub/{x-Dxm6pV9X.js → x-DbQZOLiI.js} +2 -2
- package/core/built/admin/assets/{add-integration-modal--YpTq3c0.js → add-integration-modal-BC0jExDZ.js} +1 -1
- package/core/built/admin/assets/{add-newsletter-modal-C8Ix2hol.js → add-newsletter-modal-DchTkA7l.js} +1 -1
- package/core/built/admin/assets/{add-recommendation-modal-CScuNFz4.js → add-recommendation-modal-DMvaJZKp.js} +1 -1
- package/core/built/admin/assets/alert-dialog-QhXzdHfc.js +1 -0
- package/core/built/admin/assets/{analytics-Cnji45H5.js → analytics-No1DDY3A.js} +1 -1
- package/core/built/admin/assets/{announcement-bar-modal-BTHiy1ZO.js → announcement-bar-modal-DM3cYOpo.js} +1 -1
- package/core/built/admin/assets/{api-keys-Boy5pLbD.js → api-keys-BLm2NDBh.js} +1 -1
- package/core/built/admin/assets/audience-9mwU5TW6.js +1 -0
- package/core/built/admin/assets/{automations-BWpRCZ_f.js → automations-DpUNUdcZ.js} +1 -1
- package/core/built/admin/assets/{bluesky-sharing-DHOpQxff.js → bluesky-sharing-Cjrv_f62.js} +1 -1
- package/core/built/admin/assets/{box-By_EgGtm.js → box-CdfQAP_F.js} +1 -1
- package/core/built/admin/assets/{brand-icon-09YqFZjV.js → brand-icon-CrIGOA3Z.js} +1 -1
- package/core/built/admin/assets/{breadcrumb-CcFr_ltt.js → breadcrumb-DLiqCyFc.js} +1 -1
- package/core/built/admin/assets/{button-BshWPHvn.js → button-B2jcu6bk.js} +1 -1
- package/core/built/admin/assets/{card-CiiE7QfM.js → card--VNbfgo3.js} +1 -1
- package/core/built/admin/assets/{chart-BnXyfH11.js → chart-BrhA41Zi.js} +1 -1
- package/core/built/admin/assets/chart-helpers-Fo3bUL3K.js +1 -0
- package/core/built/admin/assets/{checkbox-Dwwr_3Py.js → checkbox-BfKktMph.js} +1 -1
- package/core/built/admin/assets/{chunk.524.91ecb33e6afc3bd8949b.js → chunk.524.60ca4692d91c6022042f.js} +4 -4
- package/core/built/admin/assets/{chunk.582.512549909741883f960c.js → chunk.582.525c7617c2d9e94c940a.js} +6 -6
- package/core/built/admin/assets/{chunk.16.f76a6314082d813d67e0.js → chunk.896.435fe0637944d4a69810.js} +3 -3
- package/core/built/admin/assets/{code-editor-view-BwIdPy_k.js → code-editor-view-CYVu4EW6.js} +1 -1
- package/core/built/admin/assets/{code-editor-view-CtkF82Fv.js → code-editor-view-DCQJxsfU.js} +1 -1
- package/core/built/admin/assets/{color-picker-Bmo1r9Fc.js → color-picker-BTY_NdEm.js} +1 -1
- package/core/built/admin/assets/{color-picker-field-DywowPhF.js → color-picker-field-CPlkzOH0.js} +1 -1
- package/core/built/admin/assets/{combobox-C4QCh6Yw.js → combobox-DrMtv_4P.js} +1 -1
- package/core/built/admin/assets/command-ZdgYJpoI.js +1 -0
- package/core/built/admin/assets/comments-kidj60-h.js +1 -0
- package/core/built/admin/assets/{confirmation-context-CLFHhyyH.js → confirmation-context-BhbmQQEl.js} +1 -1
- package/core/built/admin/assets/{container-LiZf3XdY.js → container-BuQG1wuP.js} +1 -1
- package/core/built/admin/assets/{content-api-modal-BtpNI92-.js → content-api-modal-CyQEC3fr.js} +1 -1
- package/core/built/admin/assets/{copy-field-CglgRZyG.js → copy-field-B3M1s78L.js} +1 -1
- package/core/built/admin/assets/{custom-field-type-option-D0PXoSnP.js → custom-field-type-option-CsGIZk1J.js} +1 -1
- package/core/built/admin/assets/{custom-integration-modal-DCIHKN33.js → custom-integration-modal-BY37O_9X.js} +1 -1
- package/core/built/admin/assets/{data-list-CupF7bjM.js → data-list-CA2jYGPq.js} +1 -1
- package/core/built/admin/assets/{date-range-select-JPwM0yUj.js → date-range-select-DD2RKkgB.js} +1 -1
- package/core/built/admin/assets/design-and-theme-modal-DUSKM4uC.js +22 -0
- package/core/built/admin/assets/{detail-page-D8lx2SdP.js → detail-page-Dnv-CdR1.js} +1 -1
- package/core/built/admin/assets/dialog-B44iRwlc.js +1 -0
- package/core/built/admin/assets/{dirty-confirm-dialog-CmARpZQS.js → dirty-confirm-dialog-BxgQgQ6H.js} +1 -1
- package/core/built/admin/assets/{disabled-sources-indicator-BTJ2ClQu.js → disabled-sources-indicator-Cvy47bE2.js} +1 -1
- package/core/built/admin/assets/{dist-DzcfoDJ3.js → dist-8YJUlf3B.js} +1 -1
- package/core/built/admin/assets/{dist-Cb5RSHSg.js → dist-B3keLvjj.js} +1 -1
- package/core/built/admin/assets/{dist-QLZuGq7o2.js → dist-Cy8tfrp_.js} +1 -1
- package/core/built/admin/assets/{dist-BT_Z-eCn.js → dist-Dgt2cr6a.js} +1 -1
- package/core/built/admin/assets/{domain-D0SAtc-T.js → domain-Ca6KhoQt.js} +1 -1
- package/core/built/admin/assets/{dropzone-CaPOeDRZ.js → dropzone-Bb-5zQTk.js} +1 -1
- package/core/built/admin/assets/edit-profile-BdupLlus.js +1 -0
- package/core/built/admin/assets/{editor-COXn4Atu.js → editor-BP883Lpn.js} +3 -3
- package/core/built/admin/assets/{embed-signup-form-modal-BFTPf04i.js → embed-signup-form-modal-DeBMLxlL.js} +1 -1
- package/core/built/admin/assets/{empty-indicator-WB1WgT9h.js → empty-indicator-D9QdpuNX.js} +1 -1
- package/core/built/admin/assets/{explore-BsNYrubV.js → explore-FB-CimXw.js} +1 -1
- package/core/built/admin/assets/{feed-8RR1O1bK.js → feed-C1GxsmI2.js} +1 -1
- package/core/built/admin/assets/{field-LmNk7wZh.js → field-Cj8lmDOo.js} +1 -1
- package/core/built/admin/assets/{filter-sources-4C0kF1NU.js → filter-sources-D5n5bFA2.js} +1 -1
- package/core/built/admin/assets/{filters-CV5jCb9n.js → filters-DJEzkMUK.js} +1 -1
- package/core/built/admin/assets/{filters-Dmr0PoqU.js → filters-MZXvdH5D.js} +1 -1
- package/core/built/admin/assets/{first-promoter-modal-OCzSaL3B.js → first-promoter-modal-CGTGLCr5.js} +1 -1
- package/core/built/admin/assets/{ghost-403cb39badad3df411fc0ba27d220047.js → ghost-3894eedcc6968f658578c0abfe942aab.js} +2 -2
- package/core/built/admin/assets/{gift-link-modal-0mzjn5oF.js → gift-link-modal-B6v0tnRN.js} +1 -1
- package/core/built/admin/assets/{grid-CUciBfjf.js → grid-Dj29PY05.js} +1 -1
- package/core/built/admin/assets/growth-BGAJD1rs.js +3 -0
- package/core/built/admin/assets/growth-D6mhcx3q.js +1 -0
- package/core/built/admin/assets/{heading-CRZZ2FUe.js → heading-Dh5SFVjL.js} +1 -1
- package/core/built/admin/assets/history-modal-iKwUY3XR.js +1 -0
- package/core/built/admin/assets/html-field-C8qVGGC1.js +1 -0
- package/core/built/admin/assets/{images-C0XvUYMb.js → images-h8VZEQ9k.js} +1 -1
- package/core/built/admin/assets/{inbox-DZXDUt4s.js → inbox-BYd1M06Q.js} +13 -13
- package/core/built/admin/assets/index-DjQe-e5s.js +4 -0
- package/core/built/admin/assets/{index.es-BMUCj9TR.js → index.es-VihPwfeH.js} +1 -1
- package/core/built/admin/assets/{inline-Cw-gigDW.js → inline-BWSs_VzR.js} +1 -1
- package/core/built/admin/assets/{input-UHrKuvBT.js → input--W-rCTrX.js} +1 -1
- package/core/built/admin/assets/{input-group-BPAxETpQ.js → input-group-D8sCXRF5.js} +1 -1
- package/core/built/admin/assets/{input-surface-BdOe4KzO.js → input-surface-BsrIZeSF.js} +1 -1
- package/core/built/admin/assets/{integration-header-B4DyXV06.js → integration-header-Bm6IDb1A.js} +1 -1
- package/core/built/admin/assets/{invite-user-modal-BrAkxEO3.js → invite-user-modal-MdImLCaJ.js} +1 -1
- package/core/built/admin/assets/{koenig-lexical-60O_8aiO.js → koenig-lexical-_-IsVI7E.js} +1 -1
- package/core/built/admin/assets/koenig-loader-DYZpm6El.js +2 -0
- package/core/built/admin/assets/{kpi-card-fUHZlzBX.js → kpi-card-DW_2y3ug.js} +1 -1
- package/core/built/admin/assets/kpi-card-DZQk_0W8.js +1 -0
- package/core/built/admin/assets/kpi-helpers-PueTKuA6.js +1 -0
- package/core/built/admin/assets/kpi-tabs-CojDs-Qz.js +1 -0
- package/core/built/admin/assets/{label-VIG969IC.js → label-DjbT91GM.js} +1 -1
- package/core/built/admin/assets/{label-picker-BBWykUeA.js → label-picker-cB51xl1r.js} +1 -1
- package/core/built/admin/assets/layout-c_B_1hax.js +1 -0
- package/core/built/admin/assets/{link-helpers-Dtq9fxQg.js → link-helpers-MVDdnFCY.js} +1 -1
- package/core/built/admin/assets/{list-page-CdsnQR9N.js → list-page-BucXJ0hi.js} +1 -1
- package/core/built/admin/assets/{loading-indicator-SFTqyYVE.js → loading-indicator-BpFWTVgh.js} +1 -1
- package/core/built/admin/assets/{member-custom-fields-gOv6Hoh3.js → member-custom-fields-qs0dIkxM.js} +1 -1
- package/core/built/admin/assets/member-detail-B6uec2a6.js +1 -0
- package/core/built/admin/assets/members-BQF3CqhI.js +2 -0
- package/core/built/admin/assets/{modal-page-BMTzFHVO.js → modal-page-xCivTMvI.js} +1 -1
- package/core/built/admin/assets/{moderation-DzzPLDyl.js → moderation-DY4wF1Q3.js} +1 -1
- package/core/built/admin/assets/{multi-select-combobox-CGohnsxJ.js → multi-select-combobox-B6LiRzDO.js} +1 -1
- package/core/built/admin/assets/navigation-modal-DX-gNF3X.js +1 -0
- package/core/built/admin/assets/newsletter-CyQA7m3m.js +1 -0
- package/core/built/admin/assets/{newsletter-detail-modal-DQU3r4g2.js → newsletter-detail-modal-BDrptuxn.js} +1 -1
- package/core/built/admin/assets/{newsletter-emails-D5ql1rud.js → newsletter-emails-CFeLlt4z.js} +1 -1
- package/core/built/admin/assets/newsletters-DXuNmC42.js +1 -0
- package/core/built/admin/assets/{note-i8k6pjaw.js → note-Cgo2LCJ6.js} +1 -1
- package/core/built/admin/assets/notifications-BC50AMku.js +1 -0
- package/core/built/admin/assets/{offers-container-modal-BWfjSdyg.js → offers-container-modal-DWycIMzT.js} +1 -1
- package/core/built/admin/assets/{onboarding-route-Cu_ROWPn.js → onboarding-route-Dmc4IPm3.js} +1 -1
- package/core/built/admin/assets/overview-CVbFtn-k.js +1 -0
- package/core/built/admin/assets/overview-YKj7SZaK.js +1 -0
- package/core/built/admin/assets/{page-header-Cfds8pCg.js → page-header-BR_nbIPp.js} +1 -1
- package/core/built/admin/assets/{pintura-modal-TDTrJ89x.js → pintura-modal-BR9hEvS8.js} +1 -1
- package/core/built/admin/assets/popover-CCy0h5rq.js +1 -0
- package/core/built/admin/assets/{portal-frame-DjBF-uy2.js → portal-frame-dc4XKr0e.js} +1 -1
- package/core/built/admin/assets/portal-modal-BvvdF_B9.js +1 -0
- package/core/built/admin/assets/{post-analytics-Buz1COoY.js → post-analytics-DX470WRG.js} +1 -1
- package/core/built/admin/assets/{post-analytics-header-B-P0eFnT.js → post-analytics-header-CXpJmdDv.js} +1 -1
- package/core/built/admin/assets/{post-analytics-provider-Cu3jNeFh.js → post-analytics-provider-CLfKGWZy.js} +1 -1
- package/core/built/admin/assets/{post-share-modal-P1_M6o-H.js → post-share-modal-Cl0NXRJr.js} +1 -1
- package/core/built/admin/assets/{preferences-Cq1aOiLy.js → preferences-DO0UUWFp.js} +2 -2
- package/core/built/admin/assets/{preview-chrome-BOVO6_PE.js → preview-chrome-BljUBlOk.js} +1 -1
- package/core/built/admin/assets/{preview-modal-MlTjP8UU.js → preview-modal-C-BL-F9k.js} +1 -1
- package/core/built/admin/assets/profile-CxT-0l4d.js +1 -0
- package/core/built/admin/assets/radio-group-Bgz60i81.js +1 -0
- package/core/built/admin/assets/{router-provider-CJC58zTy.js → router-provider-B0gZyiGJ.js} +1 -1
- package/core/built/admin/assets/{schemas-CRsC53ls.js → schemas-4UPic-oD.js} +2 -2
- package/core/built/admin/assets/select-DuDUFdPq.js +1 -0
- package/core/built/admin/assets/{settings-B5hJKZ5C.js → settings-BjCii7BM.js} +1 -1
- package/core/built/admin/assets/settings-b8kNzZSQ.js +4 -0
- package/core/built/admin/assets/{settings-breadcrumbs-sLDNedBW.js → settings-breadcrumbs-CyP_9zTo.js} +1 -1
- package/core/built/admin/assets/{shade-app-F7WxOyfk-nufqw1hd.js → shade-app-CcS3f8MZ-vwURazk8.js} +2 -2
- package/core/built/admin/assets/{share-modal-CLBfj377.js → share-modal-BV70mr9k.js} +1 -1
- package/core/built/admin/assets/{skeleton-D7hwjdry.js → skeleton-Ce9GgUpf.js} +1 -1
- package/core/built/admin/assets/{slack-modal-Bt9I_tEo.js → slack-modal-Be2_KK-z.js} +1 -1
- package/core/built/admin/assets/sort-button-Cc-Z96sA.js +1 -0
- package/core/built/admin/assets/{source-icon-BPsD5ees.js → source-icon-v6PUnmyM.js} +1 -1
- package/core/built/admin/assets/{stack-CIfOAAVf.js → stack-B2eszIiq.js} +1 -1
- package/core/built/admin/assets/{stats-B_YkF7bp.js → stats-C4reGh9O.js} +1 -1
- package/core/built/admin/assets/{stats-view-BOCp9RG8.js → stats-view-DP9pQ62k.js} +1 -1
- package/core/built/admin/assets/{step-1-CMta6YFO.js → step-1-DSRp2vBj.js} +1 -1
- package/core/built/admin/assets/{step-2-BG04nh5q.js → step-2-COqv2g0u.js} +1 -1
- package/core/built/admin/assets/{step-3-ZnMaVIPj.js → step-3-6W1NMVQc.js} +2 -2
- package/core/built/admin/assets/{stripe-button-DDoUKN5a.js → stripe-button-D2K42Uty.js} +1 -1
- package/core/built/admin/assets/{stripe-connect-modal-BeSukI8q.js → stripe-connect-modal-Z-UT_BGc.js} +1 -1
- package/core/built/admin/assets/{switch-C9djUIMO.js → switch-CI4gLWqb.js} +1 -1
- package/core/built/admin/assets/{table-CrqQtkR2.js → table-B2pIKjVh.js} +1 -1
- package/core/built/admin/assets/{tabs-CGisSbWq.js → tabs-SaW_UT-Q.js} +1 -1
- package/core/built/admin/assets/tag-detail-Dc0nTOtU.js +2 -0
- package/core/built/admin/assets/tags-BLaXBwnb.js +1 -0
- package/core/built/admin/assets/testimonials-modal-sFwRnNLh.js +1 -0
- package/core/built/admin/assets/{text-DU9Hv33_.js → text-BQDSDsKs.js} +1 -1
- package/core/built/admin/assets/{textarea-d9qEkMOP.js → textarea-DJ1Q5V39.js} +1 -1
- package/core/built/admin/assets/{tier-detail-modal-CxRwgTPR.js → tier-detail-modal-BCFpWwUS.js} +1 -1
- package/core/built/admin/assets/{toggle-group-CtKZURJd.js → toggle-group-EM9WpESu.js} +1 -1
- package/core/built/admin/assets/{topic-filter-D8JT8Tq1.js → topic-filter-DY4gNHn2.js} +1 -1
- package/core/built/admin/assets/{transistor-modal-6PUf0idx.js → transistor-modal-CpyPG-MH.js} +1 -1
- package/core/built/admin/assets/trend-badge-ByMkuAuH.js +1 -0
- package/core/built/admin/assets/{unsplash-modal-BPuDBPja.js → unsplash-modal-Cv2Q6GtY.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data--opuzwcz.js → use-analytics-data-CHvjMYuT.js} +1 -1
- package/core/built/admin/assets/use-check-theme-limit-error-Qv4SVXqw.js +2 -0
- package/core/built/admin/assets/use-filter-params-CAvfDvf1.js +1 -0
- package/core/built/admin/assets/use-growth-stats-D6mZXGhK.js +1 -0
- package/core/built/admin/assets/{use-limiter-TDSNiHPB.js → use-limiter-cwJvsNBo.js} +1 -1
- package/core/built/admin/assets/{use-navigate-with-base-path-CK989MlC.js → use-navigate-with-base-path-BHPA228f.js} +1 -1
- package/core/built/admin/assets/{use-pintura-config-CnCGrDFk.js → use-pintura-config-CzTfnufz.js} +1 -1
- package/core/built/admin/assets/{use-pintura-editor-ntphvtUd.js → use-pintura-editor-BDBXWUYq.js} +1 -1
- package/core/built/admin/assets/{use-post-referrers-CbXLFIex.js → use-post-referrers-DbY-mzci.js} +1 -1
- package/core/built/admin/assets/{use-reply-chain-data-JYFKSO83.js → use-reply-chain-data-BeQwz8oF.js} +1 -1
- package/core/built/admin/assets/{use-router-history-entry-BwfQS2mq.js → use-router-history-entry-Bg6BhBQQ.js} +1 -1
- package/core/built/admin/assets/{use-setting-group-DQxV42-O.js → use-setting-group-VM7FQwMY.js} +1 -1
- package/core/built/admin/assets/{use-settings-navigation-BBzro2-V.js → use-settings-navigation-BbrSUVcf.js} +1 -1
- package/core/built/admin/assets/{use-simple-pagination-B2TdNX67.js → use-simple-pagination-Dum6Irbs.js} +1 -1
- package/core/built/admin/assets/{use-staff-users-QrR9voeC.js → use-staff-users-cZg4ugOF.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-query-D2Aeoty5.js → use-tinybird-query-B1IMyAcv.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-DBuwMmln.js → use-tinybird-token-Bow0Zwn8.js} +1 -1
- package/core/built/admin/assets/{use-unsaved-changes-guard-DpYJcj1d.js → use-unsaved-changes-guard-BAy0RANR.js} +1 -1
- package/core/built/admin/assets/{use-url-input-WnIqckzS.js → use-url-input-Df5QzNa7.js} +1 -1
- package/core/built/admin/assets/user-detail-modal-yipSoQfv.js +1 -0
- package/core/built/admin/assets/{virtual-list-D3MfPNOh.js → virtual-list-DEx8WgiO.js} +1 -1
- package/core/built/admin/assets/web-CKcXAu86.js +1 -0
- package/core/built/admin/assets/web-DR4TqM3E.js +2 -0
- package/core/built/admin/assets/{zapier-modal-BO6PS_Vd.js → zapier-modal-Cw3BTBUu.js} +1 -1
- package/core/built/admin/index.html +24 -25
- package/core/frontend/services/rendering/renderer.js +15 -0
- package/core/server/adapters/storage/LocalStorageBase.js +8 -5
- package/core/server/api/endpoints/db.js +19 -5
- package/core/server/api/endpoints/index.js +4 -0
- package/core/server/api/endpoints/member-custom-fields.js +4 -14
- package/core/server/api/endpoints/posts.js +1 -0
- package/core/server/api/endpoints/tiers-checkout-config.js +59 -0
- package/core/server/api/endpoints/utils/serializers/output/config.js +1 -0
- package/core/server/api/endpoints/utils/serializers/output/index.js +4 -0
- package/core/server/api/endpoints/utils/serializers/output/tiers-checkout-config.js +12 -0
- package/core/server/data/exporter/table-lists.js +3 -0
- package/core/server/data/importer/content-files.js +57 -0
- package/core/server/data/importer/handlers/image.js +2 -2
- package/core/server/data/importer/import-archive.js +131 -0
- package/core/server/data/importer/import-manager.js +18 -180
- package/core/server/data/importer/importers/content-file-importer.js +66 -4
- package/core/server/data/migrations/versions/6.61/2026-08-19-14-30-20-add-written-by-to-members-custom-field-values.js +42 -0
- package/core/server/data/migrations/versions/6.61/2026-08-19-14-38-53-add-members-custom-field-bindings-table.js +26 -0
- package/core/server/data/migrations/versions/6.61/2026-08-19-14-48-06-add-tier-checkout-field-tables.js +35 -0
- package/core/server/data/schema/schema.js +90 -0
- package/core/server/data/seeders/importers/automation-action-revisions-importer.js +3 -3
- package/core/server/data/seeders/importers/automation-actions-importer.js +3 -3
- package/core/server/data/seeders/importers/automation-run-steps-importer.js +3 -3
- package/core/server/data/seeders/importers/automation-runs-importer.js +5 -5
- package/core/server/data/seeders/importers/automations-importer.js +3 -3
- package/core/server/data/seeders/importers/comment-reports-importer.js +1 -1
- package/core/server/data/seeders/importers/comments-importer.js +1 -1
- package/core/server/data/seeders/importers/email-batches-importer.js +1 -1
- package/core/server/data/seeders/importers/email-recipients-importer.js +1 -1
- package/core/server/data/seeders/importers/emails-importer.js +1 -1
- package/core/server/data/seeders/importers/labels-importer.js +1 -1
- package/core/server/data/seeders/importers/members-click-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-created-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-feedback-importer.js +1 -1
- package/core/server/data/seeders/importers/members-importer.js +1 -1
- package/core/server/data/seeders/importers/members-login-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-products-importer.js +1 -1
- package/core/server/data/seeders/importers/members-status-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-stripe-customers-importer.js +1 -1
- package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +1 -1
- package/core/server/data/seeders/importers/members-subscribe-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +1 -1
- package/core/server/data/seeders/importers/offer-redemptions-importer.js +1 -1
- package/core/server/data/seeders/importers/offers-importer.js +1 -1
- package/core/server/data/seeders/importers/posts-importer.js +1 -1
- package/core/server/data/seeders/importers/table-importer.js +2 -2
- package/core/server/data/seeders/importers/tags-importer.js +1 -1
- package/core/server/data/seeders/importers/users-importer.js +1 -1
- package/core/server/data/seeders/importers/web-mentions-importer.js +1 -1
- package/core/server/data/seeders/utils/random.js +3 -3
- package/core/server/ghost-server.js +3 -2
- package/core/server/lib/db-types/boolean.js +18 -0
- package/core/server/lib/promise-pool.js +31 -0
- package/core/server/services/automations/database-automations-repository.js +26 -26
- package/core/server/services/automations/poll.js +1 -0
- package/core/server/services/content-import/import/assets.js +74 -0
- package/core/server/services/content-import/import/importer.js +57 -14
- package/core/server/services/content-import/import/post-data.js +1 -0
- package/core/server/services/content-import/import/post-repository.js +78 -0
- package/core/server/services/content-import/import/relations.js +149 -0
- package/core/server/services/content-import/import/row.js +11 -0
- package/core/server/services/content-import/import/schema.js +29 -0
- package/core/server/services/content-import/import/source.js +125 -0
- package/core/server/services/content-import/index.js +6 -28
- package/core/server/services/email-analytics/email-analytics-service.js +8 -1
- package/core/server/services/email-analytics/lib/queries.js +7 -1
- package/core/server/services/gift-links/schema.js +3 -3
- package/core/server/services/gifts/CONTEXT.md +1 -1
- package/core/server/services/gifts/constants.js +1 -1
- package/core/server/services/gifts/gift-bookshelf-repository.js +2 -2
- package/core/server/services/gifts/gift-delivery-bookshelf-repository.js +18 -9
- package/core/server/services/gifts/gift-delivery-schema.js +5 -5
- package/core/server/services/gifts/gift-delivery-service.js +4 -0
- package/core/server/services/gifts/gift-schema.js +10 -10
- package/core/server/services/gifts/gift-service.js +4 -2
- package/core/server/services/jobs-service/register-job-handlers.js +5 -5
- package/core/server/services/lib/mailgun-client.js +44 -8
- package/core/server/services/media-inliner/external-media-inliner-job.js +12 -0
- package/core/server/services/media-inliner/external-media-inliner.js +103 -29
- package/core/server/services/media-inliner/service.js +13 -41
- package/core/server/services/media-inliner/types.js +2 -0
- package/core/server/services/members/import-export/export/exporter.js +4 -6
- package/core/server/services/members/import-export/import/importer.js +21 -5
- package/core/server/services/members/import-export/import/stripe-utils.js +6 -1
- package/core/server/services/members/import-export/index.js +6 -1
- package/core/server/services/members/members-api/members-api.js +5 -0
- package/core/server/services/members/members-api/services/member-bread-service.js +19 -1
- package/core/server/services/members/members-api/services/payments-service.js +47 -1
- package/core/server/services/members-custom-fields/actions.js +27 -1
- package/core/server/services/members-custom-fields/bindings-service.js +119 -0
- package/core/server/services/members-custom-fields/definitions-service.js +104 -13
- package/core/server/services/members-custom-fields/index.js +11 -4
- package/core/server/services/members-custom-fields/queries.js +5 -0
- package/core/server/services/members-custom-fields/schema.js +37 -6
- package/core/server/services/members-custom-fields/values-service.js +15 -3
- package/core/server/services/public-config/config.js +7 -0
- package/core/server/services/stripe/services/checkout/allowed-countries.js +267 -0
- package/core/server/services/stripe/services/checkout/completed-session.js +68 -0
- package/core/server/services/stripe/services/checkout/field-ports.js +34 -0
- package/core/server/services/stripe/services/checkout/session-options.js +97 -0
- package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +49 -0
- package/core/server/services/stripe/stripe-api.js +29 -0
- package/core/server/services/stripe/stripe-service.js +7 -0
- package/core/server/services/tier-checkout-config/codec.js +95 -0
- package/core/server/services/tier-checkout-config/destinations.js +17 -0
- package/core/server/services/tier-checkout-config/index.js +26 -0
- package/core/server/services/tier-checkout-config/models.js +57 -0
- package/core/server/services/tier-checkout-config/queries.js +80 -0
- package/core/server/services/tier-checkout-config/schema.js +33 -0
- package/core/server/services/tier-checkout-config/serializers.js +122 -0
- package/core/server/services/tier-checkout-config/service.js +303 -0
- package/core/server/services/tiers/service.js +21 -0
- package/core/server/web/api/endpoints/admin/routes.js +24 -13
- package/core/server/web/api/middleware/upload.js +2 -2
- package/core/server/web/parent/app.js +5 -0
- package/core/server/web/parent/middleware/filter-query-parameters.js +94 -0
- package/core/server/web/parent/middleware/index.js +1 -0
- package/core/server/web/query-parameter-policy/index.js +9 -0
- package/core/server/web/query-parameter-policy/policy.json +58 -0
- package/core/server/web/query-parameter-policy/schema.js +38 -0
- package/core/shared/config/defaults.json +3 -0
- package/core/shared/config/env/config.testing-mysql.json +3 -0
- package/core/shared/config/env/config.testing.json +3 -0
- package/core/shared/config/overrides.json +4 -2
- package/core/shared/labs.js +5 -14
- package/package.json +12 -13
- package/pnpm-lock.yaml +44 -46
- package/pnpm-workspace.yaml +6 -6
- package/tsconfig.json +2 -3
- package/core/built/admin/assets/activitypub/layout-CXajhRsL.js +0 -1
- package/core/built/admin/assets/alert-dialog-wEbVxANM.js +0 -1
- package/core/built/admin/assets/app-utils-D2Wp7ZSS.js +0 -1
- package/core/built/admin/assets/audience-DTLMXAFH.js +0 -1
- package/core/built/admin/assets/chart-helpers-B3OqQ6Ez.js +0 -1
- package/core/built/admin/assets/command-DcLbSifC.js +0 -1
- package/core/built/admin/assets/comments-Bxy_3WyE.js +0 -1
- package/core/built/admin/assets/design-and-theme-modal-CZ-PkW7o.js +0 -23
- package/core/built/admin/assets/dialog-Db7c164G.js +0 -1
- package/core/built/admin/assets/edit-profile-By7v5XW5.js +0 -1
- package/core/built/admin/assets/growth-55vWlGT_.js +0 -1
- package/core/built/admin/assets/growth-DA5AluYw.js +0 -3
- package/core/built/admin/assets/history-modal-G1s5hHz7.js +0 -1
- package/core/built/admin/assets/html-field-BegxsWpw.js +0 -1
- package/core/built/admin/assets/index-CDP9tIOk.js +0 -4
- package/core/built/admin/assets/koenig-loader-DwVY_V-H.js +0 -1
- package/core/built/admin/assets/kpi-card-LERqWBoY.js +0 -1
- package/core/built/admin/assets/kpi-helpers-DB3ouhYF.js +0 -1
- package/core/built/admin/assets/kpi-tabs-BGvtMD8S.js +0 -1
- package/core/built/admin/assets/layout-Di5K7doM.js +0 -1
- package/core/built/admin/assets/member-detail-D7mZDDp3.js +0 -1
- package/core/built/admin/assets/member-route-0Aa52Ntz.js +0 -1
- package/core/built/admin/assets/members-DvZG9t69.js +0 -2
- package/core/built/admin/assets/navigation-modal-CI8Bx5vn.js +0 -1
- package/core/built/admin/assets/newsletter-Bg3cq5U-.js +0 -1
- package/core/built/admin/assets/newsletters-DMDfZbMS.js +0 -1
- package/core/built/admin/assets/notifications-psA_2Ph4.js +0 -1
- package/core/built/admin/assets/overview-C-6xOLaf.js +0 -1
- package/core/built/admin/assets/overview-DaLhpRrC.js +0 -1
- package/core/built/admin/assets/popover-CFgqFDvC.js +0 -1
- package/core/built/admin/assets/portal-modal-Cf0pBAk8.js +0 -1
- package/core/built/admin/assets/profile-D6dHYf2o.js +0 -1
- package/core/built/admin/assets/radio-group-CjtmsCPl.js +0 -1
- package/core/built/admin/assets/select-D_RQaXgt.js +0 -1
- package/core/built/admin/assets/settings-DIo_F-MF.js +0 -4
- package/core/built/admin/assets/sort-button-DMBXF7tP.js +0 -1
- package/core/built/admin/assets/tag-detail-2a3BfzTW.js +0 -2
- package/core/built/admin/assets/tags-Dp2_8UzL.js +0 -1
- package/core/built/admin/assets/testimonials-modal-C9nrypNo.js +0 -1
- package/core/built/admin/assets/use-check-theme-limit-error-C9-QhGdV.js +0 -1
- package/core/built/admin/assets/use-filter-params-CSpAvgD2.js +0 -1
- package/core/built/admin/assets/use-growth-stats-BOmoPDHJ.js +0 -1
- package/core/built/admin/assets/user-detail-modal-59mBJqxN.js +0 -1
- package/core/built/admin/assets/web-DUuX7nE2.js +0 -2
- package/core/built/admin/assets/web-N8ucs2aG.js +0 -1
- /package/core/server/lib/{db-date.js → db-types/date.js} +0 -0
|
@@ -165,8 +165,8 @@ module.exports = class MailgunClient {
|
|
|
165
165
|
* @param {Object} mailgunOptions
|
|
166
166
|
* @param {Function} batchHandler
|
|
167
167
|
* @param {Object} options
|
|
168
|
-
* @param {number} [options.maxEvents]
|
|
169
|
-
* @returns {Promise<void>}
|
|
168
|
+
* @param {number} [options.maxEvents] Per-domain soft maximum. We stop fetching a domain after we reached the maximum AND received at least one event after begin (not equal) to prevent deadlocks.
|
|
169
|
+
* @returns {Promise<{safeCursor?: Date} | void>}
|
|
170
170
|
*/
|
|
171
171
|
async fetchEvents(mailgunOptions, batchHandler, { maxEvents = Infinity } = {}) {
|
|
172
172
|
const mailgunInstance = this.getInstance();
|
|
@@ -184,12 +184,33 @@ module.exports = class MailgunClient {
|
|
|
184
184
|
// Determine which domains to fetch from
|
|
185
185
|
const domains = this.#getDomainsToFetch(mailgunConfig);
|
|
186
186
|
|
|
187
|
+
const cappedDomainCursors = [];
|
|
188
|
+
|
|
187
189
|
// Fetch events from each domain
|
|
188
190
|
for (const domain of domains) {
|
|
189
|
-
await this.#fetchEventsFromDomain(
|
|
190
|
-
|
|
191
|
-
|
|
191
|
+
const result = await this.#fetchEventsFromDomain(
|
|
192
|
+
domain,
|
|
193
|
+
mailgunInstance,
|
|
194
|
+
mailgunOptions,
|
|
195
|
+
batchHandler,
|
|
196
|
+
{ maxEvents },
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
if (
|
|
200
|
+
result.capped &&
|
|
201
|
+
result.lastEventTimestamp &&
|
|
202
|
+
Number.isFinite(result.lastEventTimestamp.getTime())
|
|
203
|
+
) {
|
|
204
|
+
cappedDomainCursors.push(result.lastEventTimestamp);
|
|
205
|
+
}
|
|
192
206
|
}
|
|
207
|
+
|
|
208
|
+
const safeCursor = cappedDomainCursors.reduce(
|
|
209
|
+
(earliest, cursor) => (!earliest || cursor < earliest ? cursor : earliest),
|
|
210
|
+
undefined,
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
return { safeCursor };
|
|
193
214
|
}
|
|
194
215
|
|
|
195
216
|
/**
|
|
@@ -220,7 +241,7 @@ module.exports = class MailgunClient {
|
|
|
220
241
|
* @param {Function} batchHandler
|
|
221
242
|
* @param {Object} options
|
|
222
243
|
* @param {number} options.maxEvents
|
|
223
|
-
* @returns {Promise<
|
|
244
|
+
* @returns {Promise<{capped: boolean, eventCount: number, lastEventTimestamp?: Date}>}
|
|
224
245
|
*/
|
|
225
246
|
async #fetchEventsFromDomain(
|
|
226
247
|
domain,
|
|
@@ -235,6 +256,9 @@ module.exports = class MailgunClient {
|
|
|
235
256
|
|
|
236
257
|
let batchCount = 0;
|
|
237
258
|
let totalBatchTime = 0;
|
|
259
|
+
let eventCount = 0;
|
|
260
|
+
let lastEventTimestamp;
|
|
261
|
+
let capped = false;
|
|
238
262
|
|
|
239
263
|
try {
|
|
240
264
|
let page = await this.getEventsFromMailgun(mailgunInstance, domain, mailgunOptions);
|
|
@@ -248,7 +272,6 @@ module.exports = class MailgunClient {
|
|
|
248
272
|
`[MailgunClient fetchEventsFromDomain ${domain}]: finished fetching first page with ${events.length} events`,
|
|
249
273
|
);
|
|
250
274
|
|
|
251
|
-
let eventCount = 0;
|
|
252
275
|
const beginTimestamp = mailgunOptions.begin
|
|
253
276
|
? Math.ceil(mailgunOptions.begin * 1000)
|
|
254
277
|
: undefined; // ceil here if we have rounding errors
|
|
@@ -263,6 +286,13 @@ module.exports = class MailgunClient {
|
|
|
263
286
|
totalBatchTime += batchDuration;
|
|
264
287
|
|
|
265
288
|
eventCount += events.length;
|
|
289
|
+
const batchLastEventTimestamp = events[events.length - 1].timestamp;
|
|
290
|
+
if (
|
|
291
|
+
batchLastEventTimestamp &&
|
|
292
|
+
(!lastEventTimestamp || batchLastEventTimestamp > lastEventTimestamp)
|
|
293
|
+
) {
|
|
294
|
+
lastEventTimestamp = batchLastEventTimestamp;
|
|
295
|
+
}
|
|
266
296
|
|
|
267
297
|
if (
|
|
268
298
|
eventCount >= maxEvents &&
|
|
@@ -270,6 +300,7 @@ module.exports = class MailgunClient {
|
|
|
270
300
|
!events[events.length - 1].timestamp ||
|
|
271
301
|
events[events.length - 1].timestamp.getTime() > beginTimestamp)
|
|
272
302
|
) {
|
|
303
|
+
capped = true;
|
|
273
304
|
break;
|
|
274
305
|
}
|
|
275
306
|
|
|
@@ -294,10 +325,15 @@ module.exports = class MailgunClient {
|
|
|
294
325
|
const overallEndTime = Date.now();
|
|
295
326
|
const totalDuration = overallEndTime - overallStartTime;
|
|
296
327
|
const averageBatchTime = batchCount > 0 ? totalBatchTime / batchCount : 0;
|
|
328
|
+
const cursor = Number.isFinite(lastEventTimestamp?.getTime())
|
|
329
|
+
? lastEventTimestamp.toISOString()
|
|
330
|
+
: 'none';
|
|
297
331
|
|
|
298
332
|
logging.info(
|
|
299
|
-
`[MailgunClient fetchEventsFromDomain ${domain}]: Processed ${batchCount} batches in ${(totalDuration / 1000).toFixed(2)}s. Average batch time: ${(averageBatchTime / 1000).toFixed(2)}s`,
|
|
333
|
+
`[MailgunClient fetchEventsFromDomain ${domain}]: Processed ${eventCount} events in ${batchCount} batches in ${(totalDuration / 1000).toFixed(2)}s. Average batch time: ${(averageBatchTime / 1000).toFixed(2)}s. Status: ${capped ? 'capped' : 'exhausted'}. Cursor: ${cursor}`,
|
|
300
334
|
);
|
|
335
|
+
|
|
336
|
+
return { capped, eventCount, lastEventTimestamp };
|
|
301
337
|
} catch (error) {
|
|
302
338
|
logging.error(`[MailgunClient fetchEventsFromDomain ${domain}]: Error fetching events`);
|
|
303
339
|
logging.error(error);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const job_1 = require("../jobs-service/job");
|
|
4
|
+
class ExternalMediaInlinerJob extends job_1.Job {
|
|
5
|
+
static type = 'external-media-inliner';
|
|
6
|
+
domains;
|
|
7
|
+
constructor({ domains }) {
|
|
8
|
+
super();
|
|
9
|
+
this.domains = domains;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.default = ExternalMediaInlinerJob;
|
|
@@ -177,6 +177,96 @@ class ExternalMediaInliner {
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Download and store one external media URL without deciding where it came from
|
|
182
|
+
* or where its replacement belongs. Callers own discovery and replacement.
|
|
183
|
+
*
|
|
184
|
+
* @param {string} sourceUrl
|
|
185
|
+
* @returns {Promise<import('./types').ExternalMediaImportResult>}
|
|
186
|
+
*/
|
|
187
|
+
async importUrl(sourceUrl) {
|
|
188
|
+
let response;
|
|
189
|
+
try {
|
|
190
|
+
response = await this.getRemoteMedia(sourceUrl);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
return {
|
|
193
|
+
status: 'failed',
|
|
194
|
+
sourceUrl,
|
|
195
|
+
stage: 'download',
|
|
196
|
+
reason: 'The media file could not be downloaded.',
|
|
197
|
+
error,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (!response) {
|
|
202
|
+
return {
|
|
203
|
+
status: 'failed',
|
|
204
|
+
sourceUrl,
|
|
205
|
+
stage: 'download',
|
|
206
|
+
reason: 'The media file could not be downloaded.',
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let media;
|
|
211
|
+
try {
|
|
212
|
+
media = await this.extractFileDataFromResponse(sourceUrl, response);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
return {
|
|
215
|
+
status: 'failed',
|
|
216
|
+
sourceUrl,
|
|
217
|
+
stage: 'extract',
|
|
218
|
+
reason: 'The downloaded media file could not be read.',
|
|
219
|
+
error,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
const storedUrl = await this.storeMediaLocally(media);
|
|
225
|
+
if (!storedUrl) {
|
|
226
|
+
return {
|
|
227
|
+
status: 'failed',
|
|
228
|
+
sourceUrl,
|
|
229
|
+
stage: 'unsupported',
|
|
230
|
+
reason: 'No configured storage accepts this media file.',
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
status: 'stored',
|
|
236
|
+
sourceUrl,
|
|
237
|
+
storedUrl,
|
|
238
|
+
};
|
|
239
|
+
} catch (error) {
|
|
240
|
+
return {
|
|
241
|
+
status: 'failed',
|
|
242
|
+
sourceUrl,
|
|
243
|
+
stage: 'storage',
|
|
244
|
+
reason: 'The media file could not be stored in Ghost.',
|
|
245
|
+
error,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Convert an import result into the replacement URL expected by the existing
|
|
252
|
+
* content and field processing. Expected download and unsupported-file failures
|
|
253
|
+
* return null so the original URL remains unchanged. Results containing an
|
|
254
|
+
* underlying processing error are rethrown so the established per-resource
|
|
255
|
+
* catch boundary continues to log and isolate them.
|
|
256
|
+
*
|
|
257
|
+
* @param {import('./types').ExternalMediaImportResult} result
|
|
258
|
+
* @returns {string|null}
|
|
259
|
+
*/
|
|
260
|
+
#replacementUrlFromImportResult(result) {
|
|
261
|
+
if (result.status === 'stored') {
|
|
262
|
+
return result.storedUrl;
|
|
263
|
+
}
|
|
264
|
+
if ('error' in result) {
|
|
265
|
+
throw result.error;
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
|
|
180
270
|
static findMatches(content, domain) {
|
|
181
271
|
// NOTE: the src could end with a quote, bracket, apostrophe, double-backslash, or encoded quote.
|
|
182
272
|
// Backlashes are added to content as an escape character
|
|
@@ -208,22 +298,14 @@ class ExternalMediaInliner {
|
|
|
208
298
|
const matches = this.constructor.findMatches(content, domain);
|
|
209
299
|
|
|
210
300
|
for (const src of matches) {
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const inlinedSrc = await this.storeMediaLocally(media);
|
|
220
|
-
|
|
221
|
-
if (inlinedSrc) {
|
|
222
|
-
// NOTE: does not account for duplicate images in content
|
|
223
|
-
// in those cases would be processed twice
|
|
224
|
-
content = content.replace(src, inlinedSrc);
|
|
225
|
-
logging.info(`Inlined media: ${src} -> ${inlinedSrc}`);
|
|
226
|
-
}
|
|
301
|
+
const result = await this.importUrl(src);
|
|
302
|
+
const replacementUrl = this.#replacementUrlFromImportResult(result);
|
|
303
|
+
|
|
304
|
+
if (replacementUrl) {
|
|
305
|
+
// NOTE: does not account for duplicate images in content
|
|
306
|
+
// in those cases would be processed twice
|
|
307
|
+
content = content.replace(src, replacementUrl);
|
|
308
|
+
logging.info(`Inlined media: ${src} -> ${replacementUrl}`);
|
|
227
309
|
}
|
|
228
310
|
}
|
|
229
311
|
}
|
|
@@ -246,20 +328,12 @@ class ExternalMediaInliner {
|
|
|
246
328
|
const src = resourceModel.get(field);
|
|
247
329
|
|
|
248
330
|
if (src && src.startsWith(domain)) {
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
let media;
|
|
252
|
-
if (response) {
|
|
253
|
-
media = await this.extractFileDataFromResponse(src, response);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (media) {
|
|
257
|
-
const inlinedSrc = await this.storeMediaLocally(media);
|
|
331
|
+
const result = await this.importUrl(src);
|
|
332
|
+
const replacementUrl = this.#replacementUrlFromImportResult(result);
|
|
258
333
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
334
|
+
if (replacementUrl) {
|
|
335
|
+
updatedFields[field] = replacementUrl;
|
|
336
|
+
logging.info(`Added media to inline: ${src} -> ${replacementUrl}`);
|
|
263
337
|
}
|
|
264
338
|
}
|
|
265
339
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
const errors = require('@tryghost/errors');
|
|
2
|
+
|
|
3
|
+
let instance;
|
|
4
|
+
|
|
1
5
|
module.exports = {
|
|
2
6
|
async init() {
|
|
3
|
-
const debug = require('@tryghost/debug')('mediaInliner');
|
|
4
7
|
const MediaInliner = require('./external-media-inliner');
|
|
5
|
-
const logging = require('@tryghost/logging');
|
|
6
8
|
const models = require('../../models');
|
|
7
|
-
const jobsService = require('../jobs');
|
|
8
9
|
const adapterManager = require('../../services/adapter-manager').default;
|
|
9
10
|
|
|
10
11
|
const mediaStorage = adapterManager.getAdapter('storage:media');
|
|
@@ -31,45 +32,16 @@ module.exports = {
|
|
|
31
32
|
},
|
|
32
33
|
});
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (!domains || !domains.length) {
|
|
37
|
-
// default domains to inline from if none are provided
|
|
38
|
-
domains = ['https://s3.amazonaws.com/revue', 'https://substackcdn.com'];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
debug('[Inliner] Starting media inlining job for domains: ', domains);
|
|
35
|
+
instance = mediaInliner;
|
|
36
|
+
},
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const startedAt = Date.now();
|
|
50
|
-
logging.info('[Background Job] external-media-inliner started');
|
|
51
|
-
try {
|
|
52
|
-
const result = await mediaInliner.inline(data.domains);
|
|
53
|
-
logging.info(
|
|
54
|
-
`[Background Job] external-media-inliner completed in ${Date.now() - startedAt}ms`,
|
|
55
|
-
);
|
|
56
|
-
return result;
|
|
57
|
-
} catch (err) {
|
|
58
|
-
logging.error(
|
|
59
|
-
err,
|
|
60
|
-
`[Background Job] external-media-inliner failed after ${Date.now() - startedAt}ms`,
|
|
61
|
-
);
|
|
62
|
-
throw err;
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
data: { domains },
|
|
66
|
-
offloaded: false,
|
|
67
|
-
});
|
|
38
|
+
getInstance() {
|
|
39
|
+
if (!instance) {
|
|
40
|
+
throw new errors.IncorrectUsageError({
|
|
41
|
+
message: 'Media inliner used before init(). Call init() from boot first.',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
68
44
|
|
|
69
|
-
|
|
70
|
-
status: 'success',
|
|
71
|
-
};
|
|
72
|
-
},
|
|
73
|
-
};
|
|
45
|
+
return instance;
|
|
74
46
|
},
|
|
75
47
|
};
|
|
@@ -54,14 +54,14 @@ class MembersCSVExporter {
|
|
|
54
54
|
const hasFilter = options.limit !== 'all' || options.filter || options.search;
|
|
55
55
|
const ids = hasFilter ? await this._members.findFilteredIds(options) : null;
|
|
56
56
|
if (ids) {
|
|
57
|
-
logging.info(
|
|
57
|
+
logging.info({ event: { name: 'members-export.filtered' }, matched: ids.length }, 'Found members matching the export filter');
|
|
58
58
|
}
|
|
59
59
|
const reference = await this.fetchReferenceData();
|
|
60
60
|
const membersQuery = this._knex('members').select(...MEMBER_COLUMNS);
|
|
61
61
|
if (ids) {
|
|
62
62
|
membersQuery.whereIn('id', ids);
|
|
63
63
|
}
|
|
64
|
-
logging.info('
|
|
64
|
+
logging.info({ event: { name: 'members-export.started' } }, 'Starting streaming export of members');
|
|
65
65
|
const batchingTransform = this.createBatchingTransform();
|
|
66
66
|
const processingTransform = this.createProcessingTransform(reference);
|
|
67
67
|
(0, node_stream_1.pipeline)(membersQuery.stream(), batchingTransform, processingTransform, (err) => {
|
|
@@ -69,9 +69,7 @@ class MembersCSVExporter {
|
|
|
69
69
|
logging.error({ event: { name: 'members-export.stream.error' }, err }, 'Members export stream failed');
|
|
70
70
|
}
|
|
71
71
|
else {
|
|
72
|
-
logging.info('
|
|
73
|
-
(Date.now() - start) / 1000 +
|
|
74
|
-
's');
|
|
72
|
+
logging.info({ event: { name: 'members-export.completed' }, durationMs: Date.now() - start }, 'Members export completed');
|
|
75
73
|
}
|
|
76
74
|
});
|
|
77
75
|
return processingTransform;
|
|
@@ -95,7 +93,7 @@ class MembersCSVExporter {
|
|
|
95
93
|
acc[label.id] = label.name;
|
|
96
94
|
return acc;
|
|
97
95
|
}, {}));
|
|
98
|
-
logging.info(
|
|
96
|
+
logging.info({ event: { name: 'members-export.reference_data_read' }, durationMs: Date.now() - start }, 'Read the products and labels an export names');
|
|
99
97
|
const activeCustomFields = await this._customFields.activeDefinitions();
|
|
100
98
|
return { allProducts, allLabels, activeCustomFields };
|
|
101
99
|
}
|
|
@@ -17,6 +17,7 @@ const messages = {
|
|
|
17
17
|
giftCannotCombineWithImportTier: 'Cannot specify both gift_id and import_tier.',
|
|
18
18
|
giftCannotCombineWithComplimentary: 'Cannot specify both gift_id and complimentary_plan.',
|
|
19
19
|
giftReassignFailed: 'Failed to reassign gift to member.',
|
|
20
|
+
customFieldWriteFailed: 'Failed to save the custom field values for this member.',
|
|
20
21
|
};
|
|
21
22
|
// Columns whose presence makes a row slow to import (they reach out to Stripe), so
|
|
22
23
|
// a file carrying any of them is deferred regardless of size. The routing decision
|
|
@@ -90,7 +91,7 @@ class MembersCSVImporter {
|
|
|
90
91
|
// a request without a user actually reaches the deferred path.
|
|
91
92
|
const emailRecipient = requestUserEmail ?? (await this._email.getDefaultRecipient());
|
|
92
93
|
const spooled = await this._spool.write(rows);
|
|
93
|
-
logging.info(
|
|
94
|
+
logging.info({ event: { name: 'members.import.queued' }, rows: rows.length }, 'Members import queued');
|
|
94
95
|
this._addJob({
|
|
95
96
|
job: () => this.runImportJob(spooled, { labelName, extraLabels, emailRecipient }, verificationTrigger),
|
|
96
97
|
offloaded: false,
|
|
@@ -101,7 +102,7 @@ class MembersCSVImporter {
|
|
|
101
102
|
// in the job itself, and there is no retry behind it.
|
|
102
103
|
async runImportJob(spooled, { labelName, extraLabels, emailRecipient, }, verificationTrigger) {
|
|
103
104
|
const startedAt = Date.now();
|
|
104
|
-
logging.info(
|
|
105
|
+
logging.info({ event: { name: 'members.import.started' } }, 'Members import started');
|
|
105
106
|
// Null until the import produces one: parsing and mapping already happened inside
|
|
106
107
|
// the request, so anything failing from here is ours rather than the file's.
|
|
107
108
|
let result = null;
|
|
@@ -125,10 +126,15 @@ class MembersCSVImporter {
|
|
|
125
126
|
links: this._email.links,
|
|
126
127
|
})));
|
|
127
128
|
if (result) {
|
|
128
|
-
logging.info(
|
|
129
|
+
logging.info({
|
|
130
|
+
event: { name: 'members.import.completed' },
|
|
131
|
+
durationMs: Date.now() - startedAt,
|
|
132
|
+
imported: result.imported,
|
|
133
|
+
rejected: result.errors.length,
|
|
134
|
+
}, 'Members import completed');
|
|
129
135
|
}
|
|
130
136
|
else {
|
|
131
|
-
logging.info(
|
|
137
|
+
logging.info({ event: { name: 'members.import.failed' }, durationMs: Date.now() - startedAt }, 'Members import failed');
|
|
132
138
|
}
|
|
133
139
|
}
|
|
134
140
|
// Only the write itself may throw. Callers rely on that to tell an import that never
|
|
@@ -300,7 +306,17 @@ class MembersCSVImporter {
|
|
|
300
306
|
}
|
|
301
307
|
}
|
|
302
308
|
// On the row's transaction, so the values commit or roll back with the member.
|
|
303
|
-
|
|
309
|
+
try {
|
|
310
|
+
await this._customFields.applyWrite(member.id, customFieldPlan, trx);
|
|
311
|
+
}
|
|
312
|
+
catch (writeError) {
|
|
313
|
+
// planWrite passed every value before the transaction opened, so a failure
|
|
314
|
+
// here is ours and not the row's. Operators get the original, which a driver
|
|
315
|
+
// will have written a query into; the publisher gets a sentence instead, in a
|
|
316
|
+
// file they open next to a spreadsheet.
|
|
317
|
+
this._report(writeError);
|
|
318
|
+
throw new errors.DataImportError({ message: tpl(messages.customFieldWriteFailed) });
|
|
319
|
+
}
|
|
304
320
|
await trx.commit();
|
|
305
321
|
imported += 1;
|
|
306
322
|
}
|
|
@@ -175,7 +175,12 @@ module.exports = class MembersCSVImporterStripeUtils {
|
|
|
175
175
|
await this.archivePrice(newStripePrice.id);
|
|
176
176
|
} catch (archiveErr) {
|
|
177
177
|
logging.warn(
|
|
178
|
-
|
|
178
|
+
{
|
|
179
|
+
event: { name: 'members.import.orphaned_price_archive_failed' },
|
|
180
|
+
err: archiveErr,
|
|
181
|
+
stripePriceId: newStripePrice.id,
|
|
182
|
+
},
|
|
183
|
+
'Failed to archive an orphaned Stripe price after a failed subscription update',
|
|
179
184
|
);
|
|
180
185
|
}
|
|
181
186
|
throw err;
|
|
@@ -63,7 +63,12 @@ function makeImporter(deps) {
|
|
|
63
63
|
const customFields = {
|
|
64
64
|
activeFields: async () => labs.isSet('membersCustomFields') ? deps.customFields.definitions.browse() : [],
|
|
65
65
|
planWrite: (values) => deps.customFields.values.planWrite(values),
|
|
66
|
-
|
|
66
|
+
// Every value the import writes came out of the file, whichever column carried it.
|
|
67
|
+
// An import has no id to give until runs are tracked, so it names its kind only.
|
|
68
|
+
applyWrite: (memberId, plan, executor) => deps.customFields.values.applyWrite(memberId, plan, {
|
|
69
|
+
writtenBy: { type: 'import', id: null },
|
|
70
|
+
executor,
|
|
71
|
+
}),
|
|
67
72
|
};
|
|
68
73
|
// Inline jobs never reach the job manager's Sentry handler, which is wired to the
|
|
69
74
|
// offloaded worker path only, so a throw here would be seen by nobody.
|
|
@@ -179,6 +179,11 @@ module.exports = function MembersAPI({
|
|
|
179
179
|
offersAPI,
|
|
180
180
|
stripeAPIService,
|
|
181
181
|
settingsCache,
|
|
182
|
+
// The service wrapper, not the checkout config it builds: tiers and members are
|
|
183
|
+
// initialised in the same Promise.all, so reading the property here would capture
|
|
184
|
+
// whatever it was before tiers finished — usually undefined.
|
|
185
|
+
tiersService,
|
|
186
|
+
labsService,
|
|
182
187
|
});
|
|
183
188
|
|
|
184
189
|
const memberController = new MemberController({
|
|
@@ -9,6 +9,8 @@ const messages = {
|
|
|
9
9
|
memberNotFound: 'Member not found.',
|
|
10
10
|
customFieldsOnAdd:
|
|
11
11
|
'Custom field values cannot be set while creating a member. Create the member, then set values with an edit.',
|
|
12
|
+
customFieldsWithoutWriter:
|
|
13
|
+
'Custom field values cannot be set by a request with no authenticated user or integration.',
|
|
12
14
|
};
|
|
13
15
|
|
|
14
16
|
// Stored in the action's `context.action_name`; Admin maps it to a display label.
|
|
@@ -654,7 +656,23 @@ module.exports = class MemberBREADService {
|
|
|
654
656
|
}
|
|
655
657
|
|
|
656
658
|
if (plannedCustomFields) {
|
|
657
|
-
|
|
659
|
+
// Every value reaching here was typed into the Admin API, so the writer is
|
|
660
|
+
// whoever made the request — the same pair the action log records, so the two
|
|
661
|
+
// agree about who did it rather than one saying only that it was "admin".
|
|
662
|
+
//
|
|
663
|
+
// The only route to this branch is the authenticated Admin API, so an anonymous
|
|
664
|
+
// request is a mistake somewhere upstream rather than a writer to invent a name
|
|
665
|
+
// for. Refusing keeps every stored writer resolvable.
|
|
666
|
+
const context = options.context || {};
|
|
667
|
+
if (!context.integration && !context.user) {
|
|
668
|
+
throw new errors.IncorrectUsageError({
|
|
669
|
+
message: tpl(messages.customFieldsWithoutWriter),
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
const writtenBy = context.integration
|
|
673
|
+
? { type: 'integration', id: context.integration.id }
|
|
674
|
+
: { type: 'user', id: context.user };
|
|
675
|
+
await this.customFieldValues.applyWrite(model.id, plannedCustomFields, { writtenBy });
|
|
658
676
|
|
|
659
677
|
// Custom fields aren't a member column or relation, so an edit touching
|
|
660
678
|
// only them leaves `model._changed` empty and the save fires nothing.
|
|
@@ -14,6 +14,8 @@ 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 {{checkout: import('../../../tier-checkout-config').TierCheckoutConfigService}} deps.tiersService
|
|
18
|
+
* @param {{isSet(flag: string): boolean}} deps.labsService
|
|
17
19
|
*/
|
|
18
20
|
constructor(deps) {
|
|
19
21
|
/** @private */
|
|
@@ -30,6 +32,10 @@ class PaymentsService {
|
|
|
30
32
|
this.stripeAPIService = deps.stripeAPIService;
|
|
31
33
|
/** @private */
|
|
32
34
|
this.settingsCache = deps.settingsCache;
|
|
35
|
+
/** @private */
|
|
36
|
+
this.tiersService = deps.tiersService;
|
|
37
|
+
/** @private */
|
|
38
|
+
this.labsService = deps.labsService;
|
|
33
39
|
DomainEvents.subscribe(OfferCreatedEvent, async (event) => {
|
|
34
40
|
await this.getCouponForOffer(event.data.offer.id);
|
|
35
41
|
});
|
|
@@ -114,11 +120,19 @@ class PaymentsService {
|
|
|
114
120
|
const price = await this.getPriceForTierCadence(tier, cadence);
|
|
115
121
|
|
|
116
122
|
const data = {
|
|
117
|
-
|
|
123
|
+
// The tier being bought, recorded on the session so the completed event can find
|
|
124
|
+
// the configuration that produced its questions. Nothing else carries it: a
|
|
125
|
+
// completed session names prices and products, and mapping those back is a
|
|
126
|
+
// lookup that can fail where this cannot.
|
|
127
|
+
metadata: { ...metadata, ghostTierId: tier.id.toHexString() },
|
|
118
128
|
successUrl: successUrl,
|
|
119
129
|
cancelUrl: cancelUrl,
|
|
120
130
|
trialDays: trialDays ?? tier.trialDays,
|
|
121
131
|
coupon: coupon?.id,
|
|
132
|
+
// Resolved here rather than cached with the tier, so a field archived a minute
|
|
133
|
+
// ago stops being asked on the next checkout. A failure to resolve must not
|
|
134
|
+
// stop a member paying, so it costs the questions and nothing else.
|
|
135
|
+
checkout: await this.getCheckoutConfigForTier(tier),
|
|
122
136
|
};
|
|
123
137
|
|
|
124
138
|
// If we already have a coupon, we don't want to give trial days over it
|
|
@@ -135,6 +149,38 @@ class PaymentsService {
|
|
|
135
149
|
return session.url;
|
|
136
150
|
}
|
|
137
151
|
|
|
152
|
+
/**
|
|
153
|
+
* What this tier's checkout should ask for beyond the payment, or nothing.
|
|
154
|
+
*
|
|
155
|
+
* Undefined on every path but the configured one, including the flag being off: the
|
|
156
|
+
* session builder adds no parameters for it, so an unconfigured site's request to
|
|
157
|
+
* Stripe is exactly the request it made before this existed.
|
|
158
|
+
*
|
|
159
|
+
* @private
|
|
160
|
+
* @param {import('../../../tiers/tier')} tier
|
|
161
|
+
*/
|
|
162
|
+
async getCheckoutConfigForTier(tier) {
|
|
163
|
+
const checkoutConfig = this.tiersService?.checkout;
|
|
164
|
+
if (!this.labsService?.isSet('membersCustomFields') || !checkoutConfig) {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
return await checkoutConfig.resolve(tier.id.toHexString());
|
|
169
|
+
} catch (err) {
|
|
170
|
+
// A checkout that asks one fewer question still takes the money; one that fails
|
|
171
|
+
// to be created takes none. This is the whole reason it is caught.
|
|
172
|
+
logging.error(
|
|
173
|
+
{
|
|
174
|
+
event: { name: 'stripe_checkout.tier_config.resolve_failed' },
|
|
175
|
+
err,
|
|
176
|
+
tierId: tier.id.toHexString(),
|
|
177
|
+
},
|
|
178
|
+
'Failed to resolve what a tier checkout should collect',
|
|
179
|
+
);
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
138
184
|
/**
|
|
139
185
|
* @param {object} params
|
|
140
186
|
* @param {Member} [params.member]
|
|
@@ -3,8 +3,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.actingContext = actingContext;
|
|
6
7
|
exports.recordCustomFieldAction = recordCustomFieldAction;
|
|
7
8
|
const logging_1 = __importDefault(require("@tryghost/logging"));
|
|
9
|
+
/**
|
|
10
|
+
* Who is acting, read off an API frame's context.
|
|
11
|
+
*
|
|
12
|
+
* Here rather than in each endpoint, because two resources now record custom field history
|
|
13
|
+
* and a second reading of the same shape is a second chance to disagree about it. An
|
|
14
|
+
* integration and a user are both actors; a request that is neither — a webhook, a job —
|
|
15
|
+
* has none, and the history says so rather than guessing.
|
|
16
|
+
*/
|
|
17
|
+
function actingContext(context) {
|
|
18
|
+
const frame = (context ?? {});
|
|
19
|
+
if (frame.integration) {
|
|
20
|
+
return { actor: { id: frame.integration.id, type: 'integration' } };
|
|
21
|
+
}
|
|
22
|
+
if (frame.user) {
|
|
23
|
+
return { actor: { id: frame.user, type: 'user' } };
|
|
24
|
+
}
|
|
25
|
+
return { actor: null };
|
|
26
|
+
}
|
|
8
27
|
// Field-definition changes map to activity-feed events. A field's timeline reads
|
|
9
28
|
// added -> edited -> archived -> restored, and a permanent delete (only from the
|
|
10
29
|
// archived state) ends it with deleted.
|
|
@@ -35,6 +54,13 @@ async function recordCustomFieldAction({ Action, context, verb, subject, details
|
|
|
35
54
|
}, { autoRefresh: false });
|
|
36
55
|
}
|
|
37
56
|
catch (err) {
|
|
38
|
-
logging_1.default.error(
|
|
57
|
+
logging_1.default.error({
|
|
58
|
+
event: { name: 'members.custom_fields.action_log_failed' },
|
|
59
|
+
err,
|
|
60
|
+
verb,
|
|
61
|
+
subject,
|
|
62
|
+
actorType: context.actor.type,
|
|
63
|
+
actorId: context.actor.id,
|
|
64
|
+
}, 'Failed to record a member custom field action');
|
|
39
65
|
}
|
|
40
66
|
}
|