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.
Files changed (399) hide show
  1. package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
  2. package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
  3. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  4. package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
  5. package/core/boot.js +13 -4
  6. package/core/built/admin/assets/{Combination-gnJO3vIw.js → Combination-5fYEzgbs.js} +1 -1
  7. package/core/built/admin/assets/{PolarAngleAxis-C4qtHy1B.js → PolarAngleAxis-pkMyqz8g.js} +1 -1
  8. package/core/built/admin/assets/{RadialBarChart-Bh09Stsj.js → RadialBarChart-JAKoS4KT.js} +1 -1
  9. package/core/built/admin/assets/{about-BgpmhCuM.js → about-Bve7IJS2.js} +1 -1
  10. package/core/built/admin/assets/{account-migration-8qTEI1i1.js → account-migration-DRhAehfw.js} +1 -1
  11. package/core/built/admin/assets/{action-list-lGzZLHc8.js → action-list-C4v0-du8.js} +1 -1
  12. package/core/built/admin/assets/activitypub/{account-migration-DMHuPnJn.js → account-migration-C-aej4x_.js} +7 -7
  13. package/core/built/admin/assets/activitypub/activitypub.js +3 -4
  14. package/core/built/admin/assets/activitypub/{avatar-DhTo5D1B.js → avatar-DLPL3Abs.js} +59 -68
  15. package/core/built/admin/assets/activitypub/{avatar-flipboard-DnVgbEfa.js → avatar-flipboard-C9iDY-QV.js} +2 -2
  16. package/core/built/admin/assets/activitypub/{bluesky-sharing-BT4zAlW7.js → bluesky-sharing-BXkA5mqV.js} +8 -8
  17. package/core/built/admin/assets/activitypub/{content-formatters-BeDZ-DIa.js → content-formatters-CHcyMFk4.js} +17 -17
  18. package/core/built/admin/assets/activitypub/{copy-8sqxUuNd.js → copy-DIAOQoCZ.js} +2 -2
  19. package/core/built/admin/assets/activitypub/{domain-xQDDu1CS.js → domain-B3ihkPde.js} +8 -8
  20. package/core/built/admin/assets/activitypub/{edit-profile-BXdF_r2G.js → edit-profile-DsZM3rTX.js} +5 -5
  21. package/core/built/admin/assets/activitypub/{explore-CMt7gKlL.js → explore-BodNrZgR.js} +8 -8
  22. package/core/built/admin/assets/activitypub/{feed-Bwqdddp_.js → feed-PwH1iJ84.js} +9 -9
  23. package/core/built/admin/assets/activitypub/{field-4co_8FVg.js → field-D06-kmOJ.js} +3 -3
  24. package/core/built/admin/assets/activitypub/{hash-DwakMs4X.js → hash-Bm3WxYN4.js} +2 -2
  25. package/core/built/admin/assets/activitypub/{inbox-DQ5CwLma.js → inbox-BluD2ucT.js} +16 -16
  26. package/core/built/admin/assets/activitypub/{inbox-ckD4wo_r.js → inbox-d8oJRTf4.js} +2 -2
  27. package/core/built/admin/assets/activitypub/{label-B72sfvEU.js → label-FHSh6ZAw.js} +3 -3
  28. package/core/built/admin/assets/activitypub/layout-Cq4NG0Xr.js +1 -0
  29. package/core/built/admin/assets/activitypub/{moderation-KCCO7L2J.js → moderation-D1Yapsod.js} +9 -9
  30. package/core/built/admin/assets/activitypub/{note-BX_Bz5A0.js → note-C5zjqq5C.js} +8 -8
  31. package/core/built/admin/assets/activitypub/{notifications-BQOYGvRv.js → notifications-B9p8eCHD.js} +9 -9
  32. package/core/built/admin/assets/activitypub/{preferences-6h43G9_q.js → preferences-BCqUdC3v.js} +9 -9
  33. package/core/built/admin/assets/activitypub/{profile-BMN9VVZ2.js → profile-BRCWoFem.js} +178 -178
  34. package/core/built/admin/assets/activitypub/{reply-ZNo04xsO.js → reply-DYK5vVqb.js} +2 -2
  35. package/core/built/admin/assets/activitypub/{routes-3B9mUQ7i.js → routes-BSXT992i.js} +81 -84
  36. package/core/built/admin/assets/activitypub/{separator-D9taVCCa.js → separator-BbQqTm-p.js} +3 -3
  37. package/core/built/admin/assets/activitypub/{settings-71gCm3SO.js → settings-DQDkr06X.js} +6 -6
  38. package/core/built/admin/assets/activitypub/{step-1-BsGGnBuT.js → step-1-B-YfsVeO.js} +5 -5
  39. package/core/built/admin/assets/activitypub/{step-2-teosIS0k.js → step-2-DtPQzlTH.js} +6 -6
  40. package/core/built/admin/assets/activitypub/{step-3-BjD5TokC.js → step-3-D6BFMXL_.js} +10 -10
  41. package/core/built/admin/assets/activitypub/{tabs-Cvwl1wXU.js → tabs-GpNecvfB.js} +6 -6
  42. package/core/built/admin/assets/activitypub/{topic-filter-C3LZJc2X.js → topic-filter-BPDeQQys.js} +3 -3
  43. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-Dp9f0gov.js → use-activity-pub-queries-BoVOxXkV.js} +2 -2
  44. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-C4RI0sa9.js → use-navigate-with-base-path-Bmk5h4lW.js} +220 -220
  45. package/core/built/admin/assets/activitypub/{use-reply-chain-data-C2oNDMUH.js → use-reply-chain-data-wVBX7swM.js} +5 -5
  46. package/core/built/admin/assets/activitypub/{x-Dxm6pV9X.js → x-DbQZOLiI.js} +2 -2
  47. package/core/built/admin/assets/{add-integration-modal--YpTq3c0.js → add-integration-modal-BC0jExDZ.js} +1 -1
  48. package/core/built/admin/assets/{add-newsletter-modal-C8Ix2hol.js → add-newsletter-modal-DchTkA7l.js} +1 -1
  49. package/core/built/admin/assets/{add-recommendation-modal-CScuNFz4.js → add-recommendation-modal-DMvaJZKp.js} +1 -1
  50. package/core/built/admin/assets/alert-dialog-QhXzdHfc.js +1 -0
  51. package/core/built/admin/assets/{analytics-Cnji45H5.js → analytics-No1DDY3A.js} +1 -1
  52. package/core/built/admin/assets/{announcement-bar-modal-BTHiy1ZO.js → announcement-bar-modal-DM3cYOpo.js} +1 -1
  53. package/core/built/admin/assets/{api-keys-Boy5pLbD.js → api-keys-BLm2NDBh.js} +1 -1
  54. package/core/built/admin/assets/audience-9mwU5TW6.js +1 -0
  55. package/core/built/admin/assets/{automations-BWpRCZ_f.js → automations-DpUNUdcZ.js} +1 -1
  56. package/core/built/admin/assets/{bluesky-sharing-DHOpQxff.js → bluesky-sharing-Cjrv_f62.js} +1 -1
  57. package/core/built/admin/assets/{box-By_EgGtm.js → box-CdfQAP_F.js} +1 -1
  58. package/core/built/admin/assets/{brand-icon-09YqFZjV.js → brand-icon-CrIGOA3Z.js} +1 -1
  59. package/core/built/admin/assets/{breadcrumb-CcFr_ltt.js → breadcrumb-DLiqCyFc.js} +1 -1
  60. package/core/built/admin/assets/{button-BshWPHvn.js → button-B2jcu6bk.js} +1 -1
  61. package/core/built/admin/assets/{card-CiiE7QfM.js → card--VNbfgo3.js} +1 -1
  62. package/core/built/admin/assets/{chart-BnXyfH11.js → chart-BrhA41Zi.js} +1 -1
  63. package/core/built/admin/assets/chart-helpers-Fo3bUL3K.js +1 -0
  64. package/core/built/admin/assets/{checkbox-Dwwr_3Py.js → checkbox-BfKktMph.js} +1 -1
  65. package/core/built/admin/assets/{chunk.524.91ecb33e6afc3bd8949b.js → chunk.524.60ca4692d91c6022042f.js} +4 -4
  66. package/core/built/admin/assets/{chunk.582.512549909741883f960c.js → chunk.582.525c7617c2d9e94c940a.js} +6 -6
  67. package/core/built/admin/assets/{chunk.16.f76a6314082d813d67e0.js → chunk.896.435fe0637944d4a69810.js} +3 -3
  68. package/core/built/admin/assets/{code-editor-view-BwIdPy_k.js → code-editor-view-CYVu4EW6.js} +1 -1
  69. package/core/built/admin/assets/{code-editor-view-CtkF82Fv.js → code-editor-view-DCQJxsfU.js} +1 -1
  70. package/core/built/admin/assets/{color-picker-Bmo1r9Fc.js → color-picker-BTY_NdEm.js} +1 -1
  71. package/core/built/admin/assets/{color-picker-field-DywowPhF.js → color-picker-field-CPlkzOH0.js} +1 -1
  72. package/core/built/admin/assets/{combobox-C4QCh6Yw.js → combobox-DrMtv_4P.js} +1 -1
  73. package/core/built/admin/assets/command-ZdgYJpoI.js +1 -0
  74. package/core/built/admin/assets/comments-kidj60-h.js +1 -0
  75. package/core/built/admin/assets/{confirmation-context-CLFHhyyH.js → confirmation-context-BhbmQQEl.js} +1 -1
  76. package/core/built/admin/assets/{container-LiZf3XdY.js → container-BuQG1wuP.js} +1 -1
  77. package/core/built/admin/assets/{content-api-modal-BtpNI92-.js → content-api-modal-CyQEC3fr.js} +1 -1
  78. package/core/built/admin/assets/{copy-field-CglgRZyG.js → copy-field-B3M1s78L.js} +1 -1
  79. package/core/built/admin/assets/{custom-field-type-option-D0PXoSnP.js → custom-field-type-option-CsGIZk1J.js} +1 -1
  80. package/core/built/admin/assets/{custom-integration-modal-DCIHKN33.js → custom-integration-modal-BY37O_9X.js} +1 -1
  81. package/core/built/admin/assets/{data-list-CupF7bjM.js → data-list-CA2jYGPq.js} +1 -1
  82. package/core/built/admin/assets/{date-range-select-JPwM0yUj.js → date-range-select-DD2RKkgB.js} +1 -1
  83. package/core/built/admin/assets/design-and-theme-modal-DUSKM4uC.js +22 -0
  84. package/core/built/admin/assets/{detail-page-D8lx2SdP.js → detail-page-Dnv-CdR1.js} +1 -1
  85. package/core/built/admin/assets/dialog-B44iRwlc.js +1 -0
  86. package/core/built/admin/assets/{dirty-confirm-dialog-CmARpZQS.js → dirty-confirm-dialog-BxgQgQ6H.js} +1 -1
  87. package/core/built/admin/assets/{disabled-sources-indicator-BTJ2ClQu.js → disabled-sources-indicator-Cvy47bE2.js} +1 -1
  88. package/core/built/admin/assets/{dist-DzcfoDJ3.js → dist-8YJUlf3B.js} +1 -1
  89. package/core/built/admin/assets/{dist-Cb5RSHSg.js → dist-B3keLvjj.js} +1 -1
  90. package/core/built/admin/assets/{dist-QLZuGq7o2.js → dist-Cy8tfrp_.js} +1 -1
  91. package/core/built/admin/assets/{dist-BT_Z-eCn.js → dist-Dgt2cr6a.js} +1 -1
  92. package/core/built/admin/assets/{domain-D0SAtc-T.js → domain-Ca6KhoQt.js} +1 -1
  93. package/core/built/admin/assets/{dropzone-CaPOeDRZ.js → dropzone-Bb-5zQTk.js} +1 -1
  94. package/core/built/admin/assets/edit-profile-BdupLlus.js +1 -0
  95. package/core/built/admin/assets/{editor-COXn4Atu.js → editor-BP883Lpn.js} +3 -3
  96. package/core/built/admin/assets/{embed-signup-form-modal-BFTPf04i.js → embed-signup-form-modal-DeBMLxlL.js} +1 -1
  97. package/core/built/admin/assets/{empty-indicator-WB1WgT9h.js → empty-indicator-D9QdpuNX.js} +1 -1
  98. package/core/built/admin/assets/{explore-BsNYrubV.js → explore-FB-CimXw.js} +1 -1
  99. package/core/built/admin/assets/{feed-8RR1O1bK.js → feed-C1GxsmI2.js} +1 -1
  100. package/core/built/admin/assets/{field-LmNk7wZh.js → field-Cj8lmDOo.js} +1 -1
  101. package/core/built/admin/assets/{filter-sources-4C0kF1NU.js → filter-sources-D5n5bFA2.js} +1 -1
  102. package/core/built/admin/assets/{filters-CV5jCb9n.js → filters-DJEzkMUK.js} +1 -1
  103. package/core/built/admin/assets/{filters-Dmr0PoqU.js → filters-MZXvdH5D.js} +1 -1
  104. package/core/built/admin/assets/{first-promoter-modal-OCzSaL3B.js → first-promoter-modal-CGTGLCr5.js} +1 -1
  105. package/core/built/admin/assets/{ghost-403cb39badad3df411fc0ba27d220047.js → ghost-3894eedcc6968f658578c0abfe942aab.js} +2 -2
  106. package/core/built/admin/assets/{gift-link-modal-0mzjn5oF.js → gift-link-modal-B6v0tnRN.js} +1 -1
  107. package/core/built/admin/assets/{grid-CUciBfjf.js → grid-Dj29PY05.js} +1 -1
  108. package/core/built/admin/assets/growth-BGAJD1rs.js +3 -0
  109. package/core/built/admin/assets/growth-D6mhcx3q.js +1 -0
  110. package/core/built/admin/assets/{heading-CRZZ2FUe.js → heading-Dh5SFVjL.js} +1 -1
  111. package/core/built/admin/assets/history-modal-iKwUY3XR.js +1 -0
  112. package/core/built/admin/assets/html-field-C8qVGGC1.js +1 -0
  113. package/core/built/admin/assets/{images-C0XvUYMb.js → images-h8VZEQ9k.js} +1 -1
  114. package/core/built/admin/assets/{inbox-DZXDUt4s.js → inbox-BYd1M06Q.js} +13 -13
  115. package/core/built/admin/assets/index-DjQe-e5s.js +4 -0
  116. package/core/built/admin/assets/{index.es-BMUCj9TR.js → index.es-VihPwfeH.js} +1 -1
  117. package/core/built/admin/assets/{inline-Cw-gigDW.js → inline-BWSs_VzR.js} +1 -1
  118. package/core/built/admin/assets/{input-UHrKuvBT.js → input--W-rCTrX.js} +1 -1
  119. package/core/built/admin/assets/{input-group-BPAxETpQ.js → input-group-D8sCXRF5.js} +1 -1
  120. package/core/built/admin/assets/{input-surface-BdOe4KzO.js → input-surface-BsrIZeSF.js} +1 -1
  121. package/core/built/admin/assets/{integration-header-B4DyXV06.js → integration-header-Bm6IDb1A.js} +1 -1
  122. package/core/built/admin/assets/{invite-user-modal-BrAkxEO3.js → invite-user-modal-MdImLCaJ.js} +1 -1
  123. package/core/built/admin/assets/{koenig-lexical-60O_8aiO.js → koenig-lexical-_-IsVI7E.js} +1 -1
  124. package/core/built/admin/assets/koenig-loader-DYZpm6El.js +2 -0
  125. package/core/built/admin/assets/{kpi-card-fUHZlzBX.js → kpi-card-DW_2y3ug.js} +1 -1
  126. package/core/built/admin/assets/kpi-card-DZQk_0W8.js +1 -0
  127. package/core/built/admin/assets/kpi-helpers-PueTKuA6.js +1 -0
  128. package/core/built/admin/assets/kpi-tabs-CojDs-Qz.js +1 -0
  129. package/core/built/admin/assets/{label-VIG969IC.js → label-DjbT91GM.js} +1 -1
  130. package/core/built/admin/assets/{label-picker-BBWykUeA.js → label-picker-cB51xl1r.js} +1 -1
  131. package/core/built/admin/assets/layout-c_B_1hax.js +1 -0
  132. package/core/built/admin/assets/{link-helpers-Dtq9fxQg.js → link-helpers-MVDdnFCY.js} +1 -1
  133. package/core/built/admin/assets/{list-page-CdsnQR9N.js → list-page-BucXJ0hi.js} +1 -1
  134. package/core/built/admin/assets/{loading-indicator-SFTqyYVE.js → loading-indicator-BpFWTVgh.js} +1 -1
  135. package/core/built/admin/assets/{member-custom-fields-gOv6Hoh3.js → member-custom-fields-qs0dIkxM.js} +1 -1
  136. package/core/built/admin/assets/member-detail-B6uec2a6.js +1 -0
  137. package/core/built/admin/assets/members-BQF3CqhI.js +2 -0
  138. package/core/built/admin/assets/{modal-page-BMTzFHVO.js → modal-page-xCivTMvI.js} +1 -1
  139. package/core/built/admin/assets/{moderation-DzzPLDyl.js → moderation-DY4wF1Q3.js} +1 -1
  140. package/core/built/admin/assets/{multi-select-combobox-CGohnsxJ.js → multi-select-combobox-B6LiRzDO.js} +1 -1
  141. package/core/built/admin/assets/navigation-modal-DX-gNF3X.js +1 -0
  142. package/core/built/admin/assets/newsletter-CyQA7m3m.js +1 -0
  143. package/core/built/admin/assets/{newsletter-detail-modal-DQU3r4g2.js → newsletter-detail-modal-BDrptuxn.js} +1 -1
  144. package/core/built/admin/assets/{newsletter-emails-D5ql1rud.js → newsletter-emails-CFeLlt4z.js} +1 -1
  145. package/core/built/admin/assets/newsletters-DXuNmC42.js +1 -0
  146. package/core/built/admin/assets/{note-i8k6pjaw.js → note-Cgo2LCJ6.js} +1 -1
  147. package/core/built/admin/assets/notifications-BC50AMku.js +1 -0
  148. package/core/built/admin/assets/{offers-container-modal-BWfjSdyg.js → offers-container-modal-DWycIMzT.js} +1 -1
  149. package/core/built/admin/assets/{onboarding-route-Cu_ROWPn.js → onboarding-route-Dmc4IPm3.js} +1 -1
  150. package/core/built/admin/assets/overview-CVbFtn-k.js +1 -0
  151. package/core/built/admin/assets/overview-YKj7SZaK.js +1 -0
  152. package/core/built/admin/assets/{page-header-Cfds8pCg.js → page-header-BR_nbIPp.js} +1 -1
  153. package/core/built/admin/assets/{pintura-modal-TDTrJ89x.js → pintura-modal-BR9hEvS8.js} +1 -1
  154. package/core/built/admin/assets/popover-CCy0h5rq.js +1 -0
  155. package/core/built/admin/assets/{portal-frame-DjBF-uy2.js → portal-frame-dc4XKr0e.js} +1 -1
  156. package/core/built/admin/assets/portal-modal-BvvdF_B9.js +1 -0
  157. package/core/built/admin/assets/{post-analytics-Buz1COoY.js → post-analytics-DX470WRG.js} +1 -1
  158. package/core/built/admin/assets/{post-analytics-header-B-P0eFnT.js → post-analytics-header-CXpJmdDv.js} +1 -1
  159. package/core/built/admin/assets/{post-analytics-provider-Cu3jNeFh.js → post-analytics-provider-CLfKGWZy.js} +1 -1
  160. package/core/built/admin/assets/{post-share-modal-P1_M6o-H.js → post-share-modal-Cl0NXRJr.js} +1 -1
  161. package/core/built/admin/assets/{preferences-Cq1aOiLy.js → preferences-DO0UUWFp.js} +2 -2
  162. package/core/built/admin/assets/{preview-chrome-BOVO6_PE.js → preview-chrome-BljUBlOk.js} +1 -1
  163. package/core/built/admin/assets/{preview-modal-MlTjP8UU.js → preview-modal-C-BL-F9k.js} +1 -1
  164. package/core/built/admin/assets/profile-CxT-0l4d.js +1 -0
  165. package/core/built/admin/assets/radio-group-Bgz60i81.js +1 -0
  166. package/core/built/admin/assets/{router-provider-CJC58zTy.js → router-provider-B0gZyiGJ.js} +1 -1
  167. package/core/built/admin/assets/{schemas-CRsC53ls.js → schemas-4UPic-oD.js} +2 -2
  168. package/core/built/admin/assets/select-DuDUFdPq.js +1 -0
  169. package/core/built/admin/assets/{settings-B5hJKZ5C.js → settings-BjCii7BM.js} +1 -1
  170. package/core/built/admin/assets/settings-b8kNzZSQ.js +4 -0
  171. package/core/built/admin/assets/{settings-breadcrumbs-sLDNedBW.js → settings-breadcrumbs-CyP_9zTo.js} +1 -1
  172. package/core/built/admin/assets/{shade-app-F7WxOyfk-nufqw1hd.js → shade-app-CcS3f8MZ-vwURazk8.js} +2 -2
  173. package/core/built/admin/assets/{share-modal-CLBfj377.js → share-modal-BV70mr9k.js} +1 -1
  174. package/core/built/admin/assets/{skeleton-D7hwjdry.js → skeleton-Ce9GgUpf.js} +1 -1
  175. package/core/built/admin/assets/{slack-modal-Bt9I_tEo.js → slack-modal-Be2_KK-z.js} +1 -1
  176. package/core/built/admin/assets/sort-button-Cc-Z96sA.js +1 -0
  177. package/core/built/admin/assets/{source-icon-BPsD5ees.js → source-icon-v6PUnmyM.js} +1 -1
  178. package/core/built/admin/assets/{stack-CIfOAAVf.js → stack-B2eszIiq.js} +1 -1
  179. package/core/built/admin/assets/{stats-B_YkF7bp.js → stats-C4reGh9O.js} +1 -1
  180. package/core/built/admin/assets/{stats-view-BOCp9RG8.js → stats-view-DP9pQ62k.js} +1 -1
  181. package/core/built/admin/assets/{step-1-CMta6YFO.js → step-1-DSRp2vBj.js} +1 -1
  182. package/core/built/admin/assets/{step-2-BG04nh5q.js → step-2-COqv2g0u.js} +1 -1
  183. package/core/built/admin/assets/{step-3-ZnMaVIPj.js → step-3-6W1NMVQc.js} +2 -2
  184. package/core/built/admin/assets/{stripe-button-DDoUKN5a.js → stripe-button-D2K42Uty.js} +1 -1
  185. package/core/built/admin/assets/{stripe-connect-modal-BeSukI8q.js → stripe-connect-modal-Z-UT_BGc.js} +1 -1
  186. package/core/built/admin/assets/{switch-C9djUIMO.js → switch-CI4gLWqb.js} +1 -1
  187. package/core/built/admin/assets/{table-CrqQtkR2.js → table-B2pIKjVh.js} +1 -1
  188. package/core/built/admin/assets/{tabs-CGisSbWq.js → tabs-SaW_UT-Q.js} +1 -1
  189. package/core/built/admin/assets/tag-detail-Dc0nTOtU.js +2 -0
  190. package/core/built/admin/assets/tags-BLaXBwnb.js +1 -0
  191. package/core/built/admin/assets/testimonials-modal-sFwRnNLh.js +1 -0
  192. package/core/built/admin/assets/{text-DU9Hv33_.js → text-BQDSDsKs.js} +1 -1
  193. package/core/built/admin/assets/{textarea-d9qEkMOP.js → textarea-DJ1Q5V39.js} +1 -1
  194. package/core/built/admin/assets/{tier-detail-modal-CxRwgTPR.js → tier-detail-modal-BCFpWwUS.js} +1 -1
  195. package/core/built/admin/assets/{toggle-group-CtKZURJd.js → toggle-group-EM9WpESu.js} +1 -1
  196. package/core/built/admin/assets/{topic-filter-D8JT8Tq1.js → topic-filter-DY4gNHn2.js} +1 -1
  197. package/core/built/admin/assets/{transistor-modal-6PUf0idx.js → transistor-modal-CpyPG-MH.js} +1 -1
  198. package/core/built/admin/assets/trend-badge-ByMkuAuH.js +1 -0
  199. package/core/built/admin/assets/{unsplash-modal-BPuDBPja.js → unsplash-modal-Cv2Q6GtY.js} +1 -1
  200. package/core/built/admin/assets/{use-analytics-data--opuzwcz.js → use-analytics-data-CHvjMYuT.js} +1 -1
  201. package/core/built/admin/assets/use-check-theme-limit-error-Qv4SVXqw.js +2 -0
  202. package/core/built/admin/assets/use-filter-params-CAvfDvf1.js +1 -0
  203. package/core/built/admin/assets/use-growth-stats-D6mZXGhK.js +1 -0
  204. package/core/built/admin/assets/{use-limiter-TDSNiHPB.js → use-limiter-cwJvsNBo.js} +1 -1
  205. package/core/built/admin/assets/{use-navigate-with-base-path-CK989MlC.js → use-navigate-with-base-path-BHPA228f.js} +1 -1
  206. package/core/built/admin/assets/{use-pintura-config-CnCGrDFk.js → use-pintura-config-CzTfnufz.js} +1 -1
  207. package/core/built/admin/assets/{use-pintura-editor-ntphvtUd.js → use-pintura-editor-BDBXWUYq.js} +1 -1
  208. package/core/built/admin/assets/{use-post-referrers-CbXLFIex.js → use-post-referrers-DbY-mzci.js} +1 -1
  209. package/core/built/admin/assets/{use-reply-chain-data-JYFKSO83.js → use-reply-chain-data-BeQwz8oF.js} +1 -1
  210. package/core/built/admin/assets/{use-router-history-entry-BwfQS2mq.js → use-router-history-entry-Bg6BhBQQ.js} +1 -1
  211. package/core/built/admin/assets/{use-setting-group-DQxV42-O.js → use-setting-group-VM7FQwMY.js} +1 -1
  212. package/core/built/admin/assets/{use-settings-navigation-BBzro2-V.js → use-settings-navigation-BbrSUVcf.js} +1 -1
  213. package/core/built/admin/assets/{use-simple-pagination-B2TdNX67.js → use-simple-pagination-Dum6Irbs.js} +1 -1
  214. package/core/built/admin/assets/{use-staff-users-QrR9voeC.js → use-staff-users-cZg4ugOF.js} +1 -1
  215. package/core/built/admin/assets/{use-tinybird-query-D2Aeoty5.js → use-tinybird-query-B1IMyAcv.js} +1 -1
  216. package/core/built/admin/assets/{use-tinybird-token-DBuwMmln.js → use-tinybird-token-Bow0Zwn8.js} +1 -1
  217. package/core/built/admin/assets/{use-unsaved-changes-guard-DpYJcj1d.js → use-unsaved-changes-guard-BAy0RANR.js} +1 -1
  218. package/core/built/admin/assets/{use-url-input-WnIqckzS.js → use-url-input-Df5QzNa7.js} +1 -1
  219. package/core/built/admin/assets/user-detail-modal-yipSoQfv.js +1 -0
  220. package/core/built/admin/assets/{virtual-list-D3MfPNOh.js → virtual-list-DEx8WgiO.js} +1 -1
  221. package/core/built/admin/assets/web-CKcXAu86.js +1 -0
  222. package/core/built/admin/assets/web-DR4TqM3E.js +2 -0
  223. package/core/built/admin/assets/{zapier-modal-BO6PS_Vd.js → zapier-modal-Cw3BTBUu.js} +1 -1
  224. package/core/built/admin/index.html +24 -25
  225. package/core/frontend/services/rendering/renderer.js +15 -0
  226. package/core/server/adapters/storage/LocalStorageBase.js +8 -5
  227. package/core/server/api/endpoints/db.js +19 -5
  228. package/core/server/api/endpoints/index.js +4 -0
  229. package/core/server/api/endpoints/member-custom-fields.js +4 -14
  230. package/core/server/api/endpoints/posts.js +1 -0
  231. package/core/server/api/endpoints/tiers-checkout-config.js +59 -0
  232. package/core/server/api/endpoints/utils/serializers/output/config.js +1 -0
  233. package/core/server/api/endpoints/utils/serializers/output/index.js +4 -0
  234. package/core/server/api/endpoints/utils/serializers/output/tiers-checkout-config.js +12 -0
  235. package/core/server/data/exporter/table-lists.js +3 -0
  236. package/core/server/data/importer/content-files.js +57 -0
  237. package/core/server/data/importer/handlers/image.js +2 -2
  238. package/core/server/data/importer/import-archive.js +131 -0
  239. package/core/server/data/importer/import-manager.js +18 -180
  240. package/core/server/data/importer/importers/content-file-importer.js +66 -4
  241. 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
  242. package/core/server/data/migrations/versions/6.61/2026-08-19-14-38-53-add-members-custom-field-bindings-table.js +26 -0
  243. package/core/server/data/migrations/versions/6.61/2026-08-19-14-48-06-add-tier-checkout-field-tables.js +35 -0
  244. package/core/server/data/schema/schema.js +90 -0
  245. package/core/server/data/seeders/importers/automation-action-revisions-importer.js +3 -3
  246. package/core/server/data/seeders/importers/automation-actions-importer.js +3 -3
  247. package/core/server/data/seeders/importers/automation-run-steps-importer.js +3 -3
  248. package/core/server/data/seeders/importers/automation-runs-importer.js +5 -5
  249. package/core/server/data/seeders/importers/automations-importer.js +3 -3
  250. package/core/server/data/seeders/importers/comment-reports-importer.js +1 -1
  251. package/core/server/data/seeders/importers/comments-importer.js +1 -1
  252. package/core/server/data/seeders/importers/email-batches-importer.js +1 -1
  253. package/core/server/data/seeders/importers/email-recipients-importer.js +1 -1
  254. package/core/server/data/seeders/importers/emails-importer.js +1 -1
  255. package/core/server/data/seeders/importers/labels-importer.js +1 -1
  256. package/core/server/data/seeders/importers/members-click-events-importer.js +1 -1
  257. package/core/server/data/seeders/importers/members-created-events-importer.js +1 -1
  258. package/core/server/data/seeders/importers/members-feedback-importer.js +1 -1
  259. package/core/server/data/seeders/importers/members-importer.js +1 -1
  260. package/core/server/data/seeders/importers/members-login-events-importer.js +1 -1
  261. package/core/server/data/seeders/importers/members-products-importer.js +1 -1
  262. package/core/server/data/seeders/importers/members-status-events-importer.js +1 -1
  263. package/core/server/data/seeders/importers/members-stripe-customers-importer.js +1 -1
  264. package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +1 -1
  265. package/core/server/data/seeders/importers/members-subscribe-events-importer.js +1 -1
  266. package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +1 -1
  267. package/core/server/data/seeders/importers/offer-redemptions-importer.js +1 -1
  268. package/core/server/data/seeders/importers/offers-importer.js +1 -1
  269. package/core/server/data/seeders/importers/posts-importer.js +1 -1
  270. package/core/server/data/seeders/importers/table-importer.js +2 -2
  271. package/core/server/data/seeders/importers/tags-importer.js +1 -1
  272. package/core/server/data/seeders/importers/users-importer.js +1 -1
  273. package/core/server/data/seeders/importers/web-mentions-importer.js +1 -1
  274. package/core/server/data/seeders/utils/random.js +3 -3
  275. package/core/server/ghost-server.js +3 -2
  276. package/core/server/lib/db-types/boolean.js +18 -0
  277. package/core/server/lib/promise-pool.js +31 -0
  278. package/core/server/services/automations/database-automations-repository.js +26 -26
  279. package/core/server/services/automations/poll.js +1 -0
  280. package/core/server/services/content-import/import/assets.js +74 -0
  281. package/core/server/services/content-import/import/importer.js +57 -14
  282. package/core/server/services/content-import/import/post-data.js +1 -0
  283. package/core/server/services/content-import/import/post-repository.js +78 -0
  284. package/core/server/services/content-import/import/relations.js +149 -0
  285. package/core/server/services/content-import/import/row.js +11 -0
  286. package/core/server/services/content-import/import/schema.js +29 -0
  287. package/core/server/services/content-import/import/source.js +125 -0
  288. package/core/server/services/content-import/index.js +6 -28
  289. package/core/server/services/email-analytics/email-analytics-service.js +8 -1
  290. package/core/server/services/email-analytics/lib/queries.js +7 -1
  291. package/core/server/services/gift-links/schema.js +3 -3
  292. package/core/server/services/gifts/CONTEXT.md +1 -1
  293. package/core/server/services/gifts/constants.js +1 -1
  294. package/core/server/services/gifts/gift-bookshelf-repository.js +2 -2
  295. package/core/server/services/gifts/gift-delivery-bookshelf-repository.js +18 -9
  296. package/core/server/services/gifts/gift-delivery-schema.js +5 -5
  297. package/core/server/services/gifts/gift-delivery-service.js +4 -0
  298. package/core/server/services/gifts/gift-schema.js +10 -10
  299. package/core/server/services/gifts/gift-service.js +4 -2
  300. package/core/server/services/jobs-service/register-job-handlers.js +5 -5
  301. package/core/server/services/lib/mailgun-client.js +44 -8
  302. package/core/server/services/media-inliner/external-media-inliner-job.js +12 -0
  303. package/core/server/services/media-inliner/external-media-inliner.js +103 -29
  304. package/core/server/services/media-inliner/service.js +13 -41
  305. package/core/server/services/media-inliner/types.js +2 -0
  306. package/core/server/services/members/import-export/export/exporter.js +4 -6
  307. package/core/server/services/members/import-export/import/importer.js +21 -5
  308. package/core/server/services/members/import-export/import/stripe-utils.js +6 -1
  309. package/core/server/services/members/import-export/index.js +6 -1
  310. package/core/server/services/members/members-api/members-api.js +5 -0
  311. package/core/server/services/members/members-api/services/member-bread-service.js +19 -1
  312. package/core/server/services/members/members-api/services/payments-service.js +47 -1
  313. package/core/server/services/members-custom-fields/actions.js +27 -1
  314. package/core/server/services/members-custom-fields/bindings-service.js +119 -0
  315. package/core/server/services/members-custom-fields/definitions-service.js +104 -13
  316. package/core/server/services/members-custom-fields/index.js +11 -4
  317. package/core/server/services/members-custom-fields/queries.js +5 -0
  318. package/core/server/services/members-custom-fields/schema.js +37 -6
  319. package/core/server/services/members-custom-fields/values-service.js +15 -3
  320. package/core/server/services/public-config/config.js +7 -0
  321. package/core/server/services/stripe/services/checkout/allowed-countries.js +267 -0
  322. package/core/server/services/stripe/services/checkout/completed-session.js +68 -0
  323. package/core/server/services/stripe/services/checkout/field-ports.js +34 -0
  324. package/core/server/services/stripe/services/checkout/session-options.js +97 -0
  325. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +49 -0
  326. package/core/server/services/stripe/stripe-api.js +29 -0
  327. package/core/server/services/stripe/stripe-service.js +7 -0
  328. package/core/server/services/tier-checkout-config/codec.js +95 -0
  329. package/core/server/services/tier-checkout-config/destinations.js +17 -0
  330. package/core/server/services/tier-checkout-config/index.js +26 -0
  331. package/core/server/services/tier-checkout-config/models.js +57 -0
  332. package/core/server/services/tier-checkout-config/queries.js +80 -0
  333. package/core/server/services/tier-checkout-config/schema.js +33 -0
  334. package/core/server/services/tier-checkout-config/serializers.js +122 -0
  335. package/core/server/services/tier-checkout-config/service.js +303 -0
  336. package/core/server/services/tiers/service.js +21 -0
  337. package/core/server/web/api/endpoints/admin/routes.js +24 -13
  338. package/core/server/web/api/middleware/upload.js +2 -2
  339. package/core/server/web/parent/app.js +5 -0
  340. package/core/server/web/parent/middleware/filter-query-parameters.js +94 -0
  341. package/core/server/web/parent/middleware/index.js +1 -0
  342. package/core/server/web/query-parameter-policy/index.js +9 -0
  343. package/core/server/web/query-parameter-policy/policy.json +58 -0
  344. package/core/server/web/query-parameter-policy/schema.js +38 -0
  345. package/core/shared/config/defaults.json +3 -0
  346. package/core/shared/config/env/config.testing-mysql.json +3 -0
  347. package/core/shared/config/env/config.testing.json +3 -0
  348. package/core/shared/config/overrides.json +4 -2
  349. package/core/shared/labs.js +5 -14
  350. package/package.json +12 -13
  351. package/pnpm-lock.yaml +44 -46
  352. package/pnpm-workspace.yaml +6 -6
  353. package/tsconfig.json +2 -3
  354. package/core/built/admin/assets/activitypub/layout-CXajhRsL.js +0 -1
  355. package/core/built/admin/assets/alert-dialog-wEbVxANM.js +0 -1
  356. package/core/built/admin/assets/app-utils-D2Wp7ZSS.js +0 -1
  357. package/core/built/admin/assets/audience-DTLMXAFH.js +0 -1
  358. package/core/built/admin/assets/chart-helpers-B3OqQ6Ez.js +0 -1
  359. package/core/built/admin/assets/command-DcLbSifC.js +0 -1
  360. package/core/built/admin/assets/comments-Bxy_3WyE.js +0 -1
  361. package/core/built/admin/assets/design-and-theme-modal-CZ-PkW7o.js +0 -23
  362. package/core/built/admin/assets/dialog-Db7c164G.js +0 -1
  363. package/core/built/admin/assets/edit-profile-By7v5XW5.js +0 -1
  364. package/core/built/admin/assets/growth-55vWlGT_.js +0 -1
  365. package/core/built/admin/assets/growth-DA5AluYw.js +0 -3
  366. package/core/built/admin/assets/history-modal-G1s5hHz7.js +0 -1
  367. package/core/built/admin/assets/html-field-BegxsWpw.js +0 -1
  368. package/core/built/admin/assets/index-CDP9tIOk.js +0 -4
  369. package/core/built/admin/assets/koenig-loader-DwVY_V-H.js +0 -1
  370. package/core/built/admin/assets/kpi-card-LERqWBoY.js +0 -1
  371. package/core/built/admin/assets/kpi-helpers-DB3ouhYF.js +0 -1
  372. package/core/built/admin/assets/kpi-tabs-BGvtMD8S.js +0 -1
  373. package/core/built/admin/assets/layout-Di5K7doM.js +0 -1
  374. package/core/built/admin/assets/member-detail-D7mZDDp3.js +0 -1
  375. package/core/built/admin/assets/member-route-0Aa52Ntz.js +0 -1
  376. package/core/built/admin/assets/members-DvZG9t69.js +0 -2
  377. package/core/built/admin/assets/navigation-modal-CI8Bx5vn.js +0 -1
  378. package/core/built/admin/assets/newsletter-Bg3cq5U-.js +0 -1
  379. package/core/built/admin/assets/newsletters-DMDfZbMS.js +0 -1
  380. package/core/built/admin/assets/notifications-psA_2Ph4.js +0 -1
  381. package/core/built/admin/assets/overview-C-6xOLaf.js +0 -1
  382. package/core/built/admin/assets/overview-DaLhpRrC.js +0 -1
  383. package/core/built/admin/assets/popover-CFgqFDvC.js +0 -1
  384. package/core/built/admin/assets/portal-modal-Cf0pBAk8.js +0 -1
  385. package/core/built/admin/assets/profile-D6dHYf2o.js +0 -1
  386. package/core/built/admin/assets/radio-group-CjtmsCPl.js +0 -1
  387. package/core/built/admin/assets/select-D_RQaXgt.js +0 -1
  388. package/core/built/admin/assets/settings-DIo_F-MF.js +0 -4
  389. package/core/built/admin/assets/sort-button-DMBXF7tP.js +0 -1
  390. package/core/built/admin/assets/tag-detail-2a3BfzTW.js +0 -2
  391. package/core/built/admin/assets/tags-Dp2_8UzL.js +0 -1
  392. package/core/built/admin/assets/testimonials-modal-C9nrypNo.js +0 -1
  393. package/core/built/admin/assets/use-check-theme-limit-error-C9-QhGdV.js +0 -1
  394. package/core/built/admin/assets/use-filter-params-CSpAvgD2.js +0 -1
  395. package/core/built/admin/assets/use-growth-stats-BOmoPDHJ.js +0 -1
  396. package/core/built/admin/assets/user-detail-modal-59mBJqxN.js +0 -1
  397. package/core/built/admin/assets/web-DUuX7nE2.js +0 -2
  398. package/core/built/admin/assets/web-N8ucs2aG.js +0 -1
  399. /package/core/server/lib/{db-date.js → db-types/date.js} +0 -0
@@ -13,7 +13,7 @@ const dequal_1 = require("dequal");
13
13
  const lexical_1 = __importDefault(require("../../lib/lexical"));
14
14
  const url_utils_1 = __importDefault(require("../../../shared/url-utils"));
15
15
  const constants_1 = require("../member-welcome-emails/constants");
16
- const db_date_1 = require("../../lib/db-date");
16
+ const date_1 = require("../../lib/db-types/date");
17
17
  const stale_lock_cutoff_1 = require("./stale-lock-cutoff");
18
18
  const HOUR_MS = 60 * 60 * 1000;
19
19
  const DEFAULT_WELCOME_EMAIL_AUTOMATIONS = [
@@ -93,7 +93,7 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier, })
93
93
  const updatedAutomation = await updateAutomation(trx, {
94
94
  ...automation,
95
95
  status: data.status,
96
- updated_at: (0, db_date_1.toDatabaseDate)(now),
96
+ updated_at: (0, date_1.toDatabaseDate)(now),
97
97
  });
98
98
  await replaceAutomationGraph(trx, updatedAutomation.id, data.actions, data.edges);
99
99
  if (updatedAutomation.status === 'inactive') {
@@ -130,7 +130,7 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier, })
130
130
  .update({
131
131
  email_sent_count: trx.raw('COALESCE(??, 0) + ?', ['email_sent_count', 1]),
132
132
  });
133
- const now = (0, db_date_1.toDatabaseDate)(new Date());
133
+ const now = (0, date_1.toDatabaseDate)(new Date());
134
134
  await trx('automated_email_recipients').insert({
135
135
  id: (0, bson_objectid_1.default)().toHexString(),
136
136
  member_id: options.memberId,
@@ -281,7 +281,7 @@ async function ensureDefaultAutomations(trx) {
281
281
  }
282
282
  }
283
283
  async function ensureAutomation(trx, defaults) {
284
- const now = (0, db_date_1.toDatabaseDate)(new Date());
284
+ const now = (0, date_1.toDatabaseDate)(new Date());
285
285
  const id = (0, bson_objectid_1.default)().toHexString();
286
286
  await trx('automations')
287
287
  .insert({
@@ -313,7 +313,7 @@ async function ensureWelcomeEmailAction(trx, automationId) {
313
313
  if (!email) {
314
314
  return;
315
315
  }
316
- const now = (0, db_date_1.toDatabaseDate)(new Date());
316
+ const now = (0, date_1.toDatabaseDate)(new Date());
317
317
  const actionId = (0, bson_objectid_1.default)().toHexString();
318
318
  await insertActions(trx, [
319
319
  {
@@ -347,7 +347,7 @@ async function trigger(trx, options) {
347
347
  return;
348
348
  }
349
349
  const now = new Date();
350
- const nowString = (0, db_date_1.toDatabaseDate)(now);
350
+ const nowString = (0, date_1.toDatabaseDate)(now);
351
351
  const readyAt = getReadyAtForAction(firstAction, now, fakeWaitHoursMultiplier);
352
352
  const run = {
353
353
  id: (0, bson_objectid_1.default)().toHexString(),
@@ -366,14 +366,14 @@ async function trigger(trx, options) {
366
366
  });
367
367
  }
368
368
  async function insertRunStep(trx, { automationRunId, automationActionRevisionId, now, readyAt, }) {
369
- const nowString = (0, db_date_1.toDatabaseDate)(now);
369
+ const nowString = (0, date_1.toDatabaseDate)(now);
370
370
  await trx('automation_run_steps').insert({
371
371
  id: (0, bson_objectid_1.default)().toHexString(),
372
372
  created_at: nowString,
373
373
  updated_at: nowString,
374
374
  automation_run_id: automationRunId,
375
375
  automation_action_revision_id: automationActionRevisionId,
376
- ready_at: (0, db_date_1.toDatabaseDate)(readyAt),
376
+ ready_at: (0, date_1.toDatabaseDate)(readyAt),
377
377
  });
378
378
  }
379
379
  async function fetchAndLockSteps(trx, limit) {
@@ -388,9 +388,9 @@ async function fetchAndLockSteps(trx, limit) {
388
388
  // 2. Try to lock those rows.
389
389
  // 3. Select any rows we successfully locked.
390
390
  const now = new Date();
391
- const nowString = (0, db_date_1.toDatabaseDate)(now);
391
+ const nowString = (0, date_1.toDatabaseDate)(now);
392
392
  const staleLockCutoff = (0, stale_lock_cutoff_1.getStaleLockCutoff)(now);
393
- const staleLockCutoffString = (0, db_date_1.toDatabaseDate)(staleLockCutoff);
393
+ const staleLockCutoffString = (0, date_1.toDatabaseDate)(staleLockCutoff);
394
394
  const lockId = node_crypto_1.default.randomUUID();
395
395
  // 1. Select up to `limit` candidate rows.
396
396
  const candidates = await trx('automation_run_steps')
@@ -444,17 +444,17 @@ async function findNextPendingReadyAt(trx, staleLockCutoff) {
444
444
  .select({ next_ready_at: 'ready_at' })
445
445
  .where('status', 'pending')
446
446
  .where((builder) => {
447
- builder.whereNull('locked_by').orWhere('locked_at', '<', (0, db_date_1.toDatabaseDate)(staleLockCutoff));
447
+ builder.whereNull('locked_by').orWhere('locked_at', '<', (0, date_1.toDatabaseDate)(staleLockCutoff));
448
448
  })
449
449
  .orderBy('ready_at')
450
450
  .first();
451
- return row?.next_ready_at ? (0, db_date_1.fromDatabaseDate)(row.next_ready_at) : null;
451
+ return row?.next_ready_at ? (0, date_1.fromDatabaseDate)(row.next_ready_at) : null;
452
452
  }
453
453
  function buildStepToRun(row) {
454
454
  const base = {
455
455
  id: row.id,
456
456
  step_attempts: row.step_attempts,
457
- ready_at: (0, db_date_1.fromDatabaseDate)(row.ready_at),
457
+ ready_at: (0, date_1.fromDatabaseDate)(row.ready_at),
458
458
  locked_by: row.locked_by,
459
459
  automation_run_id: row.automation_run_id,
460
460
  automation_id: row.automation_id,
@@ -544,7 +544,7 @@ async function findNextActionRevision(trx, sourceActionId) {
544
544
  return row ?? null;
545
545
  }
546
546
  async function markStepTerminal(trx, step, status) {
547
- const nowString = (0, db_date_1.toDatabaseDate)(new Date());
547
+ const nowString = (0, date_1.toDatabaseDate)(new Date());
548
548
  return await updateStep(trx, step, {
549
549
  status,
550
550
  finished_at: nowString,
@@ -556,12 +556,12 @@ async function retryStep(trx, step, retryAt) {
556
556
  await markStepTerminal(trx, step, 'automation disabled');
557
557
  return false;
558
558
  }
559
- const nowString = (0, db_date_1.toDatabaseDate)(new Date());
559
+ const nowString = (0, date_1.toDatabaseDate)(new Date());
560
560
  return await updateStep(trx, step, {
561
561
  status: 'pending',
562
562
  started_at: null,
563
563
  finished_at: null,
564
- ready_at: (0, db_date_1.toDatabaseDate)(retryAt),
564
+ ready_at: (0, date_1.toDatabaseDate)(retryAt),
565
565
  updated_at: nowString,
566
566
  });
567
567
  }
@@ -586,8 +586,8 @@ function getReadyAtForAction(action, now, fakeWaitHoursMultiplier) {
586
586
  }
587
587
  }
588
588
  async function cancelCancelablePendingStepsForAutomation(trx, automationId, now) {
589
- const nowString = (0, db_date_1.toDatabaseDate)(now);
590
- const staleLockCutoff = (0, db_date_1.toDatabaseDate)((0, stale_lock_cutoff_1.getStaleLockCutoff)(now));
589
+ const nowString = (0, date_1.toDatabaseDate)(now);
590
+ const staleLockCutoff = (0, date_1.toDatabaseDate)((0, stale_lock_cutoff_1.getStaleLockCutoff)(now));
591
591
  await trx('automation_run_steps')
592
592
  .update({
593
593
  status: 'automation disabled',
@@ -707,7 +707,7 @@ async function replaceAutomationGraph(trx, automationId, submittedActions, edges
707
707
  revision.action_id,
708
708
  revision,
709
709
  ]));
710
- const now = (0, db_date_1.toDatabaseDate)(new Date());
710
+ const now = (0, date_1.toDatabaseDate)(new Date());
711
711
  const actionsToInsert = [];
712
712
  const revisionsToInsert = [];
713
713
  for (const action of actions) {
@@ -884,14 +884,14 @@ async function insertActionRevisions(trx, revisions) {
884
884
  }
885
885
  function getNextRevisionCreatedAt(latestCreatedAt, requestedCreatedAt) {
886
886
  if (!latestCreatedAt) {
887
- return (0, db_date_1.toDatabaseDate)(requestedCreatedAt);
887
+ return (0, date_1.toDatabaseDate)(requestedCreatedAt);
888
888
  }
889
- const requestedTime = (0, db_date_1.fromDatabaseDate)(requestedCreatedAt).getTime();
890
- const latestTime = (0, db_date_1.fromDatabaseDate)(latestCreatedAt).getTime();
889
+ const requestedTime = (0, date_1.fromDatabaseDate)(requestedCreatedAt).getTime();
890
+ const latestTime = (0, date_1.fromDatabaseDate)(latestCreatedAt).getTime();
891
891
  if (requestedTime > latestTime) {
892
- return (0, db_date_1.toDatabaseDate)(requestedCreatedAt);
892
+ return (0, date_1.toDatabaseDate)(requestedCreatedAt);
893
893
  }
894
- return (0, db_date_1.toDatabaseDate)(new Date(latestTime + 1000));
894
+ return (0, date_1.toDatabaseDate)(new Date(latestTime + 1000));
895
895
  }
896
896
  function buildActionRevision(actionId, action, createdAt) {
897
897
  switch (action.type) {
@@ -970,7 +970,7 @@ function buildAutomationBrowseResult(automation) {
970
970
  ...buildAutomationSummary(automation),
971
971
  stats: {
972
972
  last_run_created_at: automation.last_run_created_at
973
- ? (0, db_date_1.fromDatabaseDate)(automation.last_run_created_at)
973
+ ? (0, date_1.fromDatabaseDate)(automation.last_run_created_at)
974
974
  : null,
975
975
  total_run_count: Number(automation.total_run_count ?? 0),
976
976
  in_progress_run_count: Number(automation.in_progress_run_count ?? 0),
@@ -978,7 +978,7 @@ function buildAutomationBrowseResult(automation) {
978
978
  };
979
979
  }
980
980
  function serializeDate(date) {
981
- const normalizedDate = (0, db_date_1.fromDatabaseDate)(date);
981
+ const normalizedDate = (0, date_1.fromDatabaseDate)(date);
982
982
  normalizedDate.setMilliseconds(0);
983
983
  return normalizedDate.toISOString();
984
984
  }
@@ -119,6 +119,7 @@ const processStep = async ({ automationsApi, memberWelcomeEmailService, schedule
119
119
  subject: step.email_subject,
120
120
  },
121
121
  member: {
122
+ // Note that we don't use `automation_run.member_email` here. That's only for the historical record, not for functionality.
122
123
  email: member.get('email'),
123
124
  name: member.get('name'),
124
125
  uuid: member.get('uuid'),
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PreparedAssetBatch = void 0;
4
+ exports.prepareAssetBatch = prepareAssetBatch;
5
+ exports.belongsToAssetDirectory = belongsToAssetDirectory;
6
+ const content_files_1 = require("../../../data/importer/content-files");
7
+ class PreparedAssetBatch {
8
+ groups;
9
+ constructor(groups) {
10
+ this.groups = groups;
11
+ }
12
+ get files() {
13
+ return this.groups.flatMap((group) => group.files);
14
+ }
15
+ async store() {
16
+ const results = await Promise.allSettled(this.groups.map((group) => group.importer.doImport(group.files)));
17
+ const failure = results.find((result) => result.status === 'rejected');
18
+ if (failure) {
19
+ const rollbackResults = await Promise.allSettled(results.flatMap((result, index) => result.status === 'fulfilled' ? [this.groups[index].importer.rollback(result.value)] : []));
20
+ const rollbackFailures = rollbackResults.flatMap((result) => result.status === 'rejected' ? [result.reason] : []);
21
+ if (rollbackFailures.length > 0) {
22
+ // AggregateError is the native error for preserving storage and rollback
23
+ // failures; unlike GhostError it takes an iterable before its options.
24
+ // eslint-disable-next-line ghost/ghost-custom/ghost-error-usage
25
+ throw new AggregateError([failure.reason, ...rollbackFailures], 'Asset storage failed and rollback was incomplete.', { cause: failure.reason });
26
+ }
27
+ throw failure.reason;
28
+ }
29
+ }
30
+ rewriteRows(rows) {
31
+ const importData = {
32
+ data: { data: { posts: rows, tags: [], users: [] } },
33
+ };
34
+ for (const group of this.groups) {
35
+ importData[group.type] = group.files;
36
+ group.importer.preProcess(importData);
37
+ }
38
+ }
39
+ }
40
+ exports.PreparedAssetBatch = PreparedAssetBatch;
41
+ async function prepareAssetBatch(archive, directory, baseDirectory, deps = {}) {
42
+ const handlers = deps.handlers ?? (0, content_files_1.createContentFileHandlers)();
43
+ const importers = deps.importers ?? (0, content_files_1.createContentFileImporters)();
44
+ const importerByType = new Map(importers.map((importer) => [importer.type, importer]));
45
+ const groups = await Promise.all(handlers.map(async (handler) => {
46
+ const files = archive
47
+ .getFiles(directory, handler.extensions)
48
+ .filter((file) => belongsToAssetDirectory(file.name, handler.type, baseDirectory));
49
+ if (files.length === 0) {
50
+ return;
51
+ }
52
+ const importer = importerByType.get(handler.type);
53
+ if (!importer) {
54
+ return;
55
+ }
56
+ return {
57
+ type: handler.type,
58
+ files: await handler.loadFile(files, baseDirectory),
59
+ importer,
60
+ };
61
+ }));
62
+ const presentGroups = groups.filter((group) => group !== undefined);
63
+ return presentGroups.length > 0 ? new PreparedAssetBatch(presentGroups) : undefined;
64
+ }
65
+ function belongsToAssetDirectory(fileName, type, baseDirectory) {
66
+ const parts = fileName.split('/').filter(Boolean);
67
+ if (baseDirectory && parts[0] === baseDirectory) {
68
+ parts.shift();
69
+ }
70
+ if (parts[0] === 'content') {
71
+ parts.shift();
72
+ }
73
+ return parts.length > 1 && parts[0] === type;
74
+ }
@@ -45,7 +45,7 @@ const messages = {
45
45
  unreadableFile: 'The file could not be parsed as a CSV file.',
46
46
  tooManyPosts: 'This file contains more than {max} posts. Imports are temporarily limited to {max} posts at a time — please split the file into smaller files and try again.',
47
47
  allWritesFailed: 'Content import failed to write all {count} attempted {postNoun}.',
48
- urlResolutionFailed: 'Content import could not resolve a URL for {count} created {postNoun}.',
48
+ urlResolutionFailed: 'Content import could not resolve a URL for {count} imported {postNoun}.',
49
49
  };
50
50
  function logLifecycle(message) {
51
51
  try {
@@ -64,6 +64,7 @@ function buildImportTagNames(runId, timezone, now) {
64
64
  }
65
65
  class ContentCSVImporter {
66
66
  _readRows;
67
+ _prepareSource;
67
68
  _posts;
68
69
  _getHtmlToLexical;
69
70
  _getMarkdownToHtml;
@@ -75,8 +76,9 @@ class ContentCSVImporter {
75
76
  _newRunId;
76
77
  _getTimezone;
77
78
  _now;
78
- constructor({ readRows, posts, getHtmlToLexical, getMarkdownToHtml, getCleanHTML, addJob, report, store, urlForPost, newRunId, getTimezone, now = () => new Date(), }) {
79
+ constructor({ readRows, prepareSource = async ({ filePath }) => ({ filePath, cleanup: async () => { } }), posts, getHtmlToLexical, getMarkdownToHtml, getCleanHTML, addJob, report, store, urlForPost, newRunId, getTimezone, now = () => new Date(), }) {
79
80
  this._readRows = readRows;
81
+ this._prepareSource = prepareSource;
80
82
  this._posts = posts;
81
83
  this._getHtmlToLexical = getHtmlToLexical;
82
84
  this._getMarkdownToHtml = getMarkdownToHtml;
@@ -90,11 +92,13 @@ class ContentCSVImporter {
90
92
  this._now = now;
91
93
  }
92
94
  async importCSV(request) {
95
+ const source = await this._prepareSource(request);
93
96
  let rows;
94
97
  try {
95
- rows = await this._readRows(request.filePath, request.mapping);
98
+ rows = await this._readRows(source.filePath, request.mapping);
96
99
  }
97
100
  catch (error) {
101
+ await this.cleanupSource(source.cleanup);
98
102
  throw new errors.ValidationError({
99
103
  message: tpl(messages.unreadableFile),
100
104
  err: error,
@@ -103,6 +107,7 @@ class ContentCSVImporter {
103
107
  // Temporary while import state is held in memory: the durable job
104
108
  // system milestone removes the cap.
105
109
  if (rows.length > MAX_POSTS) {
110
+ await this.cleanupSource(source.cleanup);
106
111
  throw new errors.ValidationError({
107
112
  message: tpl(messages.tooManyPosts, { max: MAX_POSTS }),
108
113
  });
@@ -111,26 +116,36 @@ class ContentCSVImporter {
111
116
  const importTagNames = buildImportTagNames(runId, this._getTimezone(), this._now());
112
117
  this._store.create(runId, rows.length);
113
118
  logLifecycle('queued');
114
- this._addJob({
115
- job: () => this.runImportJob(runId, importTagNames, rows),
116
- offloaded: false,
117
- name: 'content-import',
118
- });
119
+ try {
120
+ this._addJob({
121
+ job: () => this.runImportJob(runId, importTagNames, rows, source),
122
+ offloaded: false,
123
+ name: 'content-import',
124
+ });
125
+ }
126
+ catch (error) {
127
+ this._store.fail(runId, messageOf(error));
128
+ await this.cleanupSource(source.cleanup);
129
+ throw error;
130
+ }
119
131
  return { importId: runId, total: rows.length };
120
132
  }
121
133
  // Must resolve in every case: the job manager reads a rejected inline job as a
122
134
  // defect in the job itself, and there is no retry behind it.
123
- async runImportJob(runId, importTagNames, rows) {
135
+ async runImportJob(runId, importTagNames, rows, source) {
124
136
  const startedAt = Date.now();
125
137
  logLifecycle('started');
126
138
  let urlFailureCount = 0;
127
139
  let firstUrlFailure;
128
140
  let failed = false;
129
141
  try {
142
+ if (source.assets) {
143
+ await source.assets.store();
144
+ source.assets.rewriteRows(rows);
145
+ }
130
146
  const htmlToLexical = this._getHtmlToLexical();
131
147
  const markdownToHtml = this._getMarkdownToHtml();
132
148
  const cleanHTML = this._getCleanHTML();
133
- let attemptedWrites = 0;
134
149
  let successfulWrites = 0;
135
150
  let failedWrites = 0;
136
151
  let firstWriteFailure;
@@ -154,8 +169,9 @@ class ContentCSVImporter {
154
169
  // failure. Stop the run before misclassifying it as a lost write.
155
170
  throw error;
156
171
  }
157
- attemptedWrites += 1;
158
172
  let post;
173
+ let writeStatus;
174
+ let warnings;
159
175
  try {
160
176
  // options.importing preserves the supplied timestamps and keeps the import silent:
161
177
  // the webhook, Slack, IndexNow and mention consumers all stand down on it, and a
@@ -163,10 +179,27 @@ class ContentCSVImporter {
163
179
  // it, one reason status is never 'scheduled'). Pinned by
164
180
  // test/e2e-webhooks/posts-importer.test.js. A fresh options object per row: the
165
181
  // model layer mutates it.
166
- post = await this._posts.create(data, {
182
+ const result = await this._posts.write(data, {
167
183
  importing: true,
168
184
  context: { internal: true },
185
+ }, {
186
+ sourceUpdatedAt: row.updated_at,
187
+ authorNames: row.authors,
188
+ authorEmails: row.author_emails,
189
+ tagNames: row.tags,
169
190
  });
191
+ if (result.status === 'skipped') {
192
+ this._store.record(runId, {
193
+ line,
194
+ title: row.title,
195
+ status: 'skipped',
196
+ reason: result.reason,
197
+ });
198
+ continue;
199
+ }
200
+ post = result.post;
201
+ writeStatus = result.status;
202
+ warnings = result.warnings;
170
203
  successfulWrites += 1;
171
204
  }
172
205
  catch (error) {
@@ -185,8 +218,9 @@ class ContentCSVImporter {
185
218
  const outcome = {
186
219
  line,
187
220
  title: row.title,
188
- status: 'created',
221
+ status: writeStatus,
189
222
  postId: post.id,
223
+ ...(warnings.length > 0 ? { warnings } : {}),
190
224
  };
191
225
  try {
192
226
  outcome.url = this._urlForPost(post);
@@ -199,7 +233,7 @@ class ContentCSVImporter {
199
233
  }
200
234
  this._store.record(runId, outcome);
201
235
  }
202
- if (attemptedWrites > 0 && successfulWrites === 0 && failedWrites === attemptedWrites) {
236
+ if (failedWrites > 0 && successfulWrites === 0) {
203
237
  this._report(new errors.InternalServerError({
204
238
  message: tpl(messages.allWritesFailed, {
205
239
  count: failedWrites,
@@ -218,6 +252,7 @@ class ContentCSVImporter {
218
252
  this._store.fail(runId, messageOf(error));
219
253
  }
220
254
  finally {
255
+ await this.cleanupSource(source.cleanup);
221
256
  const outcome = failed ? 'failed after' : 'completed in';
222
257
  logLifecycle(`${outcome} ${Date.now() - startedAt}ms`);
223
258
  }
@@ -233,6 +268,14 @@ class ContentCSVImporter {
233
268
  }));
234
269
  }
235
270
  }
271
+ async cleanupSource(cleanup) {
272
+ try {
273
+ await cleanup();
274
+ }
275
+ catch (error) {
276
+ this._report(error);
277
+ }
278
+ }
236
279
  }
237
280
  function messageOf(error) {
238
281
  if (error &&
@@ -14,6 +14,7 @@ class RowSkipped extends Error {
14
14
  }
15
15
  exports.RowSkipped = RowSkipped;
16
16
  const DIRECT_OPTIONAL_FIELDS = [
17
+ 'comment_id',
17
18
  'custom_excerpt',
18
19
  'feature_image',
19
20
  'canonical_url',
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BookshelfPostsRepository = void 0;
4
+ const relations_1 = require("./relations");
5
+ class BookshelfPostsRepository {
6
+ _models;
7
+ _relations;
8
+ constructor(models, relations = new relations_1.BookshelfPostRelationsResolver(models)) {
9
+ this._models = models;
10
+ this._relations = relations;
11
+ }
12
+ write(data, options, metadata = {}) {
13
+ return this._models.Base.transaction(async (transacting) => {
14
+ const writeOptions = { ...options, transacting };
15
+ const lookupOptions = { ...writeOptions, forUpdate: true };
16
+ let existingMatch;
17
+ if (data.comment_id) {
18
+ const existing = await this._models.Post.findOne({ comment_id: data.comment_id, status: 'all' }, lookupOptions);
19
+ if (existing) {
20
+ existingMatch = {
21
+ post: existing,
22
+ duplicateReason: `A post with the source ID "${data.comment_id}" already exists.`,
23
+ };
24
+ }
25
+ }
26
+ if (!existingMatch) {
27
+ const existing = await this._models.Post.findOne({ slug: data.slug, status: 'all' }, lookupOptions);
28
+ if (existing) {
29
+ existingMatch = {
30
+ post: existing,
31
+ duplicateReason: `A post with the slug "${data.slug}" already exists.`,
32
+ };
33
+ }
34
+ }
35
+ if (existingMatch) {
36
+ const { post: existing, duplicateReason } = existingMatch;
37
+ if (!metadata.sourceUpdatedAt) {
38
+ return { status: 'skipped', reason: duplicateReason };
39
+ }
40
+ const incomingInstant = new Date(metadata.sourceUpdatedAt).getTime();
41
+ const storedUpdatedAt = existing.toJSON().updated_at;
42
+ const storedInstant = storedUpdatedAt
43
+ ? new Date(storedUpdatedAt).getTime()
44
+ : undefined;
45
+ if (Number.isNaN(incomingInstant) ||
46
+ (storedInstant !== undefined && incomingInstant <= storedInstant)) {
47
+ return {
48
+ status: 'skipped',
49
+ reason: 'The existing post is newer than or as recent as the imported row.',
50
+ };
51
+ }
52
+ // Ghost's collision plugin treats updated_at as the client's version token.
53
+ // First update the content against the locked server version, then persist
54
+ // the incoming source timestamp on its own. The second edit is safe because
55
+ // timestamp-only importing edits are excluded from collision detection.
56
+ const resolved = await this._relations.resolve(data, metadata, writeOptions);
57
+ const collisionSafeData = { ...resolved.data };
58
+ if (storedUpdatedAt) {
59
+ collisionSafeData.updated_at = storedUpdatedAt;
60
+ }
61
+ else {
62
+ delete collisionSafeData.updated_at;
63
+ }
64
+ const editOptions = {
65
+ ...writeOptions,
66
+ id: existing.id,
67
+ };
68
+ await this._models.Post.edit(collisionSafeData, { ...editOptions });
69
+ const post = await this._models.Post.edit({ updated_at: metadata.sourceUpdatedAt }, { ...editOptions });
70
+ return { status: 'updated', post, warnings: resolved.warnings };
71
+ }
72
+ const resolved = await this._relations.resolve(data, metadata, writeOptions);
73
+ const post = await this._models.Post.add(resolved.data, writeOptions);
74
+ return { status: 'created', post, warnings: resolved.warnings };
75
+ });
76
+ }
77
+ }
78
+ exports.BookshelfPostsRepository = BookshelfPostsRepository;
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BookshelfPostRelationsResolver = void 0;
4
+ exports.parseAuthorReferences = parseAuthorReferences;
5
+ exports.parseTagReferences = parseTagReferences;
6
+ const { slugify } = require('@tryghost/string');
7
+ const validator = require('@tryghost/validator');
8
+ function parseAuthorReferences(authorNames, authorEmails) {
9
+ const names = splitList(authorNames);
10
+ const emails = splitList(authorEmails);
11
+ return Array.from({ length: Math.max(names.length, emails.length) }, (_, index) => ({
12
+ ...(names[index] ? { name: names[index] } : {}),
13
+ ...(emails[index] ? { email: emails[index] } : {}),
14
+ }));
15
+ }
16
+ function parseTagReferences(tagNames) {
17
+ return splitList(tagNames).filter((tag) => Boolean(tag));
18
+ }
19
+ class BookshelfPostRelationsResolver {
20
+ _models;
21
+ constructor(models) {
22
+ this._models = models;
23
+ }
24
+ async resolve(data, source, options) {
25
+ const { authors, warnings } = await this.resolveAuthors(source, options);
26
+ const tags = await this.resolveTags(source, options);
27
+ const resolved = {
28
+ ...data,
29
+ tags: [...tags, ...data.tags],
30
+ };
31
+ if (authors.length > 0) {
32
+ resolved.authors = authors;
33
+ }
34
+ return { data: resolved, warnings };
35
+ }
36
+ async resolveAuthors(source, options) {
37
+ const authors = [];
38
+ const warnings = [];
39
+ const seen = new Set();
40
+ const authorsByEmail = new Map();
41
+ let owner;
42
+ const useOwner = async (warning) => {
43
+ owner ??= await this._models.User.getOwnerUser({ ...options });
44
+ warnings.push(warning);
45
+ if (!seen.has(owner.id)) {
46
+ seen.add(owner.id);
47
+ authors.push({ id: owner.id });
48
+ }
49
+ };
50
+ for (const reference of parseAuthorReferences(source.authorNames, source.authorEmails)) {
51
+ let author = null;
52
+ if (reference.email) {
53
+ if (!validator.isEmail(reference.email)) {
54
+ await useOwner(`Author email "${reference.email}" is invalid; assigned Owner instead.`);
55
+ continue;
56
+ }
57
+ const emailKey = reference.email.toLowerCase();
58
+ author = authorsByEmail.get(emailKey) ?? null;
59
+ if (!author) {
60
+ author = (await this._models.User.getByEmail(emailKey, { ...options })) ?? null;
61
+ }
62
+ if (!author && reference.name) {
63
+ author = await this._models.User.add({
64
+ name: reference.name,
65
+ email: emailKey,
66
+ roles: ['Contributor'],
67
+ }, { ...options });
68
+ }
69
+ if (!author) {
70
+ await useOwner(`Author email "${reference.email}" has no name; assigned Owner instead.`);
71
+ continue;
72
+ }
73
+ authorsByEmail.set(emailKey, author);
74
+ }
75
+ else if (reference.name) {
76
+ author = await this._models.User.findOne({ slug: slugify(reference.name) }, { ...options });
77
+ if (!author) {
78
+ await useOwner(`Author "${reference.name}" has no email; assigned Owner instead.`);
79
+ continue;
80
+ }
81
+ }
82
+ else {
83
+ await useOwner('An empty author entry was assigned to Owner instead.');
84
+ continue;
85
+ }
86
+ if (author && !seen.has(author.id)) {
87
+ seen.add(author.id);
88
+ authors.push({ id: author.id });
89
+ }
90
+ }
91
+ return { authors, warnings };
92
+ }
93
+ async resolveTags(source, options) {
94
+ const tags = [];
95
+ const seen = new Set();
96
+ for (const reference of parseTagReferences(source.tagNames)) {
97
+ const normalizedSlug = slugify(reference);
98
+ const lookups = [{ name: reference }, { slug: reference }];
99
+ if (normalizedSlug && normalizedSlug !== reference) {
100
+ lookups.push({ slug: normalizedSlug });
101
+ }
102
+ const findTag = async (lookupOptions = {}) => {
103
+ for (const lookup of lookups) {
104
+ const tag = await this._models.Tag.findOne(lookup, {
105
+ ...options,
106
+ ...lookupOptions,
107
+ });
108
+ if (tag) {
109
+ return tag;
110
+ }
111
+ }
112
+ return null;
113
+ };
114
+ let tag = await findTag();
115
+ if (!tag) {
116
+ try {
117
+ tag = await this._models.Tag.add({ name: reference }, { ...options });
118
+ }
119
+ catch (error) {
120
+ if (!isUniqueConstraintError(error)) {
121
+ throw error;
122
+ }
123
+ // A concurrent row or import may have created the same slug after our
124
+ // lookup. A locking read sees that committed row under MySQL's default
125
+ // repeatable-read isolation, where another ordinary select may not.
126
+ tag = await findTag({ forUpdate: true });
127
+ if (!tag) {
128
+ throw error;
129
+ }
130
+ }
131
+ }
132
+ if (!seen.has(tag.id)) {
133
+ seen.add(tag.id);
134
+ tags.push({ id: tag.id });
135
+ }
136
+ }
137
+ return tags;
138
+ }
139
+ }
140
+ exports.BookshelfPostRelationsResolver = BookshelfPostRelationsResolver;
141
+ function splitList(value) {
142
+ return value?.split(',').map((part) => part.trim() || undefined) ?? [];
143
+ }
144
+ function isUniqueConstraintError(error) {
145
+ const code = typeof error === 'object' && error !== null && 'code' in error
146
+ ? error.code
147
+ : undefined;
148
+ return (code === 'ER_DUP_ENTRY' || (typeof code === 'string' && code.startsWith('SQLITE_CONSTRAINT')));
149
+ }