ghost 6.60.0 → 6.62.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 (613) hide show
  1. package/components/ghost-storage-base-3.0.0.tgz +0 -0
  2. package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
  3. package/components/tryghost-adapter-base-jobs-0.0.0.tgz +0 -0
  4. package/components/tryghost-adapter-base-redirects-0.0.0.tgz +0 -0
  5. package/components/tryghost-adapter-base-route-settings-0.0.0.tgz +0 -0
  6. package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
  7. package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
  8. package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
  9. package/components/tryghost-checkout-0.0.0.tgz +0 -0
  10. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  11. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  12. package/components/tryghost-kg-card-factory-5.2.4.tgz +0 -0
  13. package/components/tryghost-kg-clean-basic-html-4.3.4.tgz +0 -0
  14. package/components/tryghost-kg-converters-1.2.5.tgz +0 -0
  15. package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
  16. package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
  17. package/components/tryghost-kg-default-transforms-1.3.4.tgz +0 -0
  18. package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
  19. package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
  20. package/components/tryghost-kg-markdown-html-renderer-7.2.4.tgz +0 -0
  21. package/components/tryghost-kg-utils-1.1.4.tgz +0 -0
  22. package/components/tryghost-nql-string-0.0.0.tgz +0 -0
  23. package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
  24. package/content/settings/README.md +1 -1
  25. package/content/themes/casper/.gitignore +28 -0
  26. package/content/themes/casper/assets/built/casper.js +1 -1
  27. package/content/themes/casper/assets/built/screen.css +1 -1
  28. package/content/themes/casper/assets/css/screen.css +2 -1
  29. package/content/themes/casper/assets/js/lightbox.js +63 -46
  30. package/content/themes/casper/package.json +6 -6
  31. package/content/themes/casper/page.hbs +1 -0
  32. package/content/themes/casper/post.hbs +1 -0
  33. package/content/themes/source/.gitignore +28 -0
  34. package/content/themes/source/assets/built/screen.css +1 -1
  35. package/content/themes/source/assets/built/source.js +1 -1
  36. package/content/themes/source/assets/css/screen.css +2 -1
  37. package/content/themes/source/assets/js/lightbox.js +62 -45
  38. package/content/themes/source/assets/js/main.js +2 -2
  39. package/content/themes/source/package.json +4 -4
  40. package/content/themes/source/partials/feature-image.hbs +1 -0
  41. package/core/boot.js +62 -21
  42. package/core/built/admin/assets/Combination-B0l4MKVh.js +41 -0
  43. package/core/built/admin/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
  44. package/core/built/admin/assets/InterVariable-Italic-FCBEiFp6.woff2 +0 -0
  45. package/core/built/admin/assets/{PolarAngleAxis-C4qtHy1B.js → PolarAngleAxis-pkMyqz8g.js} +1 -1
  46. package/core/built/admin/assets/{RadialBarChart-Bh09Stsj.js → RadialBarChart-JAKoS4KT.js} +1 -1
  47. package/core/built/admin/assets/{about-BgpmhCuM.js → about-Dyae_UT6.js} +1 -1
  48. package/core/built/admin/assets/account-migration-CESa0mnX.js +1 -0
  49. package/core/built/admin/assets/{action-list-lGzZLHc8.js → action-list-C4v0-du8.js} +1 -1
  50. package/core/built/admin/assets/activitypub/{account-migration-DMHuPnJn.js → account-migration-By69CgCp.js} +16 -16
  51. package/core/built/admin/assets/activitypub/activitypub.js +9 -10
  52. package/core/built/admin/assets/activitypub/{avatar-DhTo5D1B.js → avatar-DLPL3Abs.js} +59 -68
  53. package/core/built/admin/assets/activitypub/{avatar-flipboard-DnVgbEfa.js → avatar-flipboard-C9iDY-QV.js} +2 -2
  54. package/core/built/admin/assets/activitypub/{bluesky-sharing-BT4zAlW7.js → bluesky-sharing-BJcPMrDd.js} +37 -37
  55. package/core/built/admin/assets/activitypub/{content-formatters-BeDZ-DIa.js → content-formatters-3rTHg3mp.js} +18 -18
  56. package/core/built/admin/assets/activitypub/{copy-8sqxUuNd.js → copy-DIAOQoCZ.js} +2 -2
  57. package/core/built/admin/assets/activitypub/{domain-xQDDu1CS.js → domain-DUR4xSkV.js} +121 -121
  58. package/core/built/admin/assets/activitypub/{edit-profile-BXdF_r2G.js → edit-profile-BqtfzxCp.js} +40 -40
  59. package/core/built/admin/assets/activitypub/{explore-CMt7gKlL.js → explore-BxuJd-J4.js} +27 -27
  60. package/core/built/admin/assets/activitypub/{feed-Bwqdddp_.js → feed-BM1TcksA.js} +51 -51
  61. package/core/built/admin/assets/activitypub/{field-4co_8FVg.js → field-Dn7HHx2-.js} +3 -3
  62. package/core/built/admin/assets/activitypub/{hash-DwakMs4X.js → hash-Bm3WxYN4.js} +2 -2
  63. package/core/built/admin/assets/activitypub/inbox-CCjkuow2.js +1284 -0
  64. package/core/built/admin/assets/activitypub/{inbox-ckD4wo_r.js → inbox-d8oJRTf4.js} +2 -2
  65. package/core/built/admin/assets/activitypub/label-1AA_s9Fa.js +16 -0
  66. package/core/built/admin/assets/activitypub/layout-2-0bw6HN.js +1 -0
  67. package/core/built/admin/assets/activitypub/{moderation-KCCO7L2J.js → moderation-CnmxEB8w.js} +91 -91
  68. package/core/built/admin/assets/activitypub/{note-BX_Bz5A0.js → note-ZKc_Bnba.js} +24 -24
  69. package/core/built/admin/assets/activitypub/{notifications-BQOYGvRv.js → notifications-CB2tJZau.js} +51 -51
  70. package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-BsJ9E5qf.js} +2 -2
  71. package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-CSUJJIlh.js} +2 -2
  72. package/core/built/admin/assets/activitypub/{preferences-6h43G9_q.js → preferences-0-JZnUkI.js} +1519 -1519
  73. package/core/built/admin/assets/activitypub/{profile-BMN9VVZ2.js → profile-C35cFIhM.js} +256 -256
  74. package/core/built/admin/assets/activitypub/{reply-ZNo04xsO.js → reply-DYK5vVqb.js} +2 -2
  75. package/core/built/admin/assets/activitypub/{routes-3B9mUQ7i.js → routes-BD4vscyc.js} +796 -790
  76. package/core/built/admin/assets/activitypub/{separator-D9taVCCa.js → separator-BbQqTm-p.js} +3 -3
  77. package/core/built/admin/assets/activitypub/settings-BsMROdqh.js +315 -0
  78. package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-O0RL9YCN.js} +2 -2
  79. package/core/built/admin/assets/activitypub/{step-1-BsGGnBuT.js → step-1-BMSx7c_X.js} +6 -6
  80. package/core/built/admin/assets/activitypub/{step-2-teosIS0k.js → step-2-DtPQzlTH.js} +6 -6
  81. package/core/built/admin/assets/activitypub/{step-3-BjD5TokC.js → step-3-CLlOZTyt.js} +11 -11
  82. package/core/built/admin/assets/activitypub/{tabs-Cvwl1wXU.js → tabs-Dxk-b9M-.js} +306 -306
  83. package/core/built/admin/assets/activitypub/{topic-filter-C3LZJc2X.js → topic-filter-5yZH6tId.js} +3 -3
  84. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-Dp9f0gov.js → use-activity-pub-queries-CV50qe03.js} +3 -3
  85. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-C4RI0sa9.js → use-navigate-with-base-path-Bmk5h4lW.js} +220 -220
  86. package/core/built/admin/assets/activitypub/{use-reply-chain-data-C2oNDMUH.js → use-reply-chain-data-Cbvzgjzd.js} +30 -30
  87. package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-BjcoP_HC.js} +7 -5
  88. package/core/built/admin/assets/activitypub/{x-Dxm6pV9X.js → x-DbQZOLiI.js} +2 -2
  89. package/core/built/admin/assets/add-integration-modal-BlF6rs_f.js +1 -0
  90. package/core/built/admin/assets/add-newsletter-modal-CglVQqah.js +1 -0
  91. package/core/built/admin/assets/add-recommendation-modal-wz7BsuaG.js +1 -0
  92. package/core/built/admin/assets/analytics-C4HE1gBg.js +1 -0
  93. package/core/built/admin/assets/{announcement-bar-modal-BTHiy1ZO.js → announcement-bar-modal-Ci4zz8jO.js} +1 -1
  94. package/core/built/admin/assets/{api-keys-Boy5pLbD.js → api-keys-Ck-Yteiv.js} +1 -1
  95. package/core/built/admin/assets/audience-CtbA54Sn.js +1 -0
  96. package/core/built/admin/assets/{automated-emails-te1D5kq-.js → automated-emails-D5VVMND9.js} +1 -1
  97. package/core/built/admin/assets/automations-CzKt5fb8.js +1 -0
  98. package/core/built/admin/assets/bluesky-sharing-BEtJ_gL_.js +1 -0
  99. package/core/built/admin/assets/{box-By_EgGtm.js → box-CdfQAP_F.js} +1 -1
  100. package/core/built/admin/assets/{brand-icon-09YqFZjV.js → brand-icon-CrIGOA3Z.js} +1 -1
  101. package/core/built/admin/assets/{breadcrumb-CcFr_ltt.js → breadcrumb-zUrZrBtW.js} +1 -1
  102. package/core/built/admin/assets/{button-BshWPHvn.js → button-eNMKQWXr.js} +1 -1
  103. package/core/built/admin/assets/{card-CiiE7QfM.js → card--VNbfgo3.js} +1 -1
  104. package/core/built/admin/assets/{chart-BnXyfH11.js → chart-BrhA41Zi.js} +1 -1
  105. package/core/built/admin/assets/chart-helpers-CfBKt0vT.js +1 -0
  106. package/core/built/admin/assets/{checkbox-Dwwr_3Py.js → checkbox-CgOn_tKW.js} +1 -1
  107. package/core/built/admin/assets/{chunk.524.91ecb33e6afc3bd8949b.js → chunk.524.a697dee88db67fdf6021.js} +4 -4
  108. package/core/built/admin/assets/{chunk.582.512549909741883f960c.js → chunk.582.5ed5d124cfca9c259b9c.js} +6 -6
  109. package/core/built/admin/assets/{chunk.16.f76a6314082d813d67e0.js → chunk.598.7e056fabb47ce7dbd73f.js} +14 -14
  110. package/core/built/admin/assets/{code-editor-view-BwIdPy_k.js → code-editor-view-BYNoAoNV.js} +1 -1
  111. package/core/built/admin/assets/{code-editor-view-CtkF82Fv.js → code-editor-view-K2wI-I5f.js} +1 -1
  112. package/core/built/admin/assets/color-picker-Ddw80xX6.js +3 -0
  113. package/core/built/admin/assets/color-picker-field-D9nUhvA7.js +1 -0
  114. package/core/built/admin/assets/combobox-w9j8PPQT.js +1 -0
  115. package/core/built/admin/assets/command-BfpHORBv.js +1 -0
  116. package/core/built/admin/assets/comments-BLmCmyCs.js +1 -0
  117. package/core/built/admin/assets/confirmation-context-CBM8G0Vj.js +1 -0
  118. package/core/built/admin/assets/{container-LiZf3XdY.js → container-BuQG1wuP.js} +1 -1
  119. package/core/built/admin/assets/{content-api-modal-BtpNI92-.js → content-api-modal-TXRz3U7S.js} +1 -1
  120. package/core/built/admin/assets/context-menu-_QMdd3kp.js +1 -0
  121. package/core/built/admin/assets/{copy-field-CglgRZyG.js → copy-field-6N01S07E.js} +1 -1
  122. package/core/built/admin/assets/create-ghost-browse-value-source-qIBymvvf.js +1 -0
  123. package/core/built/admin/assets/custom-field-type-option-BddFlJFa.js +1 -0
  124. package/core/built/admin/assets/custom-integration-modal-DmNquxUV.js +1 -0
  125. package/core/built/admin/assets/{data-list-CupF7bjM.js → data-list-CA2jYGPq.js} +1 -1
  126. package/core/built/admin/assets/{date-range-select-JPwM0yUj.js → date-range-select-uvz_DtPh.js} +1 -1
  127. package/core/built/admin/assets/design-and-theme-modal-BSmo12Op.js +2 -0
  128. package/core/built/admin/assets/{detail-page-D8lx2SdP.js → detail-page-Dnv-CdR1.js} +1 -1
  129. package/core/built/admin/assets/dirty-confirm-dialog-BZ1iytEd.js +1 -0
  130. package/core/built/admin/assets/{disabled-sources-indicator-BTJ2ClQu.js → disabled-sources-indicator-DMRrxsiJ.js} +1 -1
  131. package/core/built/admin/assets/{dist-DzcfoDJ3.js → dist-8YJUlf3B.js} +1 -1
  132. package/core/built/admin/assets/{dist-Cb5RSHSg.js → dist-B3keLvjj.js} +1 -1
  133. package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
  134. package/core/built/admin/assets/{dist-BT_Z-eCn.js → dist-Dgt2cr6a.js} +1 -1
  135. package/core/built/admin/assets/domain-BNYrt0aD.js +1 -0
  136. package/core/built/admin/assets/dropzone-D7nFdAe5.js +5 -0
  137. package/core/built/admin/assets/edit-profile-C5Asm4LA.js +1 -0
  138. package/core/built/admin/assets/editor-REokrzci.js +8 -0
  139. package/core/built/admin/assets/{embed-signup-form-modal-BFTPf04i.js → embed-signup-form-modal-Ds6mPEi5.js} +1 -1
  140. package/core/built/admin/assets/{empty-indicator-WB1WgT9h.js → empty-indicator-D9QdpuNX.js} +1 -1
  141. package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
  142. package/core/built/admin/assets/explore-UY10Egsp.js +1 -0
  143. package/core/built/admin/assets/feature-image-placeholder-D1iF_8bc.js +1 -0
  144. package/core/built/admin/assets/feed-81C8mJWR.js +1 -0
  145. package/core/built/admin/assets/{field-LmNk7wZh.js → field-Dihp5p18.js} +1 -1
  146. package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
  147. package/core/built/admin/assets/filter-sources-BO9xUPj7.js +1 -0
  148. package/core/built/admin/assets/filters-CRUWecfY.js +1 -0
  149. package/core/built/admin/assets/filters-DirqNXjH.js +1 -0
  150. package/core/built/admin/assets/first-promoter-modal-CT6MxYZb.js +1 -0
  151. package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8eabfc1ece81b03cf7b90780d31487e8.css} +1 -1
  152. package/core/built/admin/assets/{ghost-403cb39badad3df411fc0ba27d220047.js → ghost-c2848508292937415f20f5a830eea59e.js} +31 -28
  153. package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-a7bebe2c561f55369dcf29f4c820f7ff.css} +1 -1
  154. package/core/built/admin/assets/gift-link-modal-CQVAye17.js +1 -0
  155. package/core/built/admin/assets/{grid-CUciBfjf.js → grid-Dj29PY05.js} +1 -1
  156. package/core/built/admin/assets/growth-BWIu-6xj.js +3 -0
  157. package/core/built/admin/assets/growth-DU29oxeA.js +1 -0
  158. package/core/built/admin/assets/{heading-CRZZ2FUe.js → heading-Dh5SFVjL.js} +1 -1
  159. package/core/built/admin/assets/history-modal-CFd1Hvx6.js +1 -0
  160. package/core/built/admin/assets/html-field-CJBCLTvv.js +1 -0
  161. package/core/built/admin/assets/{images-C0XvUYMb.js → images-scfkWZiK.js} +1 -1
  162. package/core/built/admin/assets/{inbox-DZXDUt4s.js → inbox-Mcp4DXZN.js} +14 -14
  163. package/core/built/admin/assets/index-6MkPdCtr.js +4 -0
  164. package/core/built/admin/assets/index-Bn7QhcZu.css +2 -0
  165. package/core/built/admin/assets/index.es-CNnuNH0d.js +1 -0
  166. package/core/built/admin/assets/{inline-Cw-gigDW.js → inline-BWSs_VzR.js} +1 -1
  167. package/core/built/admin/assets/{input-group-BPAxETpQ.js → input-group-CMhe2DvY.js} +1 -1
  168. package/core/built/admin/assets/{input-surface-BdOe4KzO.js → input-surface-BsrIZeSF.js} +1 -1
  169. package/core/built/admin/assets/{integration-header-B4DyXV06.js → integration-header-Bm6IDb1A.js} +1 -1
  170. package/core/built/admin/assets/invite-user-modal-DfheMXs0.js +1 -0
  171. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
  172. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
  173. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  174. package/core/built/admin/assets/{koenig-lexical-60O_8aiO.js → koenig-lexical-DBSqAuiI.js} +3 -3
  175. package/core/built/admin/assets/koenig-loader-aFQNlJlD.js +2 -0
  176. package/core/built/admin/assets/kpi-card-DBRMfGOW.js +1 -0
  177. package/core/built/admin/assets/{kpi-card-fUHZlzBX.js → kpi-card-DFafD1qq.js} +1 -1
  178. package/core/built/admin/assets/kpi-helpers-Cv8i8hns.js +1 -0
  179. package/core/built/admin/assets/kpi-tabs-BJItvLYm.js +1 -0
  180. package/core/built/admin/assets/{label-VIG969IC.js → label-BnSCvffu.js} +1 -1
  181. package/core/built/admin/assets/label-picker-KVoo91sh.js +1 -0
  182. package/core/built/admin/assets/layout-Bjv2Ll-5.js +1 -0
  183. package/core/built/admin/assets/{link-helpers-Dtq9fxQg.js → link-helpers-MVDdnFCY.js} +1 -1
  184. package/core/built/admin/assets/{list-page-CdsnQR9N.js → list-page-BucXJ0hi.js} +1 -1
  185. package/core/built/admin/assets/member-custom-fields-DDQV6QeG.js +1 -0
  186. package/core/built/admin/assets/member-detail-CdJF6Agw.js +1 -0
  187. package/core/built/admin/assets/members-DjQbq9Z2.js +4 -0
  188. package/core/built/admin/assets/{modal-page-BMTzFHVO.js → modal-page-xCivTMvI.js} +1 -1
  189. package/core/built/admin/assets/moderation-AgCIEso4.js +1 -0
  190. package/core/built/admin/assets/{multi-select-combobox-CGohnsxJ.js → multi-select-combobox-BcITkUVr.js} +1 -1
  191. package/core/built/admin/assets/navigation-modal-BkT7b1M2.js +1 -0
  192. package/core/built/admin/assets/newsletter-BMMAuvgq.js +1 -0
  193. package/core/built/admin/assets/newsletter-detail-modal-0SCJ7Zpm.js +1 -0
  194. package/core/built/admin/assets/{newsletter-emails-D5ql1rud.js → newsletter-emails-DKzwafuh.js} +1 -1
  195. package/core/built/admin/assets/newsletters-BRBb_uQC.js +1 -0
  196. package/core/built/admin/assets/note-DyGHtS9a.js +1 -0
  197. package/core/built/admin/assets/notifications-ZgWniKna.js +1 -0
  198. package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
  199. package/core/built/admin/assets/offers-container-modal-B-E8TIWr.js +1 -0
  200. package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-CzIsre-d.js} +1 -1
  201. package/core/built/admin/assets/onboarding-qg8Akovm.js +1 -0
  202. package/core/built/admin/assets/{onboarding-route-Cu_ROWPn.js → onboarding-route-CaavZulg.js} +1 -1
  203. package/core/built/admin/assets/overview-BW8GLeYi.js +1 -0
  204. package/core/built/admin/assets/overview-BkXZNzaZ.js +1 -0
  205. package/core/built/admin/assets/{page-header-Cfds8pCg.js → page-header-De0VzKBi.js} +1 -1
  206. package/core/built/admin/assets/pagemenu-B5KKCpbA.js +1 -0
  207. package/core/built/admin/assets/pages-jgaFm69d.js +1 -0
  208. package/core/built/admin/assets/pages-route-CIUAQxtY.js +1 -0
  209. package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
  210. package/core/built/admin/assets/{pintura-modal-TDTrJ89x.js → pintura-modal-BZ2J9w3n.js} +1 -1
  211. package/core/built/admin/assets/portal-frame-B6Hr9wHc.js +1 -0
  212. package/core/built/admin/assets/portal-modal-D4ceei3t.js +1 -0
  213. package/core/built/admin/assets/post-analytics-header-BYCsT0GP.js +1 -0
  214. package/core/built/admin/assets/post-analytics-ot7f6pih.js +1 -0
  215. package/core/built/admin/assets/{post-analytics-provider-Cu3jNeFh.js → post-analytics-provider-Bo1gmYaP.js} +1 -1
  216. package/core/built/admin/assets/{post-share-modal-P1_M6o-H.js → post-share-modal-C-PaYZ_e.js} +1 -1
  217. package/core/built/admin/assets/posts-DuGazgTb.js +1 -0
  218. package/core/built/admin/assets/posts-list-screen-CBGGgjjj.js +2 -0
  219. package/core/built/admin/assets/posts-route-D6xmS7Vf.js +1 -0
  220. package/core/built/admin/assets/preferences-C5YJLp74.js +5 -0
  221. package/core/built/admin/assets/{preview-chrome-BOVO6_PE.js → preview-chrome-BljUBlOk.js} +1 -1
  222. package/core/built/admin/assets/{preview-modal-MlTjP8UU.js → preview-modal-BfeFqi5y.js} +1 -1
  223. package/core/built/admin/assets/profile-B8mx2yAu.js +1 -0
  224. package/core/built/admin/assets/{radio-group-CjtmsCPl.js → radio-group-DczlLKOn.js} +1 -1
  225. package/core/built/admin/assets/{router-provider-CJC58zTy.js → router-provider-B0gZyiGJ.js} +1 -1
  226. package/core/built/admin/assets/{schemas-CRsC53ls.js → schemas-DppqmpeJ.js} +2 -2
  227. package/core/built/admin/assets/select-cb0t_TAJ.js +1 -0
  228. package/core/built/admin/assets/settings-DZqxR0Da.js +1 -0
  229. package/core/built/admin/assets/settings-DvfTNdHQ.js +4 -0
  230. package/core/built/admin/assets/{settings-breadcrumbs-sLDNedBW.js → settings-breadcrumbs-DLzbRRSt.js} +1 -1
  231. package/core/built/admin/assets/{shade-app-F7WxOyfk-nufqw1hd.js → shade-app-CcS3f8MZ-vwURazk8.js} +2 -2
  232. package/core/built/admin/assets/share-modal-D2-Bz1_I.js +1 -0
  233. package/core/built/admin/assets/{skeleton-D7hwjdry.js → skeleton-Ce9GgUpf.js} +1 -1
  234. package/core/built/admin/assets/slack-modal-DYDTUria.js +1 -0
  235. package/core/built/admin/assets/sort-button-VVeQjjbu.js +1 -0
  236. package/core/built/admin/assets/{source-icon-BPsD5ees.js → source-icon-Ck5_5Kgq.js} +1 -1
  237. package/core/built/admin/assets/{stack-CIfOAAVf.js → stack-B2eszIiq.js} +1 -1
  238. package/core/built/admin/assets/stats-Rjmk5owg.js +1 -0
  239. package/core/built/admin/assets/stats-view-BGGmkmgv.js +1 -0
  240. package/core/built/admin/assets/{step-1-CMta6YFO.js → step-1-CsaBjeN4.js} +1 -1
  241. package/core/built/admin/assets/{step-2-BG04nh5q.js → step-2-D2vnxOOM.js} +1 -1
  242. package/core/built/admin/assets/{step-3-ZnMaVIPj.js → step-3-wBoLdGEb.js} +2 -2
  243. package/core/built/admin/assets/{stripe-button-DDoUKN5a.js → stripe-button-CDgLz0S0.js} +1 -1
  244. package/core/built/admin/assets/stripe-connect-modal-CSjMJetP.js +1 -0
  245. package/core/built/admin/assets/{switch-C9djUIMO.js → switch-CI4gLWqb.js} +1 -1
  246. package/core/built/admin/assets/{table-CrqQtkR2.js → table-Do6iQ83Q.js} +1 -1
  247. package/core/built/admin/assets/{tabs-CGisSbWq.js → tabs-D2yWLMp_.js} +1 -1
  248. package/core/built/admin/assets/tag-detail-BhXlOsCa.js +2 -0
  249. package/core/built/admin/assets/tags-ldukRApe.js +1 -0
  250. package/core/built/admin/assets/testimonials-modal-CtnZBJKl.js +1 -0
  251. package/core/built/admin/assets/{text-DU9Hv33_.js → text-BQDSDsKs.js} +1 -1
  252. package/core/built/admin/assets/{textarea-d9qEkMOP.js → textarea-DJ1Q5V39.js} +1 -1
  253. package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +1 -0
  254. package/core/built/admin/assets/{toggle-group-CtKZURJd.js → toggle-group-ByUJsxwD.js} +1 -1
  255. package/core/built/admin/assets/{topic-filter-D8JT8Tq1.js → topic-filter-BgC3g5_v.js} +1 -1
  256. package/core/built/admin/assets/{transistor-modal-6PUf0idx.js → transistor-modal-Drr0SNfo.js} +1 -1
  257. package/core/built/admin/assets/trend-badge-6ye93YAW.js +1 -0
  258. package/core/built/admin/assets/{unsplash-modal-BPuDBPja.js → unsplash-modal-p6AoQoWp.js} +1 -1
  259. package/core/built/admin/assets/{use-analytics-data--opuzwcz.js → use-analytics-data-CWCMAESo.js} +1 -1
  260. package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
  261. package/core/built/admin/assets/use-check-theme-limit-error-Cw3WQHy8.js +2 -0
  262. package/core/built/admin/assets/use-filter-params-BIni9taJ.js +1 -0
  263. package/core/built/admin/assets/use-growth-stats-DCVG3s9w.js +1 -0
  264. package/core/built/admin/assets/{use-limiter-TDSNiHPB.js → use-limiter-D2WRRx0H.js} +1 -1
  265. package/core/built/admin/assets/{use-navigate-with-base-path-CK989MlC.js → use-navigate-with-base-path-BHPA228f.js} +1 -1
  266. package/core/built/admin/assets/{use-pintura-config-CnCGrDFk.js → use-pintura-config-h-J0Lvta.js} +1 -1
  267. package/core/built/admin/assets/{use-pintura-editor-ntphvtUd.js → use-pintura-editor-BfN1UwzH.js} +1 -1
  268. package/core/built/admin/assets/use-post-referrers-Czg47m8s.js +1 -0
  269. package/core/built/admin/assets/use-reply-chain-data-ns0caK8k.js +1 -0
  270. package/core/built/admin/assets/{use-router-history-entry-BwfQS2mq.js → use-router-history-entry-uldn7zJO.js} +1 -1
  271. package/core/built/admin/assets/{use-setting-group-DQxV42-O.js → use-setting-group-DpcuCUDg.js} +1 -1
  272. package/core/built/admin/assets/use-settings-navigation-CZjGrhsp.js +1 -0
  273. package/core/built/admin/assets/{use-simple-pagination-B2TdNX67.js → use-simple-pagination-DzJWobPR.js} +1 -1
  274. package/core/built/admin/assets/{use-staff-users-QrR9voeC.js → use-staff-users-Csipb-O0.js} +1 -1
  275. package/core/built/admin/assets/use-tinybird-query-CSnGXzZh.js +1 -0
  276. package/core/built/admin/assets/use-tinybird-token-DTOKRR7e.js +1 -0
  277. package/core/built/admin/assets/{use-unsaved-changes-guard-DpYJcj1d.js → use-unsaved-changes-guard-CBzs-KPi.js} +1 -1
  278. package/core/built/admin/assets/{use-url-input-WnIqckzS.js → use-url-input-DFr8lCbS.js} +1 -1
  279. package/core/built/admin/assets/user-detail-modal-B_iUClI6.js +1 -0
  280. package/core/built/admin/assets/users-Cg-OeGzC.js +1 -0
  281. package/core/built/admin/assets/{virtual-list-D3MfPNOh.js → virtual-list-BW-padMe.js} +1 -1
  282. package/core/built/admin/assets/web-C1v33ehA.js +2 -0
  283. package/core/built/admin/assets/web-C4BKzn2T.js +1 -0
  284. package/core/built/admin/assets/{zapier-modal-BO6PS_Vd.js → zapier-modal-BBFfI6Ml.js} +1 -1
  285. package/core/built/admin/index.html +24 -30
  286. package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
  287. package/core/frontend/helpers/cancel_link.js +2 -2
  288. package/core/frontend/helpers/pagination.js +2 -2
  289. package/core/frontend/helpers/social_accounts.js +2 -2
  290. package/core/frontend/public/ghost.css +1 -1
  291. package/core/frontend/public/ghost.min.css +1 -1
  292. package/core/frontend/services/rendering/renderer.js +15 -0
  293. package/core/frontend/services/sitemap/user-map-generator.js +9 -2
  294. package/core/server/adapters/storage/LocalStorageBase.js +8 -5
  295. package/core/server/api/endpoints/db.js +19 -5
  296. package/core/server/api/endpoints/index.js +6 -2
  297. package/core/server/api/endpoints/mail.js +1 -1
  298. package/core/server/api/endpoints/member-metafields.js +89 -0
  299. package/core/server/api/endpoints/members.js +4 -4
  300. package/core/server/api/endpoints/posts.js +4 -3
  301. package/core/server/api/endpoints/tiers-checkout-config.js +59 -0
  302. package/core/server/api/endpoints/utils/serializers/input/members.js +4 -7
  303. package/core/server/api/endpoints/utils/serializers/output/config.js +1 -0
  304. package/core/server/api/endpoints/utils/serializers/output/index.js +6 -2
  305. package/core/server/api/endpoints/utils/serializers/output/{member-custom-fields.js → member-metafields.js} +2 -4
  306. package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
  307. package/core/server/api/endpoints/utils/serializers/output/tiers-checkout-config.js +12 -0
  308. package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
  309. package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
  310. package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
  311. package/core/server/data/exporter/table-lists.js +3 -0
  312. package/core/server/data/importer/content-files.js +57 -0
  313. package/core/server/data/importer/handlers/image.js +2 -2
  314. package/core/server/data/importer/import-archive.js +131 -0
  315. package/core/server/data/importer/import-manager.js +18 -180
  316. package/core/server/data/importer/importers/content-file-importer.js +66 -4
  317. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  318. package/core/server/data/migrations/utils/migrations.js +1 -1
  319. 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
  320. package/core/server/data/migrations/versions/6.61/2026-08-19-14-38-53-add-members-custom-field-bindings-table.js +26 -0
  321. package/core/server/data/migrations/versions/6.61/2026-08-19-14-48-06-add-tier-checkout-field-tables.js +35 -0
  322. package/core/server/data/schema/schema.js +90 -0
  323. package/core/server/data/seeders/importers/automation-action-revisions-importer.js +3 -3
  324. package/core/server/data/seeders/importers/automation-actions-importer.js +3 -3
  325. package/core/server/data/seeders/importers/automation-run-steps-importer.js +3 -3
  326. package/core/server/data/seeders/importers/automation-runs-importer.js +5 -5
  327. package/core/server/data/seeders/importers/automations-importer.js +3 -3
  328. package/core/server/data/seeders/importers/comment-reports-importer.js +1 -1
  329. package/core/server/data/seeders/importers/comments-importer.js +1 -1
  330. package/core/server/data/seeders/importers/email-batches-importer.js +1 -1
  331. package/core/server/data/seeders/importers/email-recipients-importer.js +1 -1
  332. package/core/server/data/seeders/importers/emails-importer.js +1 -1
  333. package/core/server/data/seeders/importers/labels-importer.js +1 -1
  334. package/core/server/data/seeders/importers/members-click-events-importer.js +1 -1
  335. package/core/server/data/seeders/importers/members-created-events-importer.js +1 -1
  336. package/core/server/data/seeders/importers/members-feedback-importer.js +1 -1
  337. package/core/server/data/seeders/importers/members-importer.js +1 -1
  338. package/core/server/data/seeders/importers/members-login-events-importer.js +1 -1
  339. package/core/server/data/seeders/importers/members-products-importer.js +1 -1
  340. package/core/server/data/seeders/importers/members-status-events-importer.js +1 -1
  341. package/core/server/data/seeders/importers/members-stripe-customers-importer.js +1 -1
  342. package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +1 -1
  343. package/core/server/data/seeders/importers/members-subscribe-events-importer.js +1 -1
  344. package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +1 -1
  345. package/core/server/data/seeders/importers/offer-redemptions-importer.js +1 -1
  346. package/core/server/data/seeders/importers/offers-importer.js +1 -1
  347. package/core/server/data/seeders/importers/posts-importer.js +1 -1
  348. package/core/server/data/seeders/importers/table-importer.js +2 -2
  349. package/core/server/data/seeders/importers/tags-importer.js +1 -1
  350. package/core/server/data/seeders/importers/users-importer.js +1 -1
  351. package/core/server/data/seeders/importers/web-mentions-importer.js +1 -1
  352. package/core/server/data/seeders/utils/random.js +3 -3
  353. package/core/server/ghost-server.js +3 -2
  354. package/core/server/lib/db-types/boolean.js +18 -0
  355. package/core/server/lib/image/image-size.js +24 -0
  356. package/core/server/lib/package-json/parse.js +2 -2
  357. package/core/server/lib/promise-pool.js +31 -0
  358. package/core/server/models/member.js +6 -17
  359. package/core/server/models/post.js +2 -2
  360. package/core/server/models/relations/authors.js +2 -16
  361. package/core/server/models/user.js +9 -2
  362. package/core/server/services/auth/passwordreset.js +13 -0
  363. package/core/server/services/automations/database-automations-repository.js +26 -26
  364. package/core/server/services/automations/poll.js +1 -0
  365. package/core/server/services/comments/comments-controller.js +30 -9
  366. package/core/server/services/comments/comments-service.js +55 -5
  367. package/core/server/services/content-import/csv/formula.js +12 -0
  368. package/core/server/services/content-import/csv/index.js +6 -1
  369. package/core/server/services/content-import/csv/parse.js +27 -6
  370. package/core/server/services/content-import/csv/serialize.js +13 -0
  371. package/core/server/services/content-import/import/assets.js +74 -0
  372. package/core/server/services/content-import/import/completion-email.js +164 -0
  373. package/core/server/services/content-import/import/errors-file.js +36 -0
  374. package/core/server/services/content-import/import/importer.js +204 -54
  375. package/core/server/services/content-import/import/local-media-url.js +63 -0
  376. package/core/server/services/content-import/import/media.js +254 -0
  377. package/core/server/services/content-import/import/post-data.js +1 -1
  378. package/core/server/services/content-import/import/post-link.js +11 -0
  379. package/core/server/services/content-import/import/post-repository.js +100 -0
  380. package/core/server/services/content-import/import/reader.js +9 -2
  381. package/core/server/services/content-import/import/relations.js +149 -0
  382. package/core/server/services/content-import/import/report.js +34 -0
  383. package/core/server/services/content-import/import/row.js +11 -2
  384. package/core/server/services/content-import/import/schema.js +30 -0
  385. package/core/server/services/content-import/import/source.js +125 -0
  386. package/core/server/services/content-import/import/staged-file.js +29 -0
  387. package/core/server/services/content-import/import/store.js +25 -2
  388. package/core/server/services/content-import/index.js +58 -34
  389. package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
  390. package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
  391. package/core/server/services/custom-redirects/redirects-service.js +1 -1
  392. package/core/server/services/custom-redirects/validation.js +1 -1
  393. package/core/server/services/email-address/email-address-parser.js +30 -38
  394. package/core/server/services/email-address/email-address-service.js +37 -4
  395. package/core/server/services/email-analytics/email-analytics-service.js +8 -1
  396. package/core/server/services/email-analytics/index.js +2 -7
  397. package/core/server/services/email-analytics/lib/queries.js +7 -1
  398. package/core/server/services/email-service/batch-sending-service.js +0 -4
  399. package/core/server/services/email-service/email-renderer.js +14 -4
  400. package/core/server/services/email-service/email-service-wrapper.js +0 -9
  401. package/core/server/services/email-service/mailgun-email-provider.js +20 -9
  402. package/core/server/services/gift-links/schema.js +3 -3
  403. package/core/server/services/gifts/CONTEXT.md +1 -1
  404. package/core/server/services/gifts/constants.js +1 -1
  405. package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
  406. package/core/server/services/gifts/gift-bookshelf-repository.js +2 -2
  407. package/core/server/services/gifts/gift-delivery-bookshelf-repository.js +18 -9
  408. package/core/server/services/gifts/gift-delivery-schema.js +5 -5
  409. package/core/server/services/gifts/gift-delivery-service.js +4 -0
  410. package/core/server/services/gifts/gift-email-service.js +0 -1
  411. package/core/server/services/gifts/gift-schema.js +10 -10
  412. package/core/server/services/gifts/gift-service.js +4 -2
  413. package/core/server/services/gifts/index.js +3 -3
  414. package/core/server/services/gifts/jobs/index.js +4 -4
  415. package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
  416. package/core/server/services/invitations/accept.js +4 -2
  417. package/core/server/services/jobs/job-service.js +0 -9
  418. package/core/server/services/jobs-service/register-job-handlers.js +25 -15
  419. package/core/server/services/lib/mailgun-client.js +44 -8
  420. package/core/server/services/mail/ghost-mailer.js +4 -4
  421. package/core/server/services/media-inliner/external-media-inliner-job.js +12 -0
  422. package/core/server/services/media-inliner/external-media-inliner.js +103 -29
  423. package/core/server/services/media-inliner/service.js +13 -41
  424. package/core/server/services/media-inliner/types.js +2 -0
  425. package/core/server/services/member-welcome-emails/service.js +7 -7
  426. package/core/server/services/members/api.js +1 -0
  427. package/core/server/services/members/import-export/csv/parse.js +0 -7
  428. package/core/server/services/members/import-export/export/exporter.js +4 -6
  429. package/core/server/services/members/import-export/import/completion-email.js +2 -5
  430. package/core/server/services/members/import-export/import/importer.js +21 -5
  431. package/core/server/services/members/import-export/import/row.js +0 -3
  432. package/core/server/services/members/import-export/import/stripe-utils.js +6 -1
  433. package/core/server/services/members/import-export/index.js +10 -12
  434. package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
  435. package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
  436. package/core/server/services/members/jobs/index.js +48 -24
  437. package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
  438. package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
  439. package/core/server/services/members/members-api/members-api.js +9 -6
  440. package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
  441. package/core/server/services/members/members-api/services/member-bread-service.js +53 -63
  442. package/core/server/services/members/members-api/services/payments-service.js +47 -1
  443. package/core/server/services/members/service.js +1 -5
  444. package/core/server/services/members-custom-fields/actions.js +27 -1
  445. package/core/server/services/members-custom-fields/bindings-service.js +120 -0
  446. package/core/server/services/members-custom-fields/codec.js +3 -4
  447. package/core/server/services/members-custom-fields/definitions-service.js +165 -22
  448. package/core/server/services/members-custom-fields/filter.js +75 -93
  449. package/core/server/services/members-custom-fields/index.js +11 -4
  450. package/core/server/services/members-custom-fields/key.js +2 -1
  451. package/core/server/services/members-custom-fields/models.js +1 -1
  452. package/core/server/services/members-custom-fields/queries.js +5 -0
  453. package/core/server/services/members-custom-fields/schema.js +37 -6
  454. package/core/server/services/members-custom-fields/serializers.js +3 -5
  455. package/core/server/services/members-custom-fields/values-service.js +65 -31
  456. package/core/server/services/mentions/mention-controller.js +23 -21
  457. package/core/server/services/mentions/process-webmention-job.js +16 -0
  458. package/core/server/services/mentions/service.js +8 -4
  459. package/core/server/services/public-config/config.js +7 -0
  460. package/core/server/services/route-settings/validation-errors.js +1 -1
  461. package/core/server/services/route-settings/yaml-parser.js +1 -1
  462. package/core/server/services/settings/settings-service.js +1 -8
  463. package/core/server/services/settings-helpers/settings-helpers.js +4 -6
  464. package/core/server/services/slack-ping/slack-ping-service.js +1 -1
  465. package/core/server/services/staff/staff-service-emails.js +2 -2
  466. package/core/server/services/stripe/config.js +14 -8
  467. package/core/server/services/stripe/service.js +10 -1
  468. package/core/server/services/stripe/services/checkout/completed-session.js +68 -0
  469. package/core/server/services/stripe/services/checkout/session-options.js +100 -0
  470. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +71 -1
  471. package/core/server/services/stripe/stripe-api.js +31 -0
  472. package/core/server/services/stripe/stripe-service.js +26 -9
  473. package/core/server/services/stripe/webhook-controller.js +10 -0
  474. package/core/server/services/tier-checkout-config/codec.js +99 -0
  475. package/core/server/services/tier-checkout-config/index.js +26 -0
  476. package/core/server/services/tier-checkout-config/models.js +63 -0
  477. package/core/server/services/tier-checkout-config/queries.js +80 -0
  478. package/core/server/services/tier-checkout-config/schema.js +33 -0
  479. package/core/server/services/tier-checkout-config/serializers.js +128 -0
  480. package/core/server/services/tier-checkout-config/service.js +304 -0
  481. package/core/server/services/tiers/service.js +21 -0
  482. package/core/server/services/update-check/index.js +13 -13
  483. package/core/server/services/update-check/jobs/update-check-job.js +7 -0
  484. package/core/server/services/update-check/update-check-service.js +2 -2
  485. package/core/server/web/admin/controller.js +1 -1
  486. package/core/server/web/api/endpoints/admin/routes.js +34 -20
  487. package/core/server/web/api/middleware/upload.js +2 -2
  488. package/core/server/web/parent/app.js +5 -0
  489. package/core/server/web/parent/middleware/filter-query-parameters.js +94 -0
  490. package/core/server/web/parent/middleware/index.js +1 -0
  491. package/core/server/web/query-parameter-policy/index.js +9 -0
  492. package/core/server/web/query-parameter-policy/policy.json +58 -0
  493. package/core/server/web/query-parameter-policy/schema.js +38 -0
  494. package/core/shared/config/defaults.json +3 -0
  495. package/core/shared/config/env/config.testing-mysql.json +4 -1
  496. package/core/shared/config/env/config.testing.json +3 -0
  497. package/core/shared/config/overrides.json +4 -2
  498. package/core/shared/labs.js +9 -15
  499. package/package.json +25 -25
  500. package/pnpm-lock.yaml +741 -108
  501. package/pnpm-workspace.yaml +12 -9
  502. package/tsconfig.json +2 -3
  503. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  504. package/core/built/admin/assets/Combination-gnJO3vIw.js +0 -41
  505. package/core/built/admin/assets/account-migration-8qTEI1i1.js +0 -1
  506. package/core/built/admin/assets/activitypub/inbox-DQ5CwLma.js +0 -1284
  507. package/core/built/admin/assets/activitypub/label-B72sfvEU.js +0 -16
  508. package/core/built/admin/assets/activitypub/layout-CXajhRsL.js +0 -1
  509. package/core/built/admin/assets/activitypub/settings-71gCm3SO.js +0 -315
  510. package/core/built/admin/assets/add-integration-modal--YpTq3c0.js +0 -1
  511. package/core/built/admin/assets/add-newsletter-modal-C8Ix2hol.js +0 -1
  512. package/core/built/admin/assets/add-recommendation-modal-CScuNFz4.js +0 -1
  513. package/core/built/admin/assets/alert-dialog-wEbVxANM.js +0 -1
  514. package/core/built/admin/assets/analytics-Cnji45H5.js +0 -1
  515. package/core/built/admin/assets/app-utils-D2Wp7ZSS.js +0 -1
  516. package/core/built/admin/assets/audience-DTLMXAFH.js +0 -1
  517. package/core/built/admin/assets/automations-BWpRCZ_f.js +0 -1
  518. package/core/built/admin/assets/bluesky-sharing-DHOpQxff.js +0 -1
  519. package/core/built/admin/assets/chart-helpers-B3OqQ6Ez.js +0 -1
  520. package/core/built/admin/assets/color-picker-Bmo1r9Fc.js +0 -3
  521. package/core/built/admin/assets/color-picker-field-DywowPhF.js +0 -1
  522. package/core/built/admin/assets/combobox-C4QCh6Yw.js +0 -1
  523. package/core/built/admin/assets/command-DcLbSifC.js +0 -1
  524. package/core/built/admin/assets/comments-Bxy_3WyE.js +0 -1
  525. package/core/built/admin/assets/confirmation-context-CLFHhyyH.js +0 -1
  526. package/core/built/admin/assets/custom-field-type-option-D0PXoSnP.js +0 -10
  527. package/core/built/admin/assets/custom-integration-modal-DCIHKN33.js +0 -1
  528. package/core/built/admin/assets/design-and-theme-modal-CZ-PkW7o.js +0 -23
  529. package/core/built/admin/assets/dialog-Db7c164G.js +0 -1
  530. package/core/built/admin/assets/dirty-confirm-dialog-CmARpZQS.js +0 -1
  531. package/core/built/admin/assets/dist-QLZuGq7o2.js +0 -1
  532. package/core/built/admin/assets/domain-D0SAtc-T.js +0 -1
  533. package/core/built/admin/assets/dropzone-CaPOeDRZ.js +0 -5
  534. package/core/built/admin/assets/edit-profile-By7v5XW5.js +0 -1
  535. package/core/built/admin/assets/editor-COXn4Atu.js +0 -8
  536. package/core/built/admin/assets/explore-BsNYrubV.js +0 -1
  537. package/core/built/admin/assets/feed-8RR1O1bK.js +0 -1
  538. package/core/built/admin/assets/filter-sources-4C0kF1NU.js +0 -1
  539. package/core/built/admin/assets/filters-CV5jCb9n.js +0 -1
  540. package/core/built/admin/assets/filters-Dmr0PoqU.js +0 -1
  541. package/core/built/admin/assets/first-promoter-modal-OCzSaL3B.js +0 -1
  542. package/core/built/admin/assets/gift-link-modal-0mzjn5oF.js +0 -1
  543. package/core/built/admin/assets/growth-55vWlGT_.js +0 -1
  544. package/core/built/admin/assets/growth-DA5AluYw.js +0 -3
  545. package/core/built/admin/assets/history-modal-G1s5hHz7.js +0 -1
  546. package/core/built/admin/assets/html-field-BegxsWpw.js +0 -1
  547. package/core/built/admin/assets/index-CDP9tIOk.js +0 -4
  548. package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
  549. package/core/built/admin/assets/index.es-BMUCj9TR.js +0 -1
  550. package/core/built/admin/assets/input-UHrKuvBT.js +0 -1
  551. package/core/built/admin/assets/invite-user-modal-BrAkxEO3.js +0 -1
  552. package/core/built/admin/assets/koenig-loader-DwVY_V-H.js +0 -1
  553. package/core/built/admin/assets/kpi-card-LERqWBoY.js +0 -1
  554. package/core/built/admin/assets/kpi-helpers-DB3ouhYF.js +0 -1
  555. package/core/built/admin/assets/kpi-tabs-BGvtMD8S.js +0 -1
  556. package/core/built/admin/assets/label-picker-BBWykUeA.js +0 -1
  557. package/core/built/admin/assets/layout-Di5K7doM.js +0 -1
  558. package/core/built/admin/assets/loading-indicator-SFTqyYVE.js +0 -1
  559. package/core/built/admin/assets/member-custom-fields-gOv6Hoh3.js +0 -1
  560. package/core/built/admin/assets/member-detail-D7mZDDp3.js +0 -1
  561. package/core/built/admin/assets/member-route-0Aa52Ntz.js +0 -1
  562. package/core/built/admin/assets/members-DvZG9t69.js +0 -2
  563. package/core/built/admin/assets/moderation-DzzPLDyl.js +0 -1
  564. package/core/built/admin/assets/navigation-modal-CI8Bx5vn.js +0 -1
  565. package/core/built/admin/assets/newsletter-Bg3cq5U-.js +0 -1
  566. package/core/built/admin/assets/newsletter-detail-modal-DQU3r4g2.js +0 -1
  567. package/core/built/admin/assets/newsletters-DMDfZbMS.js +0 -1
  568. package/core/built/admin/assets/note-i8k6pjaw.js +0 -1
  569. package/core/built/admin/assets/notifications-psA_2Ph4.js +0 -1
  570. package/core/built/admin/assets/offers-container-modal-BWfjSdyg.js +0 -1
  571. package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
  572. package/core/built/admin/assets/overview-C-6xOLaf.js +0 -1
  573. package/core/built/admin/assets/overview-DaLhpRrC.js +0 -1
  574. package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
  575. package/core/built/admin/assets/popover-CFgqFDvC.js +0 -1
  576. package/core/built/admin/assets/portal-frame-DjBF-uy2.js +0 -1
  577. package/core/built/admin/assets/portal-modal-Cf0pBAk8.js +0 -1
  578. package/core/built/admin/assets/post-analytics-Buz1COoY.js +0 -1
  579. package/core/built/admin/assets/post-analytics-header-B-P0eFnT.js +0 -1
  580. package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
  581. package/core/built/admin/assets/preferences-Cq1aOiLy.js +0 -5
  582. package/core/built/admin/assets/profile-D6dHYf2o.js +0 -1
  583. package/core/built/admin/assets/select-D_RQaXgt.js +0 -1
  584. package/core/built/admin/assets/settings-B5hJKZ5C.js +0 -1
  585. package/core/built/admin/assets/settings-DIo_F-MF.js +0 -4
  586. package/core/built/admin/assets/share-modal-CLBfj377.js +0 -1
  587. package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
  588. package/core/built/admin/assets/slack-modal-Bt9I_tEo.js +0 -1
  589. package/core/built/admin/assets/sort-button-DMBXF7tP.js +0 -1
  590. package/core/built/admin/assets/stats-B_YkF7bp.js +0 -1
  591. package/core/built/admin/assets/stats-view-BOCp9RG8.js +0 -1
  592. package/core/built/admin/assets/stripe-connect-modal-BeSukI8q.js +0 -1
  593. package/core/built/admin/assets/tag-detail-2a3BfzTW.js +0 -2
  594. package/core/built/admin/assets/tags-Dp2_8UzL.js +0 -1
  595. package/core/built/admin/assets/testimonials-modal-C9nrypNo.js +0 -1
  596. package/core/built/admin/assets/tier-detail-modal-CxRwgTPR.js +0 -1
  597. package/core/built/admin/assets/use-check-theme-limit-error-C9-QhGdV.js +0 -1
  598. package/core/built/admin/assets/use-filter-params-CSpAvgD2.js +0 -1
  599. package/core/built/admin/assets/use-growth-stats-BOmoPDHJ.js +0 -1
  600. package/core/built/admin/assets/use-post-referrers-CbXLFIex.js +0 -1
  601. package/core/built/admin/assets/use-reply-chain-data-JYFKSO83.js +0 -1
  602. package/core/built/admin/assets/use-settings-navigation-BBzro2-V.js +0 -1
  603. package/core/built/admin/assets/use-tinybird-query-D2Aeoty5.js +0 -39
  604. package/core/built/admin/assets/use-tinybird-token-DBuwMmln.js +0 -1
  605. package/core/built/admin/assets/user-detail-modal-59mBJqxN.js +0 -1
  606. package/core/built/admin/assets/users-5msE1WMs.js +0 -1
  607. package/core/built/admin/assets/web-DUuX7nE2.js +0 -2
  608. package/core/built/admin/assets/web-N8ucs2aG.js +0 -1
  609. package/core/server/api/endpoints/member-custom-fields.js +0 -100
  610. package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
  611. package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
  612. package/core/server/services/update-check/run-update-check.js +0 -63
  613. /package/core/server/lib/{db-date.js → db-types/date.js} +0 -0
@@ -1,31 +1,21 @@
1
1
  const _ = require('lodash');
2
2
  const fs = require('fs-extra');
3
3
  const path = require('path');
4
- const os = require('os');
5
- const { globSync } = require('glob');
6
- const crypto = require('crypto');
7
4
  const config = require('../../../shared/config');
8
- const { extract } = require('@tryghost/zip');
9
5
  const tpl = require('@tryghost/tpl');
10
6
  const debug = require('@tryghost/debug')('import-manager');
11
7
  const logging = require('@tryghost/logging');
12
8
  const errors = require('@tryghost/errors');
13
- const ImageHandler = require('./handlers/image');
14
- const ImporterContentFileHandler = require('./handlers/importer-content-file-handler');
15
9
  const RevueHandler = require('./handlers/revue');
16
10
  const JSONHandler = require('./handlers/json');
17
11
  const MarkdownHandler = require('./handlers/markdown');
18
- const ContentFileImporter = require('./importers/content-file-importer');
19
12
  const RevueImporter = require('./importers/importer-revue');
20
13
  const DataImporter = require('./importers/data');
21
14
  const urlUtils = require('../../../shared/url-utils').default;
22
15
  const { GhostMailer } = require('../../services/mail');
23
16
  const jobManager = require('../../services/jobs');
24
- const adapterManager = require('../../services/adapter-manager').default;
25
-
26
- const mediaStorage = adapterManager.getAdapter('storage:media');
27
- const imageStorage = adapterManager.getAdapter('storage:images');
28
- const fileStorage = adapterManager.getAdapter('storage:files');
17
+ const ImportArchive = require('./import-archive').default;
18
+ const { createContentFileHandlers, createContentFileImporters } = require('./content-files');
29
19
 
30
20
  const { emailTemplate } = require('./email-template');
31
21
  const ghostMailer = new GhostMailer();
@@ -36,21 +26,9 @@ const messages = {
36
26
  context: 'Your site will continue to work as expected',
37
27
  },
38
28
  noContentToImport: 'Zip did not include any content to import.',
39
- invalidZipStructure: 'Invalid zip file structure.',
40
- invalidZipFileBaseDirectory: 'Invalid zip file: base directory read failed',
41
29
  zipContainsMultipleDataFormats:
42
30
  'Zip file contains multiple data formats. Please split up and import separately.',
43
- invalidZipFileNameEncoding: 'The uploaded zip could not be read',
44
- invalidZipFileNameEncodingContext: 'The filename was too long or contained invalid characters',
45
- invalidZipFileNameEncodingHelp:
46
- 'Remove any special characters from the file name, or alternatively try another archiving tool if using MacOS Archive Utility',
47
31
  };
48
-
49
- // Glob levels
50
- const ROOT_ONLY = 0;
51
-
52
- const ROOT_OR_SINGLE_DIR = 1;
53
- const ALL_DIRS = 2;
54
32
  let defaults = {
55
33
  extensions: ['.zip'],
56
34
  contentTypes: ['application/zip', 'application/x-zip-compressed'],
@@ -59,68 +37,23 @@ let defaults = {
59
37
 
60
38
  class ImportManager {
61
39
  constructor() {
62
- const mediaHandler = new ImporterContentFileHandler({
63
- type: 'media',
64
- // @NOTE: making the second parameter strict folder "content/media" brakes the glob pattern
65
- // in the importer, so we need to keep it as general "content" unless
66
- // it becomes a strict requirement
67
- directories: ['media', 'content'],
68
- ignoreRootFolderFiles: true,
69
- extensions: config.get('uploads').media.extensions,
70
- contentTypes: config.get('uploads').media.contentTypes,
71
- urlUtils: urlUtils,
72
- storage: mediaStorage,
73
- });
74
-
75
- const filesHandler = new ImporterContentFileHandler({
76
- type: 'files',
77
- // @NOTE: making the second parameter strict folder "content/files" brakes the glob pattern
78
- // in the importer, so we need to keep it as general "content" unless
79
- // it becomes a strict requirement
80
- directories: ['files', 'content'],
81
- ignoreRootFolderFiles: true,
82
- extensions: config.get('uploads').files.extensions,
83
- contentTypes: config.get('uploads').files.contentTypes,
84
- urlUtils: urlUtils,
85
- storage: fileStorage,
86
- });
87
-
88
- const imageImporter = new ContentFileImporter({
89
- type: 'images',
90
- store: imageStorage,
91
- });
92
- const mediaImporter = new ContentFileImporter({
93
- type: 'media',
94
- store: mediaStorage,
95
- });
96
-
97
- const contentFilesImporter = new ContentFileImporter({
98
- type: 'files',
99
- store: fileStorage,
100
- });
40
+ const contentFileHandlers = createContentFileHandlers();
41
+ const contentFileImporters = createContentFileImporters();
101
42
 
102
43
  /**
103
44
  * @type {Importer[]} importers
104
45
  */
105
- this.importers = [
106
- imageImporter,
107
- mediaImporter,
108
- contentFilesImporter,
109
- RevueImporter,
110
- DataImporter,
111
- ];
46
+ this.importers = [...contentFileImporters, RevueImporter, DataImporter];
112
47
 
113
48
  /**
114
49
  * @type {Handler[]}
115
50
  */
116
- this.handlers = [
117
- ImageHandler,
118
- mediaHandler,
119
- filesHandler,
120
- RevueHandler,
121
- JSONHandler,
122
- MarkdownHandler,
123
- ];
51
+ this.handlers = [...contentFileHandlers, RevueHandler, JSONHandler, MarkdownHandler];
52
+
53
+ this.archive = new ImportArchive({
54
+ extensions: this.getExtensions(),
55
+ directories: this.getDirectories(),
56
+ });
124
57
 
125
58
  // Keep track of file to cleanup at the end
126
59
  /**
@@ -159,17 +92,7 @@ class ImportManager {
159
92
  * @returns {string}
160
93
  */
161
94
  getGlobPattern(items) {
162
- return (
163
- '+(' +
164
- _.reduce(
165
- items,
166
- function (memo, ext) {
167
- return memo !== '' ? memo + '|' + ext : ext;
168
- },
169
- '',
170
- ) +
171
- ')'
172
- );
95
+ return this.archive.getGlobPattern(items);
173
96
  }
174
97
 
175
98
  /**
@@ -178,9 +101,7 @@ class ImportManager {
178
101
  * @returns {string}
179
102
  */
180
103
  getExtensionGlob(extensions, level) {
181
- const prefix = level === ALL_DIRS ? '**/*' : level === ROOT_OR_SINGLE_DIR ? '{*/*,*}' : '*';
182
-
183
- return prefix + this.getGlobPattern(extensions);
104
+ return this.archive.getExtensionGlob(extensions, level);
184
105
  }
185
106
 
186
107
  /**
@@ -190,9 +111,7 @@ class ImportManager {
190
111
  * @returns {string}
191
112
  */
192
113
  getDirectoryGlob(directories, level) {
193
- const prefix = level === ALL_DIRS ? '**/' : level === ROOT_OR_SINGLE_DIR ? '{*/,}' : '';
194
-
195
- return prefix + this.getGlobPattern(directories);
114
+ return this.archive.getDirectoryGlob(directories, level);
196
115
  }
197
116
 
198
117
  /**
@@ -212,31 +131,7 @@ class ImportManager {
212
131
  * @returns {boolean}
213
132
  */
214
133
  isValidZip(directory) {
215
- // Globs match content in the root or inside a single directory
216
- const extMatchesBase = globSync(
217
- this.getExtensionGlob(this.getExtensions(), ROOT_OR_SINGLE_DIR),
218
- { cwd: directory, nocase: true },
219
- );
220
-
221
- const extMatchesAll = globSync(this.getExtensionGlob(this.getExtensions(), ALL_DIRS), {
222
- cwd: directory,
223
- nocase: true,
224
- });
225
-
226
- const dirMatches = globSync(this.getDirectoryGlob(this.getDirectories(), ROOT_OR_SINGLE_DIR), {
227
- cwd: directory,
228
- });
229
-
230
- // If this folder contains importable files or a content or images directory
231
- if (extMatchesBase.length > 0 || (dirMatches.length > 0 && extMatchesAll.length > 0)) {
232
- return true;
233
- }
234
-
235
- if (extMatchesAll.length < 1) {
236
- throw new errors.UnsupportedMediaTypeError({ message: tpl(messages.noContentToImport) });
237
- }
238
-
239
- throw new errors.UnsupportedMediaTypeError({ message: tpl(messages.invalidZipStructure) });
134
+ return this.archive.isValid(directory);
240
135
  }
241
136
 
242
137
  /**
@@ -245,37 +140,8 @@ class ImportManager {
245
140
  * @returns {Promise<string>} full path to the extracted folder
246
141
  */
247
142
  async extractZip(filePath) {
248
- const tmpDir = path.join(os.tmpdir(), crypto.randomUUID());
143
+ const tmpDir = await this.archive.extract(filePath);
249
144
  this.fileToDelete = tmpDir;
250
-
251
- try {
252
- await extract(filePath, tmpDir);
253
-
254
- // Set permissions for all extracted files
255
- const files = globSync('**/*', { cwd: tmpDir, nodir: true });
256
- await Promise.all(files.map((file) => fs.chmod(path.join(tmpDir, file), 0o644)));
257
- } catch (err) {
258
- if (err.message.startsWith('ENAMETOOLONG:')) {
259
- // The file was probably zipped with MacOS zip utility. Which doesn't correctly set UTF-8 encoding flag.
260
- // This causes ENAMETOOLONG error on Linux, because the resulting filename length is too long when decoded using the default string encoder.
261
- throw new errors.UnsupportedMediaTypeError({
262
- message: tpl(messages.invalidZipFileNameEncoding),
263
- context: tpl(messages.invalidZipFileNameEncodingContext),
264
- help: tpl(messages.invalidZipFileNameEncodingHelp),
265
- code: 'INVALID_ZIP_FILE_NAME_ENCODING',
266
- });
267
- } else if (
268
- err.message.includes('end of central directory record signature not found') ||
269
- err.message.includes('invalid comment length')
270
- ) {
271
- // This comes from Yauzl when the zip is invalid
272
- throw new errors.UnsupportedMediaTypeError({
273
- message: tpl(messages.invalidZipFileNameEncoding),
274
- code: 'INVALID_ZIP_FILE',
275
- });
276
- }
277
- throw err;
278
- }
279
145
  return tmpDir;
280
146
  }
281
147
 
@@ -287,10 +153,7 @@ class ImportManager {
287
153
  * @returns {File[]} Files
288
154
  */
289
155
  getFilesFromZip(handler, directory) {
290
- const globPattern = this.getExtensionGlob(handler.extensions, ALL_DIRS);
291
- return _.map(globSync(globPattern, { cwd: directory, nocase: true }), function (file) {
292
- return { name: file, path: path.join(directory, file) };
293
- });
156
+ return this.archive.getFiles(directory, handler.extensions);
294
157
  }
295
158
 
296
159
  /**
@@ -299,32 +162,7 @@ class ImportManager {
299
162
  * @returns {string}
300
163
  */
301
164
  getBaseDirectory(directory) {
302
- // Globs match root level only
303
- const extMatches = globSync(this.getExtensionGlob(this.getExtensions(), ROOT_ONLY), {
304
- cwd: directory,
305
- nocase: true,
306
- });
307
-
308
- const dirMatches = globSync(this.getDirectoryGlob(this.getDirectories(), ROOT_ONLY), {
309
- cwd: directory,
310
- nocase: true,
311
- });
312
- let extMatchesAll;
313
-
314
- // There is no base directory
315
- if (extMatches.length > 0 || dirMatches.length > 0) {
316
- return;
317
- }
318
- // There is a base directory, grab it from any ext match
319
- extMatchesAll = globSync(this.getExtensionGlob(this.getExtensions(), ALL_DIRS), {
320
- cwd: directory,
321
- nocase: true,
322
- });
323
- if (extMatchesAll.length < 1 || extMatchesAll[0].split('/').length < 1) {
324
- throw new errors.ValidationError({ message: tpl(messages.invalidZipFileBaseDirectory) });
325
- }
326
-
327
- return extMatchesAll[0].split('/')[0];
165
+ return this.archive.getBaseDirectory(directory);
328
166
  }
329
167
 
330
168
  /**
@@ -1,4 +1,5 @@
1
1
  const _ = require('lodash');
2
+ const path = require('node:path');
2
3
  let replaceImage;
3
4
  let preProcessPosts;
4
5
  let preProcessTags;
@@ -9,8 +10,19 @@ replaceImage = function (markdown, image) {
9
10
  return;
10
11
  }
11
12
 
12
- // Normalizes to include a trailing slash if there was one
13
- const regex = new RegExp('(/)?' + image.originalPath, 'gm');
13
+ const originalPaths = [image.originalPath];
14
+ if (image.originalPath.startsWith('content/')) {
15
+ originalPaths.push(image.originalPath.slice('content/'.length));
16
+ } else {
17
+ originalPaths.unshift(`content/${image.originalPath}`);
18
+ }
19
+
20
+ // Match canonical /content/{type} paths before their shorter archive path so
21
+ // replacing images/image.jpg cannot leave an extra /content prefix behind.
22
+ // Consume __GHOST_URL__ too: newPath already contains the configured subdir
23
+ // and the model will normalize it back to transform-ready form on write.
24
+ const escapedPaths = originalPaths.map((originalPath) => _.escapeRegExp(originalPath));
25
+ const regex = new RegExp(`(?:__GHOST_URL__)?/?(?:${escapedPaths.join('|')})`, 'gm');
14
26
 
15
27
  return markdown.replace(regex, image.newPath);
16
28
  };
@@ -31,6 +43,12 @@ preProcessPosts = function (data, contentFile) {
31
43
  if (post.feature_image) {
32
44
  post.feature_image = replaceImage(post.feature_image, contentFile);
33
45
  }
46
+ if (post.og_image) {
47
+ post.og_image = replaceImage(post.og_image, contentFile);
48
+ }
49
+ if (post.twitter_image) {
50
+ post.twitter_image = replaceImage(post.twitter_image, contentFile);
51
+ }
34
52
  });
35
53
  };
36
54
 
@@ -114,10 +132,10 @@ class ContentFileImporter {
114
132
  * @param {Object[]} contentFilesData
115
133
  * @returns
116
134
  */
117
- doImport(contentFilesData) {
135
+ async doImport(contentFilesData) {
118
136
  const store = this.#store;
119
137
 
120
- return Promise.all(
138
+ const results = await Promise.allSettled(
121
139
  contentFilesData.map(function (contentFile) {
122
140
  return store.save(contentFile, contentFile.targetDir).then(function (result) {
123
141
  return {
@@ -128,6 +146,50 @@ class ContentFileImporter {
128
146
  });
129
147
  }),
130
148
  );
149
+
150
+ const failure = results.find((result) => result.status === 'rejected');
151
+ if (failure) {
152
+ const storedFiles = results.flatMap((result) =>
153
+ result.status === 'fulfilled' ? [result.value] : [],
154
+ );
155
+ try {
156
+ await this.rollback(storedFiles);
157
+ } catch (rollbackFailure) {
158
+ // AggregateError is the native error for preserving both storage failures;
159
+ // it is not a GhostError and therefore does not accept an options object.
160
+ // eslint-disable-next-line ghost/ghost-custom/ghost-error-usage
161
+ throw new AggregateError(
162
+ [failure.reason, rollbackFailure],
163
+ 'Asset storage failed and rollback was incomplete.',
164
+ { cause: failure.reason },
165
+ );
166
+ }
167
+ throw failure.reason;
168
+ }
169
+
170
+ return results.map((result) => result.value);
171
+ }
172
+
173
+ /**
174
+ * @param {{stored: string}[]} storedFiles
175
+ * @returns {Promise<void>}
176
+ */
177
+ async rollback(storedFiles) {
178
+ const store = this.#store;
179
+ const results = await Promise.allSettled(
180
+ storedFiles.map(function (storedFile) {
181
+ const storedPath = store.urlToPath(storedFile.stored);
182
+ const targetDir = path.posix.dirname(storedPath);
183
+ return store.delete(
184
+ path.posix.basename(storedPath),
185
+ targetDir === '.' ? undefined : targetDir,
186
+ );
187
+ }),
188
+ );
189
+ const failure = results.find((result) => result.status === 'rejected');
190
+ if (failure) {
191
+ throw failure.reason;
192
+ }
131
193
  }
132
194
  }
133
195
 
@@ -99,7 +99,7 @@ DataImporter = {
99
99
  return Promise.reject(
100
100
  new IncorrectUsageError({
101
101
  message: 'Wrong importer structure. `meta` is missing.',
102
- help: 'https://ghost.org/docs/migration/custom/',
102
+ help: 'https://docs.ghost.org/migration/custom/',
103
103
  }),
104
104
  );
105
105
  }
@@ -108,7 +108,7 @@ DataImporter = {
108
108
  return Promise.reject(
109
109
  new IncorrectUsageError({
110
110
  message: 'Wrong importer structure. `meta.version` is missing.',
111
- help: 'https://ghost.org/docs/migration/custom/',
111
+ help: 'https://docs.ghost.org/migration/custom/',
112
112
  }),
113
113
  );
114
114
  }
@@ -119,7 +119,7 @@ DataImporter = {
119
119
  return Promise.reject(
120
120
  new IncorrectUsageError({
121
121
  message: 'Detected unsupported file structure.',
122
- help: 'Please install Ghost 1.0, import the file and then update your blog to the latest Ghost version.\nVisit https://ghost.org/docs/update/ or ask for help in our https://forum.ghost.org.',
122
+ help: 'Please install Ghost 1.0, import the file and then update your blog to the latest Ghost version.\nVisit https://docs.ghost.org/update/ or ask for help in our https://forum.ghost.org.',
123
123
  }),
124
124
  );
125
125
  }
@@ -117,7 +117,7 @@ function createFinalMigration(major) {
117
117
  async function up() {
118
118
  throw new errors.InternalServerError({
119
119
  message: `Unable to run migrations`,
120
- context: `You must be on the latest v${major}.x to update across major versions - https://ghost.org/docs/update/`,
120
+ context: `You must be on the latest v${major}.x to update across major versions - https://docs.ghost.org/update/`,
121
121
  help: `Run 'ghost update v${major}' to get the latest v${major}.x version, then run 'ghost update' to get to the latest.`,
122
122
  });
123
123
  },
@@ -0,0 +1,42 @@
1
+ const logging = require('@tryghost/logging');
2
+ const {
3
+ combineNonTransactionalMigrations,
4
+ createAddColumnMigration,
5
+ createNonTransactionalMigration,
6
+ } = require('../../utils');
7
+
8
+ const TABLE = 'members_custom_field_values';
9
+
10
+ // Who wrote the value that is here now: a type and an id, the way `actions` records an
11
+ // actor. The type is required because it is the namespace the id resolves in, and a value
12
+ // nobody can be traced to is not a record of provenance. The id is nullable for the one
13
+ // writer that resolves in no table — an import, until runs are tracked.
14
+ //
15
+ // Existing rows have a writer nobody can recover, so they go rather than get backfilled:
16
+ // the feature is behind the `membersCustomFields` flag with no released data, and adding
17
+ // a required column over them ends either in an error, as SQLite refuses one with no
18
+ // default, or in an invented writer wherever the engine supplies its own empty string.
19
+ module.exports = combineNonTransactionalMigrations(
20
+ createNonTransactionalMigration(
21
+ async function up(knex) {
22
+ if (!(await knex.schema.hasColumn(TABLE, 'written_by_type'))) {
23
+ logging.info(`Clearing ${TABLE} of values with no recorded writer`);
24
+ await knex(TABLE).del();
25
+ }
26
+ },
27
+ async function down() {
28
+ // Nothing to undo: the rows are gone, and dropping the columns below is what a
29
+ // rollback is for.
30
+ },
31
+ ),
32
+ createAddColumnMigration(TABLE, 'written_by_type', {
33
+ type: 'string',
34
+ maxlength: 50,
35
+ nullable: false,
36
+ }),
37
+ createAddColumnMigration(TABLE, 'written_by_id', {
38
+ type: 'string',
39
+ maxlength: 24,
40
+ nullable: true,
41
+ }),
42
+ );
@@ -0,0 +1,26 @@
1
+ const { addTable } = require('../../utils');
2
+
3
+ module.exports = addTable('members_custom_field_bindings', {
4
+ id: { type: 'string', maxlength: 24, nullable: false, primary: true },
5
+ product_id: {
6
+ type: 'string',
7
+ maxlength: 24,
8
+ nullable: false,
9
+ references: 'products.id',
10
+ cascadeDelete: true,
11
+ },
12
+ port: { type: 'string', maxlength: 191, nullable: false },
13
+ custom_field_key: {
14
+ type: 'string',
15
+ maxlength: 191,
16
+ nullable: false,
17
+ references: 'members_custom_fields.key',
18
+ cascadeDelete: true,
19
+ },
20
+ created_at: { type: 'dateTime', nullable: false },
21
+ updated_at: { type: 'dateTime', nullable: true },
22
+ '@@UNIQUE_CONSTRAINTS@@': [
23
+ { columns: ['product_id', 'port'], indexName: 'members_custom_field_bindings_unique' },
24
+ ],
25
+ '@@INDEXES@@': [['custom_field_key']],
26
+ });
@@ -0,0 +1,35 @@
1
+ const { combineNonTransactionalMigrations, addTable } = require('../../utils');
2
+
3
+ module.exports = combineNonTransactionalMigrations(
4
+ addTable('products_checkout_fields', {
5
+ id: { type: 'string', maxlength: 24, nullable: false, primary: true },
6
+ binding_id: {
7
+ type: 'string',
8
+ maxlength: 24,
9
+ nullable: false,
10
+ unique: true,
11
+ references: 'members_custom_field_bindings.id',
12
+ cascadeDelete: true,
13
+ },
14
+ sort_order: { type: 'integer', nullable: false, unsigned: true, defaultTo: 0 },
15
+ label: { type: 'string', maxlength: 191, nullable: true },
16
+ optional: { type: 'boolean', nullable: false, defaultTo: true },
17
+ created_at: { type: 'dateTime', nullable: false },
18
+ updated_at: { type: 'dateTime', nullable: true },
19
+ }),
20
+ addTable('products_checkout_config', {
21
+ id: { type: 'string', maxlength: 24, nullable: false, primary: true },
22
+ product_id: {
23
+ type: 'string',
24
+ maxlength: 24,
25
+ nullable: false,
26
+ unique: true,
27
+ references: 'products.id',
28
+ cascadeDelete: true,
29
+ },
30
+ shipping_allowed_countries: { type: 'string', maxlength: 2000, nullable: true },
31
+ tax_number_collect: { type: 'boolean', nullable: false, defaultTo: false },
32
+ created_at: { type: 'dateTime', nullable: false },
33
+ updated_at: { type: 'dateTime', nullable: true },
34
+ }),
35
+ );
@@ -1064,6 +1064,79 @@ module.exports = {
1064
1064
  created_at: { type: 'dateTime', nullable: false },
1065
1065
  updated_at: { type: 'dateTime', nullable: true },
1066
1066
  },
1067
+ // Where a source sends what it collected. The source is who collects, the port is that
1068
+ // source's own name for the thing, and the destination is the publisher's field, which
1069
+ // they can repoint without the source knowing. The row is the collecting: there is one
1070
+ // and the source writes through it, or there is none and it does not.
1071
+ //
1072
+ // A second kind of source becomes a `source_type` beside a widened id. What it must not
1073
+ // become is a second table holding destinations.
1074
+ members_custom_field_bindings: {
1075
+ id: { type: 'string', maxlength: 24, nullable: false, primary: true },
1076
+ product_id: {
1077
+ type: 'string',
1078
+ maxlength: 24,
1079
+ nullable: false,
1080
+ references: 'products.id',
1081
+ cascadeDelete: true,
1082
+ },
1083
+ port: { type: 'string', maxlength: 191, nullable: false },
1084
+ // Indexed rather than unique: several sources landing in one field is expected.
1085
+ custom_field_key: {
1086
+ type: 'string',
1087
+ maxlength: 191,
1088
+ nullable: false,
1089
+ references: 'members_custom_fields.key',
1090
+ cascadeDelete: true,
1091
+ },
1092
+ created_at: { type: 'dateTime', nullable: false },
1093
+ updated_at: { type: 'dateTime', nullable: true },
1094
+ '@@UNIQUE_CONSTRAINTS@@': [
1095
+ { columns: ['product_id', 'port'], indexName: 'members_custom_field_bindings_unique' },
1096
+ ],
1097
+ '@@INDEXES@@': [['custom_field_key']],
1098
+ },
1099
+ // How a tier's checkout question is asked. Where the answer lands is the binding it
1100
+ // hangs off.
1101
+ products_checkout_fields: {
1102
+ id: { type: 'string', maxlength: 24, nullable: false, primary: true },
1103
+ binding_id: {
1104
+ type: 'string',
1105
+ maxlength: 24,
1106
+ nullable: false,
1107
+ unique: true,
1108
+ references: 'members_custom_field_bindings.id',
1109
+ cascadeDelete: true,
1110
+ },
1111
+ sort_order: { type: 'integer', nullable: false, unsigned: true, defaultTo: 0 },
1112
+ // Processors cap a label far shorter than a field name may be. Null asks under the
1113
+ // field's own name.
1114
+ label: { type: 'string', maxlength: 191, nullable: true },
1115
+ optional: { type: 'boolean', nullable: false, defaultTo: true },
1116
+ created_at: { type: 'dateTime', nullable: false },
1117
+ updated_at: { type: 'dateTime', nullable: true },
1118
+ },
1119
+ // The options a tier's collection needs, and the one thing it collects without keeping.
1120
+ // Whether it collects anything it *does* keep is the binding above.
1121
+ products_checkout_config: {
1122
+ id: { type: 'string', maxlength: 24, nullable: false, primary: true },
1123
+ product_id: {
1124
+ type: 'string',
1125
+ maxlength: 24,
1126
+ nullable: false,
1127
+ unique: true,
1128
+ references: 'products.id',
1129
+ cascadeDelete: true,
1130
+ },
1131
+ // ISO 3166-1 alpha-2, comma-joined. A processor will not render an address form
1132
+ // without them, and a wrong code fails the session create.
1133
+ shipping_allowed_countries: { type: 'string', maxlength: 2000, nullable: true },
1134
+ // Stripe keeps a tax number against the customer it invoices, so there is no
1135
+ // destination to bind and nothing to record but whether to ask.
1136
+ tax_number_collect: { type: 'boolean', nullable: false, defaultTo: false },
1137
+ created_at: { type: 'dateTime', nullable: false },
1138
+ updated_at: { type: 'dateTime', nullable: true },
1139
+ },
1067
1140
  members_custom_field_values: {
1068
1141
  id: { type: 'string', maxlength: 24, nullable: false, primary: true },
1069
1142
  // The field's stable key, not its id: a value is addressed by key everywhere it
@@ -1096,6 +1169,23 @@ module.exports = {
1096
1169
  // column a fresh install bounds at 65,535 bytes. The bound matching long_text's
1097
1170
  // exactly is worth more than the schema restating what the write path enforces.
1098
1171
  value_text: { type: 'text', maxlength: 65535, nullable: true },
1172
+ // Who wrote the value that is here now.
1173
+ //
1174
+ // Shaped like `actions`: a type and an id, no foreign key. A type because not every
1175
+ // write comes through a binding — a person edits a member's fields, an import reads a
1176
+ // file — and an id so the writer can be resolved back rather than merely named. A
1177
+ // binding id resolves to the tier, the port and the field it routed into, which is
1178
+ // everything worth knowing about how a value got here.
1179
+ //
1180
+ // No foreign key, because provenance has to outlive its cause: that a value arrived
1181
+ // through a tier's shipping port stays true after someone deletes that binding, even
1182
+ // though it stops being joinable.
1183
+ //
1184
+ // The type is the namespace the id resolves in, so every row carries one. The id is
1185
+ // nullable for the one writer that resolves in no table: an import has none to give
1186
+ // until runs are tracked.
1187
+ written_by_type: { type: 'string', maxlength: 50, nullable: false },
1188
+ written_by_id: { type: 'string', maxlength: 24, nullable: true },
1099
1189
  created_at: { type: 'dateTime', nullable: false },
1100
1190
  updated_at: { type: 'dateTime', nullable: true },
1101
1191
  // Named, because the name knex derives from the table and all three columns
@@ -7,7 +7,7 @@ exports.AutomationActionRevisionsImporter = void 0;
7
7
  const faker_1 = require("@faker-js/faker");
8
8
  const errors_1 = __importDefault(require("@tryghost/errors"));
9
9
  const table_importer_1 = require("./table-importer");
10
- const db_date_1 = require("../../../lib/db-date");
10
+ const date_1 = require("../../../lib/db-types/date");
11
11
  const constants_1 = require("../../../services/member-welcome-emails/constants");
12
12
  class AutomationActionRevisionsImporter extends table_importer_1.TableImporter {
13
13
  static table = 'automation_action_revisions';
@@ -48,12 +48,12 @@ class AutomationActionRevisionsImporter extends table_importer_1.TableImporter {
48
48
  message: 'Cannot generate automation action revision without an action',
49
49
  });
50
50
  }
51
- const createdAt = (0, db_date_1.fromDatabaseDate)(this.#action.created_at);
51
+ const createdAt = (0, date_1.fromDatabaseDate)(this.#action.created_at);
52
52
  createdAt.setSeconds(createdAt.getSeconds() + this.#revisionIndex);
53
53
  this.#revisionIndex += 1;
54
54
  const common = {
55
55
  id: this.fastFakeObjectId(),
56
- created_at: (0, db_date_1.toDatabaseDate)(createdAt),
56
+ created_at: (0, date_1.toDatabaseDate)(createdAt),
57
57
  action_id: this.#action.id,
58
58
  email_sent_count: null,
59
59
  email_opened_count: null,