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
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CustomFieldBindingsService = void 0;
|
|
7
|
+
const bson_objectid_1 = __importDefault(require("bson-objectid"));
|
|
8
|
+
const logging_1 = __importDefault(require("@tryghost/logging"));
|
|
9
|
+
const schema_1 = require("./schema");
|
|
10
|
+
const FIELDS_TABLE = 'members_custom_fields';
|
|
11
|
+
const BINDINGS_TABLE = 'members_custom_field_bindings';
|
|
12
|
+
/**
|
|
13
|
+
* Where a source sends what it collected: a `port` is the name that source uses for a
|
|
14
|
+
* thing, and the binding resolves it to one of the publisher's fields.
|
|
15
|
+
*/
|
|
16
|
+
class CustomFieldBindingsService {
|
|
17
|
+
knex;
|
|
18
|
+
values;
|
|
19
|
+
constructor({ knex, values }) {
|
|
20
|
+
this.knex = knex;
|
|
21
|
+
this.values = values;
|
|
22
|
+
}
|
|
23
|
+
async bind(db, productId, port, customFieldKey, now) {
|
|
24
|
+
const existing = await db(BINDINGS_TABLE).where({ product_id: productId, port }).first();
|
|
25
|
+
if (existing?.custom_field_key === customFieldKey) {
|
|
26
|
+
await db(BINDINGS_TABLE).where('id', existing.id).update({ updated_at: now });
|
|
27
|
+
return existing.id;
|
|
28
|
+
}
|
|
29
|
+
if (existing) {
|
|
30
|
+
await db(BINDINGS_TABLE).where('id', existing.id).del();
|
|
31
|
+
}
|
|
32
|
+
const bindingId = new bson_objectid_1.default().toHexString();
|
|
33
|
+
await db(BINDINGS_TABLE).insert({
|
|
34
|
+
id: bindingId,
|
|
35
|
+
product_id: productId,
|
|
36
|
+
port,
|
|
37
|
+
custom_field_key: customFieldKey,
|
|
38
|
+
created_at: now,
|
|
39
|
+
updated_at: now,
|
|
40
|
+
});
|
|
41
|
+
return bindingId;
|
|
42
|
+
}
|
|
43
|
+
/** Stops the writing. Whatever hangs off the binding cascades with it. */
|
|
44
|
+
async remove(db, productId, port) {
|
|
45
|
+
await db(BINDINGS_TABLE).where({ product_id: productId, port }).del();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Values arrive in the order they are to be applied: where two land in one field, the
|
|
49
|
+
* last of them is what the field holds.
|
|
50
|
+
*/
|
|
51
|
+
async writeCollected(memberId, productId, collected) {
|
|
52
|
+
for (const { port, value } of collected) {
|
|
53
|
+
const destination = await this.resolve(productId, port);
|
|
54
|
+
if (!destination) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
await this.writeOne(memberId, destination, value);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async writeOne(memberId, into, value) {
|
|
61
|
+
let planned;
|
|
62
|
+
try {
|
|
63
|
+
planned = await this.values.planWrite({ [into.key]: value });
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
logging_1.default.warn({
|
|
67
|
+
event: { name: 'members.custom_fields.collected_value_rejected' },
|
|
68
|
+
err,
|
|
69
|
+
memberId,
|
|
70
|
+
customFieldKey: into.key,
|
|
71
|
+
}, 'A collected value could not be saved');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
await this.values.applyWrite(memberId, planned, {
|
|
76
|
+
writtenBy: { type: 'binding', id: into.bindingId },
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
logging_1.default.error({
|
|
81
|
+
event: { name: 'members.custom_fields.collected_value_write_failed' },
|
|
82
|
+
err,
|
|
83
|
+
memberId,
|
|
84
|
+
customFieldKey: into.key,
|
|
85
|
+
bindingId: into.bindingId,
|
|
86
|
+
}, 'Failed to store a collected custom field value');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async resolve(productId, port) {
|
|
90
|
+
const row = await this.knex(BINDINGS_TABLE)
|
|
91
|
+
.join(FIELDS_TABLE, `${BINDINGS_TABLE}.custom_field_key`, `${FIELDS_TABLE}.key`)
|
|
92
|
+
.where(`${BINDINGS_TABLE}.product_id`, productId)
|
|
93
|
+
.where(`${BINDINGS_TABLE}.port`, port)
|
|
94
|
+
// An archived destination is still where this goes, and still not somewhere a value
|
|
95
|
+
// can land, so the write drops rather than waiting.
|
|
96
|
+
.where(`${FIELDS_TABLE}.status`, schema_1.FIELD_STATUS.active)
|
|
97
|
+
.select(`${BINDINGS_TABLE}.id as binding_id`, `${FIELDS_TABLE}.key`, `${FIELDS_TABLE}.type`)
|
|
98
|
+
.first();
|
|
99
|
+
if (!row) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
// Decoded rather than trusted: a join is a read boundary, and `type` is what decides
|
|
103
|
+
// how the collected value is read. Unreadable counts as unresolved rather than
|
|
104
|
+
// throwing, so one bad row skips its value the way an unbound port does instead of
|
|
105
|
+
// failing everything else the same checkout collected.
|
|
106
|
+
const bound = schema_1.DbBoundField.safeParse(row);
|
|
107
|
+
if (!bound.success) {
|
|
108
|
+
logging_1.default.warn({
|
|
109
|
+
event: { name: 'members.custom_fields.binding_unreadable' },
|
|
110
|
+
err: bound.error,
|
|
111
|
+
productId,
|
|
112
|
+
port,
|
|
113
|
+
}, 'A binding could not be read');
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
return { bindingId: bound.data.binding_id, key: bound.data.key, type: bound.data.type };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.CustomFieldBindingsService = CustomFieldBindingsService;
|
|
@@ -33,10 +33,12 @@ const MAX_KEY_BASE_LENGTH = MAX_KEY_LENGTH - (String(MAX_KEY_ITERATIONS).length
|
|
|
33
33
|
// object from JSON.parse. A key naming a member of Object.prototype reads back as
|
|
34
34
|
// inherited rather than absent wherever one of those objects is indexed.
|
|
35
35
|
//
|
|
36
|
-
// Derived rather than listed,
|
|
37
|
-
// minted:
|
|
38
|
-
//
|
|
39
|
-
|
|
36
|
+
// Derived rather than listed, from the format a key may take rather than from how one
|
|
37
|
+
// is minted: a caller can state a key instead of deriving it from a name, so what has
|
|
38
|
+
// to be reserved is every prototype name a well-formed key could spell. The ones that
|
|
39
|
+
// carry a capital cannot be spelled at all and need no reserving; `constructor` and
|
|
40
|
+
// `__proto__` can.
|
|
41
|
+
const RESERVED_KEYS = Object.getOwnPropertyNames(Object.prototype).filter((name) => key_1.KEY_CHARACTERS.test(name));
|
|
40
42
|
const FieldName = zod_1.z
|
|
41
43
|
.string()
|
|
42
44
|
.trim()
|
|
@@ -114,11 +116,11 @@ class CustomFieldDefinitionsService {
|
|
|
114
116
|
return rows.map((row) => zod_1.z.decode(codec_1.customFieldCodec, row));
|
|
115
117
|
}
|
|
116
118
|
async read(key) {
|
|
117
|
-
const
|
|
118
|
-
if (!
|
|
119
|
+
const [field] = await this.list((0, queries_1.fieldByKey)(this.knex, key));
|
|
120
|
+
if (!field) {
|
|
119
121
|
throw new errors_1.default.NotFoundError({ message: 'Custom field not found.' });
|
|
120
122
|
}
|
|
121
|
-
return
|
|
123
|
+
return field;
|
|
122
124
|
}
|
|
123
125
|
/**
|
|
124
126
|
* Create one or more field definitions. All-or-nothing: the batch runs in a
|
|
@@ -167,13 +169,11 @@ class CustomFieldDefinitionsService {
|
|
|
167
169
|
for (const [index, field] of fields.entries()) {
|
|
168
170
|
await this.assertNameAvailable(trx, field.name);
|
|
169
171
|
const key = await this.mintKey(trx, bases[index]);
|
|
170
|
-
await
|
|
171
|
-
id: new bson_objectid_1.default().toHexString(),
|
|
172
|
+
await this.insertField(trx, {
|
|
172
173
|
key,
|
|
173
174
|
name: field.name,
|
|
174
175
|
type: field.type,
|
|
175
|
-
|
|
176
|
-
created_at: new Date(),
|
|
176
|
+
sortOrder: firstSortOrder + index,
|
|
177
177
|
});
|
|
178
178
|
keys.push(key);
|
|
179
179
|
}
|
|
@@ -194,7 +194,69 @@ class CustomFieldDefinitionsService {
|
|
|
194
194
|
// Logged after the commit: the action log is a separate Bookshelf write
|
|
195
195
|
// outside this transaction, so recording inside it would leave orphaned
|
|
196
196
|
// "added" entries for fields a rollback never created.
|
|
197
|
-
|
|
197
|
+
await this.recordCreated(context, created);
|
|
198
|
+
return created;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Given an executor it joins that transaction; given none it opens its own. Unlike
|
|
202
|
+
* `add`, the key is stated rather than minted from the name, and nothing about it is
|
|
203
|
+
* worked around: a caller states a key because something else already names that key,
|
|
204
|
+
* so a variant of it would be a field nothing points at.
|
|
205
|
+
*
|
|
206
|
+
* The field is returned rather than logged: the history writes on its own connection,
|
|
207
|
+
* which a single-connection pool would deadlock against an open transaction.
|
|
208
|
+
*/
|
|
209
|
+
async addOne(wanted, { executor = this.knex } = {}) {
|
|
210
|
+
// Before any database access, the way `add` mints before opening its transaction:
|
|
211
|
+
// an unusable key is a payload problem worth reporting on its own terms.
|
|
212
|
+
assertKeyUsable(wanted.key);
|
|
213
|
+
const write = async (db) => {
|
|
214
|
+
await this.assertWithinLimit(db, 1);
|
|
215
|
+
await this.assertKeyAvailable(db, wanted.key);
|
|
216
|
+
await this.assertNameAvailable(db, wanted.name);
|
|
217
|
+
await this.insertField(db, {
|
|
218
|
+
key: wanted.key,
|
|
219
|
+
name: wanted.name,
|
|
220
|
+
type: wanted.type,
|
|
221
|
+
sortOrder: await this.nextSortOrder(db),
|
|
222
|
+
});
|
|
223
|
+
const [created] = await this.readMany(db, [wanted.key]);
|
|
224
|
+
return created;
|
|
225
|
+
};
|
|
226
|
+
// knex's marker for a transactor: join it rather than nesting a savepoint under it.
|
|
227
|
+
return executor.isTransaction ? write(executor) : executor.transaction(write);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Only for a stated key. Minting picks a free one instead, so this reads as a clean 422
|
|
231
|
+
* where the unique index would read as a 500.
|
|
232
|
+
*/
|
|
233
|
+
async assertKeyAvailable(db, key) {
|
|
234
|
+
const taken = await db(TABLE).where('key', key).first();
|
|
235
|
+
if (taken) {
|
|
236
|
+
throw new errors_1.default.ValidationError({
|
|
237
|
+
message: 'A custom field with this key already exists.',
|
|
238
|
+
property: 'key',
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async insertField(db, field) {
|
|
243
|
+
await db(TABLE).insert({
|
|
244
|
+
id: new bson_objectid_1.default().toHexString(),
|
|
245
|
+
key: field.key,
|
|
246
|
+
name: field.name,
|
|
247
|
+
type: field.type,
|
|
248
|
+
sort_order: field.sortOrder,
|
|
249
|
+
created_at: new Date(),
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/** `read` for a caller that is deciding rather than serving: absent is an answer. */
|
|
253
|
+
async findByKey(key, { executor = this.knex } = {}) {
|
|
254
|
+
const row = await executor(TABLE).where('key', key).first();
|
|
255
|
+
return row ? zod_1.z.decode(codec_1.customFieldCodec, row) : null;
|
|
256
|
+
}
|
|
257
|
+
/** The same entry `add` writes. Only the caller knows its transaction committed. */
|
|
258
|
+
async recordCreated(context, fields) {
|
|
259
|
+
for (const field of fields) {
|
|
198
260
|
await this.recordAction({
|
|
199
261
|
context,
|
|
200
262
|
verb: 'create',
|
|
@@ -202,7 +264,6 @@ class CustomFieldDefinitionsService {
|
|
|
202
264
|
details: { primary_name: field.name, key: field.key },
|
|
203
265
|
});
|
|
204
266
|
}
|
|
205
|
-
return created;
|
|
206
267
|
}
|
|
207
268
|
/**
|
|
208
269
|
* The operational ceiling on how many definitions a site can hold. This is a
|
|
@@ -460,6 +521,36 @@ class CustomFieldDefinitionsService {
|
|
|
460
521
|
}
|
|
461
522
|
}
|
|
462
523
|
exports.CustomFieldDefinitionsService = CustomFieldDefinitionsService;
|
|
524
|
+
/**
|
|
525
|
+
* The shape a stated key has to have. Minting derives one that is usable by
|
|
526
|
+
* construction, so this is the check that path never needed: a caller stating its own
|
|
527
|
+
* key has said nothing about the format, and guarding here covers every route in
|
|
528
|
+
* rather than whichever one arrived first.
|
|
529
|
+
*
|
|
530
|
+
* The length bound is the column's own, not `mintKey`'s: that one holds back room for a
|
|
531
|
+
* `_<n>` collision suffix, and a stated key is written exactly as given and never
|
|
532
|
+
* suffixed, so the whole column is available to it.
|
|
533
|
+
*/
|
|
534
|
+
function assertKeyUsable(key) {
|
|
535
|
+
if (!key_1.KEY_CHARACTERS.test(key)) {
|
|
536
|
+
throw new errors_1.default.ValidationError({
|
|
537
|
+
message: 'A custom field key can only contain lowercase letters, numbers and underscores.',
|
|
538
|
+
property: 'key',
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
if (key.length > MAX_KEY_LENGTH) {
|
|
542
|
+
throw new errors_1.default.ValidationError({
|
|
543
|
+
message: `A custom field key can be at most ${MAX_KEY_LENGTH} characters.`,
|
|
544
|
+
property: 'key',
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
if (RESERVED_KEYS.includes(key)) {
|
|
548
|
+
throw new errors_1.default.ValidationError({
|
|
549
|
+
message: `${key} cannot be used as a custom field key.`,
|
|
550
|
+
property: 'key',
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
}
|
|
463
554
|
// The field a zod issue points at. Create validates an array, so an issue's path
|
|
464
555
|
// is prefixed with the item's index (`[0, 'name']`); `property` names the field
|
|
465
556
|
// that is wrong, so the numeric prefix is dropped. Which item it was is reported
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.values = exports.definitions = void 0;
|
|
3
|
+
exports.bindings = exports.values = exports.definitions = exports.actingContext = void 0;
|
|
4
4
|
exports.init = init;
|
|
5
5
|
const definitions_service_1 = require("./definitions-service");
|
|
6
6
|
const values_service_1 = require("./values-service");
|
|
7
|
+
const bindings_service_1 = require("./bindings-service");
|
|
7
8
|
const actions_1 = require("./actions");
|
|
8
9
|
const config_1 = require("./config");
|
|
10
|
+
var actions_2 = require("./actions");
|
|
11
|
+
Object.defineProperty(exports, "actingContext", { enumerable: true, get: function () { return actions_2.actingContext; } });
|
|
9
12
|
function init() {
|
|
10
|
-
// The
|
|
11
|
-
//
|
|
12
|
-
if (exports.definitions && exports.values) {
|
|
13
|
+
// The three are constructed together below, so checking all of them keeps the "all or
|
|
14
|
+
// none" invariant explicit rather than trusting one to stand in for the rest.
|
|
15
|
+
if (exports.definitions && exports.values && exports.bindings) {
|
|
13
16
|
return;
|
|
14
17
|
}
|
|
15
18
|
const { knex } = require('../../data/db');
|
|
@@ -31,4 +34,8 @@ function init() {
|
|
|
31
34
|
knex,
|
|
32
35
|
getMaxDefinitions: () => (0, config_1.resolveMaxDefinitions)(config.get('members:customFields:maxDefinitions')),
|
|
33
36
|
});
|
|
37
|
+
// Built after the values, which is what a binding routes into. It has no handle on the
|
|
38
|
+
// definitions: making a field is not part of binding to one, so a caller that needs both
|
|
39
|
+
// asks for both.
|
|
40
|
+
exports.bindings = new bindings_service_1.CustomFieldBindingsService({ knex, values: exports.values });
|
|
34
41
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.activeFields = activeFields;
|
|
4
|
+
exports.fieldByKey = fieldByKey;
|
|
4
5
|
exports.inFieldOrder = inFieldOrder;
|
|
5
6
|
const schema_1 = require("./schema");
|
|
6
7
|
const FIELDS_TABLE = 'members_custom_fields';
|
|
@@ -11,6 +12,10 @@ const FIELDS_TABLE = 'members_custom_fields';
|
|
|
11
12
|
function activeFields(db) {
|
|
12
13
|
return db(FIELDS_TABLE).where('status', schema_1.FIELD_STATUS.active);
|
|
13
14
|
}
|
|
15
|
+
/** One field by key, as the same kind of query the rest of this reads through. */
|
|
16
|
+
function fieldByKey(db, key) {
|
|
17
|
+
return db(FIELDS_TABLE).where(`${FIELDS_TABLE}.key`, key);
|
|
18
|
+
}
|
|
14
19
|
/**
|
|
15
20
|
* The publisher's order, applied to every read of the list. Here for the same reason the
|
|
16
21
|
* status filter is: a read that forgets it comes back in whatever order the engine chose.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DbCustomFieldLeaf = exports.DbCustomFieldValue = exports.DbCustomField = exports.FieldStatusSchema = exports.FIELD_STATUS = void 0;
|
|
3
|
+
exports.DbBoundField = exports.DbCustomFieldBinding = exports.DbCustomFieldLeaf = exports.DbCustomFieldValue = exports.WrittenBy = exports.DbCustomField = exports.FieldStatusSchema = exports.FIELD_STATUS = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const custom_field_types_1 = require("@tryghost/custom-field-types");
|
|
6
|
-
const
|
|
6
|
+
const date_1 = require("../../lib/db-types/date");
|
|
7
7
|
// `archived` is soft: the field drops out of the values path but stays in the definition
|
|
8
8
|
// list so it can be renamed, restored or deleted. Mirrors schema.js's `isIn` on the
|
|
9
9
|
// column, which is static config and cannot import this.
|
|
@@ -17,9 +17,21 @@ exports.DbCustomField = zod_1.z.object({
|
|
|
17
17
|
name: zod_1.z.string(),
|
|
18
18
|
type: custom_field_types_1.FieldTypeSchema,
|
|
19
19
|
status: exports.FieldStatusSchema,
|
|
20
|
-
created_at:
|
|
21
|
-
updated_at:
|
|
20
|
+
created_at: date_1.DbDate,
|
|
21
|
+
updated_at: date_1.DbDate.nullable(),
|
|
22
22
|
});
|
|
23
|
+
/**
|
|
24
|
+
* How a value arrived, not who caused it: who edited a member's fields is already an
|
|
25
|
+
* action, and Stripe is not a person. `type` is the namespace that makes `id` resolvable —
|
|
26
|
+
* `users`, `integrations`, `members_custom_field_bindings` — so the one writer that
|
|
27
|
+
* resolves in no table is the one with no id to give.
|
|
28
|
+
*/
|
|
29
|
+
exports.WrittenBy = zod_1.z.discriminatedUnion('type', [
|
|
30
|
+
zod_1.z.object({ type: zod_1.z.literal('user'), id: zod_1.z.string() }),
|
|
31
|
+
zod_1.z.object({ type: zod_1.z.literal('integration'), id: zod_1.z.string() }),
|
|
32
|
+
zod_1.z.object({ type: zod_1.z.literal('binding'), id: zod_1.z.string() }),
|
|
33
|
+
zod_1.z.object({ type: zod_1.z.literal('import'), id: zod_1.z.null() }),
|
|
34
|
+
]);
|
|
23
35
|
// One part of a member's value. What a `path` means is storage.ts's business, so the row
|
|
24
36
|
// carries it as a plain string.
|
|
25
37
|
exports.DbCustomFieldValue = zod_1.z.object({
|
|
@@ -30,8 +42,13 @@ exports.DbCustomFieldValue = zod_1.z.object({
|
|
|
30
42
|
// Nullable like the column, though nothing here writes a null: a part with no value
|
|
31
43
|
// has no row.
|
|
32
44
|
value_text: zod_1.z.string().nullable(),
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
// Plain columns rather than the `WrittenBy` union: the rule holds at the write
|
|
46
|
+
// boundary, so one malformed row cannot throw away a member's whole profile on read.
|
|
47
|
+
written_by_type: zod_1.z.string(),
|
|
48
|
+
// Null for the one writer that resolves nowhere: an import, until runs are tracked.
|
|
49
|
+
written_by_id: zod_1.z.string().nullable(),
|
|
50
|
+
created_at: date_1.DbDate,
|
|
51
|
+
updated_at: date_1.DbDate.nullable(),
|
|
35
52
|
});
|
|
36
53
|
// The field's key travels with the row so a value assembles without a second lookup.
|
|
37
54
|
//
|
|
@@ -45,3 +62,17 @@ exports.DbCustomFieldLeaf = zod_1.z.object({
|
|
|
45
62
|
path: zod_1.z.string(),
|
|
46
63
|
value_text: zod_1.z.string(),
|
|
47
64
|
});
|
|
65
|
+
exports.DbCustomFieldBinding = zod_1.z.object({
|
|
66
|
+
id: zod_1.z.string(),
|
|
67
|
+
product_id: zod_1.z.string(),
|
|
68
|
+
port: zod_1.z.string(),
|
|
69
|
+
custom_field_key: zod_1.z.string(),
|
|
70
|
+
created_at: date_1.DbDate,
|
|
71
|
+
updated_at: date_1.DbDate.nullable(),
|
|
72
|
+
});
|
|
73
|
+
/** A binding joined to the field it points at, which is how a collected value is routed. */
|
|
74
|
+
exports.DbBoundField = zod_1.z.object({
|
|
75
|
+
binding_id: zod_1.z.string(),
|
|
76
|
+
key: zod_1.z.string(),
|
|
77
|
+
type: custom_field_types_1.FieldTypeSchema,
|
|
78
|
+
});
|
|
@@ -80,7 +80,12 @@ class CustomFieldValuesService {
|
|
|
80
80
|
leaves.push(schema_1.DbCustomFieldLeaf.parse(row));
|
|
81
81
|
}
|
|
82
82
|
catch (err) {
|
|
83
|
-
logging_1.default.warn(
|
|
83
|
+
logging_1.default.warn({
|
|
84
|
+
event: { name: 'members.custom_fields.value_unreadable' },
|
|
85
|
+
err,
|
|
86
|
+
customFieldKey: row.key,
|
|
87
|
+
path: row.path,
|
|
88
|
+
}, 'Skipping an unreadable custom field value');
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
return (0, storage_1.valuesFromLeaves)(leaves);
|
|
@@ -167,10 +172,13 @@ class CustomFieldValuesService {
|
|
|
167
172
|
* them, and saying nothing about a path leaves it alone. There is no whole-value
|
|
168
173
|
* replace, so a caller that does not know about a field cannot erase it.
|
|
169
174
|
*
|
|
175
|
+
* `writtenBy` is required and has no default: every writer has to name itself, so a new
|
|
176
|
+
* one cannot quietly inherit the identity of whichever was written first.
|
|
177
|
+
*
|
|
170
178
|
* Always transactional. Given an executor it joins that transaction, so the importer's
|
|
171
179
|
* failed value write takes its member with it; given none it opens its own.
|
|
172
180
|
*/
|
|
173
|
-
async applyWrite(memberId, writes, { executor = this.knex }
|
|
181
|
+
async applyWrite(memberId, writes, { writtenBy, executor = this.knex }) {
|
|
174
182
|
if (writes.length === 0) {
|
|
175
183
|
return;
|
|
176
184
|
}
|
|
@@ -197,6 +205,8 @@ class CustomFieldValuesService {
|
|
|
197
205
|
custom_field_key: field.key,
|
|
198
206
|
path: leaf.path,
|
|
199
207
|
value_text: leaf.value_text,
|
|
208
|
+
written_by_type: writtenBy.type,
|
|
209
|
+
written_by_id: writtenBy.id,
|
|
200
210
|
created_at: now,
|
|
201
211
|
updated_at: now,
|
|
202
212
|
})));
|
|
@@ -227,7 +237,9 @@ class CustomFieldValuesService {
|
|
|
227
237
|
// Naming the columns rather than giving values takes each from the row
|
|
228
238
|
// that lost the conflict, so every part updates to its own value.
|
|
229
239
|
.onConflict(['member_id', 'custom_field_key', 'path'])
|
|
230
|
-
|
|
240
|
+
// The writer is merged with the value, so a leaf names who wrote what
|
|
241
|
+
// it currently holds rather than who wrote its first value.
|
|
242
|
+
.merge(['value_text', 'written_by_type', 'written_by_id', 'updated_at']);
|
|
231
243
|
}
|
|
232
244
|
};
|
|
233
245
|
// knex's marker for a transactor: join it rather than nesting a savepoint under it.
|