ghost 6.61.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 (472) 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 +54 -22
  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/{about-Bve7IJS2.js → about-Dyae_UT6.js} +1 -1
  46. package/core/built/admin/assets/account-migration-CESa0mnX.js +1 -0
  47. package/core/built/admin/assets/activitypub/{account-migration-C-aej4x_.js → account-migration-By69CgCp.js} +16 -16
  48. package/core/built/admin/assets/activitypub/activitypub.js +9 -9
  49. package/core/built/admin/assets/activitypub/{bluesky-sharing-BXkA5mqV.js → bluesky-sharing-BJcPMrDd.js} +36 -36
  50. package/core/built/admin/assets/activitypub/{content-formatters-CHcyMFk4.js → content-formatters-3rTHg3mp.js} +3 -3
  51. package/core/built/admin/assets/activitypub/{domain-B3ihkPde.js → domain-DUR4xSkV.js} +121 -121
  52. package/core/built/admin/assets/activitypub/{edit-profile-DsZM3rTX.js → edit-profile-BqtfzxCp.js} +40 -40
  53. package/core/built/admin/assets/activitypub/{explore-BodNrZgR.js → explore-BxuJd-J4.js} +26 -26
  54. package/core/built/admin/assets/activitypub/{feed-PwH1iJ84.js → feed-BM1TcksA.js} +48 -48
  55. package/core/built/admin/assets/activitypub/{field-D06-kmOJ.js → field-Dn7HHx2-.js} +2 -2
  56. package/core/built/admin/assets/activitypub/inbox-CCjkuow2.js +1284 -0
  57. package/core/built/admin/assets/activitypub/label-1AA_s9Fa.js +16 -0
  58. package/core/built/admin/assets/activitypub/layout-2-0bw6HN.js +1 -0
  59. package/core/built/admin/assets/activitypub/{moderation-D1Yapsod.js → moderation-CnmxEB8w.js} +91 -91
  60. package/core/built/admin/assets/activitypub/{note-C5zjqq5C.js → note-ZKc_Bnba.js} +23 -23
  61. package/core/built/admin/assets/activitypub/{notifications-B9p8eCHD.js → notifications-CB2tJZau.js} +48 -48
  62. package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-BsJ9E5qf.js} +2 -2
  63. package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-CSUJJIlh.js} +2 -2
  64. package/core/built/admin/assets/activitypub/{preferences-BCqUdC3v.js → preferences-0-JZnUkI.js} +1519 -1519
  65. package/core/built/admin/assets/activitypub/{profile-BRCWoFem.js → profile-C35cFIhM.js} +183 -183
  66. package/core/built/admin/assets/activitypub/{routes-BSXT992i.js → routes-BD4vscyc.js} +740 -731
  67. package/core/built/admin/assets/activitypub/settings-BsMROdqh.js +315 -0
  68. package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-O0RL9YCN.js} +2 -2
  69. package/core/built/admin/assets/activitypub/{step-1-B-YfsVeO.js → step-1-BMSx7c_X.js} +4 -4
  70. package/core/built/admin/assets/activitypub/{step-3-D6BFMXL_.js → step-3-CLlOZTyt.js} +3 -3
  71. package/core/built/admin/assets/activitypub/{tabs-GpNecvfB.js → tabs-Dxk-b9M-.js} +306 -306
  72. package/core/built/admin/assets/activitypub/{topic-filter-BPDeQQys.js → topic-filter-5yZH6tId.js} +2 -2
  73. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-BoVOxXkV.js → use-activity-pub-queries-CV50qe03.js} +2 -2
  74. package/core/built/admin/assets/activitypub/{use-reply-chain-data-wVBX7swM.js → use-reply-chain-data-Cbvzgjzd.js} +30 -30
  75. package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-BjcoP_HC.js} +7 -5
  76. package/core/built/admin/assets/add-integration-modal-BlF6rs_f.js +1 -0
  77. package/core/built/admin/assets/add-newsletter-modal-CglVQqah.js +1 -0
  78. package/core/built/admin/assets/add-recommendation-modal-wz7BsuaG.js +1 -0
  79. package/core/built/admin/assets/analytics-C4HE1gBg.js +1 -0
  80. package/core/built/admin/assets/{announcement-bar-modal-DM3cYOpo.js → announcement-bar-modal-Ci4zz8jO.js} +1 -1
  81. package/core/built/admin/assets/{api-keys-BLm2NDBh.js → api-keys-Ck-Yteiv.js} +1 -1
  82. package/core/built/admin/assets/{audience-9mwU5TW6.js → audience-CtbA54Sn.js} +1 -1
  83. package/core/built/admin/assets/{automated-emails-te1D5kq-.js → automated-emails-D5VVMND9.js} +1 -1
  84. package/core/built/admin/assets/automations-CzKt5fb8.js +1 -0
  85. package/core/built/admin/assets/bluesky-sharing-BEtJ_gL_.js +1 -0
  86. package/core/built/admin/assets/{breadcrumb-DLiqCyFc.js → breadcrumb-zUrZrBtW.js} +1 -1
  87. package/core/built/admin/assets/{button-B2jcu6bk.js → button-eNMKQWXr.js} +1 -1
  88. package/core/built/admin/assets/{chart-helpers-Fo3bUL3K.js → chart-helpers-CfBKt0vT.js} +1 -1
  89. package/core/built/admin/assets/{checkbox-BfKktMph.js → checkbox-CgOn_tKW.js} +1 -1
  90. package/core/built/admin/assets/{chunk.524.60ca4692d91c6022042f.js → chunk.524.a697dee88db67fdf6021.js} +4 -4
  91. package/core/built/admin/assets/{chunk.582.525c7617c2d9e94c940a.js → chunk.582.5ed5d124cfca9c259b9c.js} +6 -6
  92. package/core/built/admin/assets/{chunk.896.435fe0637944d4a69810.js → chunk.598.7e056fabb47ce7dbd73f.js} +14 -14
  93. package/core/built/admin/assets/{code-editor-view-CYVu4EW6.js → code-editor-view-BYNoAoNV.js} +1 -1
  94. package/core/built/admin/assets/{code-editor-view-DCQJxsfU.js → code-editor-view-K2wI-I5f.js} +1 -1
  95. package/core/built/admin/assets/color-picker-Ddw80xX6.js +3 -0
  96. package/core/built/admin/assets/color-picker-field-D9nUhvA7.js +1 -0
  97. package/core/built/admin/assets/combobox-w9j8PPQT.js +1 -0
  98. package/core/built/admin/assets/command-BfpHORBv.js +1 -0
  99. package/core/built/admin/assets/comments-BLmCmyCs.js +1 -0
  100. package/core/built/admin/assets/confirmation-context-CBM8G0Vj.js +1 -0
  101. package/core/built/admin/assets/{content-api-modal-CyQEC3fr.js → content-api-modal-TXRz3U7S.js} +1 -1
  102. package/core/built/admin/assets/context-menu-_QMdd3kp.js +1 -0
  103. package/core/built/admin/assets/{copy-field-B3M1s78L.js → copy-field-6N01S07E.js} +1 -1
  104. package/core/built/admin/assets/create-ghost-browse-value-source-qIBymvvf.js +1 -0
  105. package/core/built/admin/assets/custom-field-type-option-BddFlJFa.js +1 -0
  106. package/core/built/admin/assets/custom-integration-modal-DmNquxUV.js +1 -0
  107. package/core/built/admin/assets/{date-range-select-DD2RKkgB.js → date-range-select-uvz_DtPh.js} +1 -1
  108. package/core/built/admin/assets/design-and-theme-modal-BSmo12Op.js +2 -0
  109. package/core/built/admin/assets/dirty-confirm-dialog-BZ1iytEd.js +1 -0
  110. package/core/built/admin/assets/{disabled-sources-indicator-Cvy47bE2.js → disabled-sources-indicator-DMRrxsiJ.js} +1 -1
  111. package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
  112. package/core/built/admin/assets/domain-BNYrt0aD.js +1 -0
  113. package/core/built/admin/assets/dropzone-D7nFdAe5.js +5 -0
  114. package/core/built/admin/assets/edit-profile-C5Asm4LA.js +1 -0
  115. package/core/built/admin/assets/editor-REokrzci.js +8 -0
  116. package/core/built/admin/assets/{embed-signup-form-modal-DeBMLxlL.js → embed-signup-form-modal-Ds6mPEi5.js} +1 -1
  117. package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
  118. package/core/built/admin/assets/explore-UY10Egsp.js +1 -0
  119. package/core/built/admin/assets/feature-image-placeholder-D1iF_8bc.js +1 -0
  120. package/core/built/admin/assets/feed-81C8mJWR.js +1 -0
  121. package/core/built/admin/assets/{field-Cj8lmDOo.js → field-Dihp5p18.js} +1 -1
  122. package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
  123. package/core/built/admin/assets/filter-sources-BO9xUPj7.js +1 -0
  124. package/core/built/admin/assets/filters-CRUWecfY.js +1 -0
  125. package/core/built/admin/assets/filters-DirqNXjH.js +1 -0
  126. package/core/built/admin/assets/first-promoter-modal-CT6MxYZb.js +1 -0
  127. package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8eabfc1ece81b03cf7b90780d31487e8.css} +1 -1
  128. package/core/built/admin/assets/{ghost-3894eedcc6968f658578c0abfe942aab.js → ghost-c2848508292937415f20f5a830eea59e.js} +31 -28
  129. package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-a7bebe2c561f55369dcf29f4c820f7ff.css} +1 -1
  130. package/core/built/admin/assets/gift-link-modal-CQVAye17.js +1 -0
  131. package/core/built/admin/assets/growth-BWIu-6xj.js +3 -0
  132. package/core/built/admin/assets/growth-DU29oxeA.js +1 -0
  133. package/core/built/admin/assets/history-modal-CFd1Hvx6.js +1 -0
  134. package/core/built/admin/assets/{html-field-C8qVGGC1.js → html-field-CJBCLTvv.js} +1 -1
  135. package/core/built/admin/assets/{images-h8VZEQ9k.js → images-scfkWZiK.js} +1 -1
  136. package/core/built/admin/assets/{inbox-BYd1M06Q.js → inbox-Mcp4DXZN.js} +14 -14
  137. package/core/built/admin/assets/index-6MkPdCtr.js +4 -0
  138. package/core/built/admin/assets/index-Bn7QhcZu.css +2 -0
  139. package/core/built/admin/assets/index.es-CNnuNH0d.js +1 -0
  140. package/core/built/admin/assets/{input-group-D8sCXRF5.js → input-group-CMhe2DvY.js} +1 -1
  141. package/core/built/admin/assets/invite-user-modal-DfheMXs0.js +1 -0
  142. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
  143. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
  144. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  145. package/core/built/admin/assets/{koenig-lexical-_-IsVI7E.js → koenig-lexical-DBSqAuiI.js} +3 -3
  146. package/core/built/admin/assets/koenig-loader-aFQNlJlD.js +2 -0
  147. package/core/built/admin/assets/{kpi-card-DZQk_0W8.js → kpi-card-DBRMfGOW.js} +1 -1
  148. package/core/built/admin/assets/{kpi-card-DW_2y3ug.js → kpi-card-DFafD1qq.js} +1 -1
  149. package/core/built/admin/assets/{kpi-helpers-PueTKuA6.js → kpi-helpers-Cv8i8hns.js} +1 -1
  150. package/core/built/admin/assets/{kpi-tabs-CojDs-Qz.js → kpi-tabs-BJItvLYm.js} +1 -1
  151. package/core/built/admin/assets/{label-DjbT91GM.js → label-BnSCvffu.js} +1 -1
  152. package/core/built/admin/assets/label-picker-KVoo91sh.js +1 -0
  153. package/core/built/admin/assets/layout-Bjv2Ll-5.js +1 -0
  154. package/core/built/admin/assets/member-custom-fields-DDQV6QeG.js +1 -0
  155. package/core/built/admin/assets/member-detail-CdJF6Agw.js +1 -0
  156. package/core/built/admin/assets/members-DjQbq9Z2.js +4 -0
  157. package/core/built/admin/assets/moderation-AgCIEso4.js +1 -0
  158. package/core/built/admin/assets/{multi-select-combobox-B6LiRzDO.js → multi-select-combobox-BcITkUVr.js} +1 -1
  159. package/core/built/admin/assets/navigation-modal-BkT7b1M2.js +1 -0
  160. package/core/built/admin/assets/newsletter-BMMAuvgq.js +1 -0
  161. package/core/built/admin/assets/newsletter-detail-modal-0SCJ7Zpm.js +1 -0
  162. package/core/built/admin/assets/{newsletter-emails-CFeLlt4z.js → newsletter-emails-DKzwafuh.js} +1 -1
  163. package/core/built/admin/assets/newsletters-BRBb_uQC.js +1 -0
  164. package/core/built/admin/assets/note-DyGHtS9a.js +1 -0
  165. package/core/built/admin/assets/notifications-ZgWniKna.js +1 -0
  166. package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
  167. package/core/built/admin/assets/offers-container-modal-B-E8TIWr.js +1 -0
  168. package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-CzIsre-d.js} +1 -1
  169. package/core/built/admin/assets/onboarding-qg8Akovm.js +1 -0
  170. package/core/built/admin/assets/{onboarding-route-Dmc4IPm3.js → onboarding-route-CaavZulg.js} +1 -1
  171. package/core/built/admin/assets/overview-BW8GLeYi.js +1 -0
  172. package/core/built/admin/assets/overview-BkXZNzaZ.js +1 -0
  173. package/core/built/admin/assets/{page-header-BR_nbIPp.js → page-header-De0VzKBi.js} +1 -1
  174. package/core/built/admin/assets/pagemenu-B5KKCpbA.js +1 -0
  175. package/core/built/admin/assets/pages-jgaFm69d.js +1 -0
  176. package/core/built/admin/assets/pages-route-CIUAQxtY.js +1 -0
  177. package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
  178. package/core/built/admin/assets/{pintura-modal-BR9hEvS8.js → pintura-modal-BZ2J9w3n.js} +1 -1
  179. package/core/built/admin/assets/portal-frame-B6Hr9wHc.js +1 -0
  180. package/core/built/admin/assets/portal-modal-D4ceei3t.js +1 -0
  181. package/core/built/admin/assets/post-analytics-header-BYCsT0GP.js +1 -0
  182. package/core/built/admin/assets/post-analytics-ot7f6pih.js +1 -0
  183. package/core/built/admin/assets/{post-analytics-provider-CLfKGWZy.js → post-analytics-provider-Bo1gmYaP.js} +1 -1
  184. package/core/built/admin/assets/{post-share-modal-Cl0NXRJr.js → post-share-modal-C-PaYZ_e.js} +1 -1
  185. package/core/built/admin/assets/posts-DuGazgTb.js +1 -0
  186. package/core/built/admin/assets/posts-list-screen-CBGGgjjj.js +2 -0
  187. package/core/built/admin/assets/posts-route-D6xmS7Vf.js +1 -0
  188. package/core/built/admin/assets/preferences-C5YJLp74.js +5 -0
  189. package/core/built/admin/assets/{preview-modal-C-BL-F9k.js → preview-modal-BfeFqi5y.js} +1 -1
  190. package/core/built/admin/assets/profile-B8mx2yAu.js +1 -0
  191. package/core/built/admin/assets/radio-group-DczlLKOn.js +1 -0
  192. package/core/built/admin/assets/{schemas-4UPic-oD.js → schemas-DppqmpeJ.js} +1 -1
  193. package/core/built/admin/assets/select-cb0t_TAJ.js +1 -0
  194. package/core/built/admin/assets/settings-DZqxR0Da.js +1 -0
  195. package/core/built/admin/assets/settings-DvfTNdHQ.js +4 -0
  196. package/core/built/admin/assets/{settings-breadcrumbs-CyP_9zTo.js → settings-breadcrumbs-DLzbRRSt.js} +1 -1
  197. package/core/built/admin/assets/share-modal-D2-Bz1_I.js +1 -0
  198. package/core/built/admin/assets/slack-modal-DYDTUria.js +1 -0
  199. package/core/built/admin/assets/{sort-button-Cc-Z96sA.js → sort-button-VVeQjjbu.js} +1 -1
  200. package/core/built/admin/assets/{source-icon-v6PUnmyM.js → source-icon-Ck5_5Kgq.js} +1 -1
  201. package/core/built/admin/assets/stats-Rjmk5owg.js +1 -0
  202. package/core/built/admin/assets/stats-view-BGGmkmgv.js +1 -0
  203. package/core/built/admin/assets/{step-1-DSRp2vBj.js → step-1-CsaBjeN4.js} +1 -1
  204. package/core/built/admin/assets/{step-2-COqv2g0u.js → step-2-D2vnxOOM.js} +1 -1
  205. package/core/built/admin/assets/{step-3-6W1NMVQc.js → step-3-wBoLdGEb.js} +2 -2
  206. package/core/built/admin/assets/{stripe-button-D2K42Uty.js → stripe-button-CDgLz0S0.js} +1 -1
  207. package/core/built/admin/assets/stripe-connect-modal-CSjMJetP.js +1 -0
  208. package/core/built/admin/assets/{table-B2pIKjVh.js → table-Do6iQ83Q.js} +1 -1
  209. package/core/built/admin/assets/{tabs-SaW_UT-Q.js → tabs-D2yWLMp_.js} +1 -1
  210. package/core/built/admin/assets/tag-detail-BhXlOsCa.js +2 -0
  211. package/core/built/admin/assets/tags-ldukRApe.js +1 -0
  212. package/core/built/admin/assets/testimonials-modal-CtnZBJKl.js +1 -0
  213. package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +1 -0
  214. package/core/built/admin/assets/{toggle-group-EM9WpESu.js → toggle-group-ByUJsxwD.js} +1 -1
  215. package/core/built/admin/assets/{topic-filter-DY4gNHn2.js → topic-filter-BgC3g5_v.js} +1 -1
  216. package/core/built/admin/assets/{transistor-modal-CpyPG-MH.js → transistor-modal-Drr0SNfo.js} +1 -1
  217. package/core/built/admin/assets/{trend-badge-ByMkuAuH.js → trend-badge-6ye93YAW.js} +1 -1
  218. package/core/built/admin/assets/{unsplash-modal-Cv2Q6GtY.js → unsplash-modal-p6AoQoWp.js} +1 -1
  219. package/core/built/admin/assets/{use-analytics-data-CHvjMYuT.js → use-analytics-data-CWCMAESo.js} +1 -1
  220. package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
  221. package/core/built/admin/assets/{use-check-theme-limit-error-Qv4SVXqw.js → use-check-theme-limit-error-Cw3WQHy8.js} +1 -1
  222. package/core/built/admin/assets/use-filter-params-BIni9taJ.js +1 -0
  223. package/core/built/admin/assets/use-growth-stats-DCVG3s9w.js +1 -0
  224. package/core/built/admin/assets/{use-limiter-cwJvsNBo.js → use-limiter-D2WRRx0H.js} +1 -1
  225. package/core/built/admin/assets/{use-pintura-config-CzTfnufz.js → use-pintura-config-h-J0Lvta.js} +1 -1
  226. package/core/built/admin/assets/{use-pintura-editor-BDBXWUYq.js → use-pintura-editor-BfN1UwzH.js} +1 -1
  227. package/core/built/admin/assets/use-post-referrers-Czg47m8s.js +1 -0
  228. package/core/built/admin/assets/use-reply-chain-data-ns0caK8k.js +1 -0
  229. package/core/built/admin/assets/{use-router-history-entry-Bg6BhBQQ.js → use-router-history-entry-uldn7zJO.js} +1 -1
  230. package/core/built/admin/assets/{use-setting-group-VM7FQwMY.js → use-setting-group-DpcuCUDg.js} +1 -1
  231. package/core/built/admin/assets/use-settings-navigation-CZjGrhsp.js +1 -0
  232. package/core/built/admin/assets/{use-simple-pagination-Dum6Irbs.js → use-simple-pagination-DzJWobPR.js} +1 -1
  233. package/core/built/admin/assets/{use-staff-users-cZg4ugOF.js → use-staff-users-Csipb-O0.js} +1 -1
  234. package/core/built/admin/assets/use-tinybird-query-CSnGXzZh.js +1 -0
  235. package/core/built/admin/assets/use-tinybird-token-DTOKRR7e.js +1 -0
  236. package/core/built/admin/assets/{use-unsaved-changes-guard-BAy0RANR.js → use-unsaved-changes-guard-CBzs-KPi.js} +1 -1
  237. package/core/built/admin/assets/{use-url-input-Df5QzNa7.js → use-url-input-DFr8lCbS.js} +1 -1
  238. package/core/built/admin/assets/user-detail-modal-B_iUClI6.js +1 -0
  239. package/core/built/admin/assets/users-Cg-OeGzC.js +1 -0
  240. package/core/built/admin/assets/{virtual-list-DEx8WgiO.js → virtual-list-BW-padMe.js} +1 -1
  241. package/core/built/admin/assets/web-C1v33ehA.js +2 -0
  242. package/core/built/admin/assets/web-C4BKzn2T.js +1 -0
  243. package/core/built/admin/assets/{zapier-modal-Cw3BTBUu.js → zapier-modal-BBFfI6Ml.js} +1 -1
  244. package/core/built/admin/index.html +17 -22
  245. package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
  246. package/core/frontend/helpers/cancel_link.js +2 -2
  247. package/core/frontend/helpers/pagination.js +2 -2
  248. package/core/frontend/helpers/social_accounts.js +2 -2
  249. package/core/frontend/public/ghost.css +1 -1
  250. package/core/frontend/public/ghost.min.css +1 -1
  251. package/core/frontend/services/sitemap/user-map-generator.js +9 -2
  252. package/core/server/api/endpoints/index.js +2 -2
  253. package/core/server/api/endpoints/mail.js +1 -1
  254. package/core/server/api/endpoints/{member-custom-fields.js → member-metafields.js} +27 -28
  255. package/core/server/api/endpoints/members.js +4 -4
  256. package/core/server/api/endpoints/posts.js +3 -3
  257. package/core/server/api/endpoints/utils/serializers/input/members.js +4 -7
  258. package/core/server/api/endpoints/utils/serializers/output/index.js +2 -2
  259. package/core/server/api/endpoints/utils/serializers/output/{member-custom-fields.js → member-metafields.js} +2 -4
  260. package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
  261. package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
  262. package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
  263. package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
  264. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  265. package/core/server/data/migrations/utils/migrations.js +1 -1
  266. package/core/server/lib/image/image-size.js +24 -0
  267. package/core/server/lib/package-json/parse.js +2 -2
  268. package/core/server/models/member.js +6 -17
  269. package/core/server/models/post.js +2 -2
  270. package/core/server/models/relations/authors.js +2 -16
  271. package/core/server/models/user.js +9 -2
  272. package/core/server/services/auth/passwordreset.js +13 -0
  273. package/core/server/services/comments/comments-controller.js +30 -9
  274. package/core/server/services/comments/comments-service.js +55 -5
  275. package/core/server/services/content-import/csv/formula.js +12 -0
  276. package/core/server/services/content-import/csv/index.js +6 -1
  277. package/core/server/services/content-import/csv/parse.js +27 -6
  278. package/core/server/services/content-import/csv/serialize.js +13 -0
  279. package/core/server/services/content-import/import/completion-email.js +164 -0
  280. package/core/server/services/content-import/import/errors-file.js +36 -0
  281. package/core/server/services/content-import/import/importer.js +160 -53
  282. package/core/server/services/content-import/import/local-media-url.js +63 -0
  283. package/core/server/services/content-import/import/media.js +254 -0
  284. package/core/server/services/content-import/import/post-data.js +0 -1
  285. package/core/server/services/content-import/import/post-link.js +11 -0
  286. package/core/server/services/content-import/import/post-repository.js +25 -3
  287. package/core/server/services/content-import/import/reader.js +9 -2
  288. package/core/server/services/content-import/import/report.js +34 -0
  289. package/core/server/services/content-import/import/row.js +0 -2
  290. package/core/server/services/content-import/import/schema.js +1 -0
  291. package/core/server/services/content-import/import/staged-file.js +29 -0
  292. package/core/server/services/content-import/import/store.js +25 -2
  293. package/core/server/services/content-import/index.js +52 -6
  294. package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
  295. package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
  296. package/core/server/services/custom-redirects/redirects-service.js +1 -1
  297. package/core/server/services/custom-redirects/validation.js +1 -1
  298. package/core/server/services/email-address/email-address-parser.js +30 -38
  299. package/core/server/services/email-address/email-address-service.js +37 -4
  300. package/core/server/services/email-analytics/index.js +2 -7
  301. package/core/server/services/email-service/batch-sending-service.js +0 -4
  302. package/core/server/services/email-service/email-renderer.js +14 -4
  303. package/core/server/services/email-service/email-service-wrapper.js +0 -9
  304. package/core/server/services/email-service/mailgun-email-provider.js +20 -9
  305. package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
  306. package/core/server/services/gifts/gift-email-service.js +0 -1
  307. package/core/server/services/gifts/index.js +3 -3
  308. package/core/server/services/gifts/jobs/index.js +4 -4
  309. package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
  310. package/core/server/services/invitations/accept.js +4 -2
  311. package/core/server/services/jobs/job-service.js +0 -9
  312. package/core/server/services/jobs-service/register-job-handlers.js +21 -11
  313. package/core/server/services/mail/ghost-mailer.js +4 -4
  314. package/core/server/services/member-welcome-emails/service.js +7 -7
  315. package/core/server/services/members/api.js +1 -0
  316. package/core/server/services/members/import-export/csv/parse.js +0 -7
  317. package/core/server/services/members/import-export/import/completion-email.js +2 -5
  318. package/core/server/services/members/import-export/import/row.js +0 -3
  319. package/core/server/services/members/import-export/index.js +4 -11
  320. package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
  321. package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
  322. package/core/server/services/members/jobs/index.js +48 -24
  323. package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
  324. package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
  325. package/core/server/services/members/members-api/members-api.js +4 -6
  326. package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
  327. package/core/server/services/members/members-api/services/member-bread-service.js +34 -62
  328. package/core/server/services/members/members-api/services/payments-service.js +1 -1
  329. package/core/server/services/members/service.js +1 -5
  330. package/core/server/services/members-custom-fields/bindings-service.js +2 -1
  331. package/core/server/services/members-custom-fields/codec.js +3 -4
  332. package/core/server/services/members-custom-fields/definitions-service.js +62 -10
  333. package/core/server/services/members-custom-fields/filter.js +75 -93
  334. package/core/server/services/members-custom-fields/key.js +2 -1
  335. package/core/server/services/members-custom-fields/models.js +1 -1
  336. package/core/server/services/members-custom-fields/serializers.js +3 -5
  337. package/core/server/services/members-custom-fields/values-service.js +50 -28
  338. package/core/server/services/mentions/mention-controller.js +23 -21
  339. package/core/server/services/mentions/process-webmention-job.js +16 -0
  340. package/core/server/services/mentions/service.js +8 -4
  341. package/core/server/services/route-settings/validation-errors.js +1 -1
  342. package/core/server/services/route-settings/yaml-parser.js +1 -1
  343. package/core/server/services/settings/settings-service.js +1 -8
  344. package/core/server/services/settings-helpers/settings-helpers.js +4 -6
  345. package/core/server/services/slack-ping/slack-ping-service.js +1 -1
  346. package/core/server/services/staff/staff-service-emails.js +2 -2
  347. package/core/server/services/stripe/config.js +14 -8
  348. package/core/server/services/stripe/service.js +10 -1
  349. package/core/server/services/stripe/services/checkout/completed-session.js +2 -2
  350. package/core/server/services/stripe/services/checkout/session-options.js +18 -15
  351. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +26 -5
  352. package/core/server/services/stripe/stripe-api.js +2 -0
  353. package/core/server/services/stripe/stripe-service.js +20 -10
  354. package/core/server/services/stripe/webhook-controller.js +10 -0
  355. package/core/server/services/tier-checkout-config/codec.js +9 -5
  356. package/core/server/services/tier-checkout-config/models.js +9 -3
  357. package/core/server/services/tier-checkout-config/queries.js +4 -4
  358. package/core/server/services/tier-checkout-config/serializers.js +16 -10
  359. package/core/server/services/tier-checkout-config/service.js +13 -12
  360. package/core/server/services/update-check/index.js +13 -13
  361. package/core/server/services/update-check/jobs/update-check-job.js +7 -0
  362. package/core/server/services/update-check/update-check-service.js +2 -2
  363. package/core/server/web/admin/controller.js +1 -1
  364. package/core/server/web/api/endpoints/admin/routes.js +19 -16
  365. package/core/shared/config/env/config.testing-mysql.json +1 -1
  366. package/core/shared/labs.js +5 -2
  367. package/package.json +24 -23
  368. package/pnpm-lock.yaml +704 -69
  369. package/pnpm-workspace.yaml +8 -5
  370. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  371. package/core/built/admin/assets/Combination-5fYEzgbs.js +0 -41
  372. package/core/built/admin/assets/account-migration-DRhAehfw.js +0 -1
  373. package/core/built/admin/assets/activitypub/inbox-BluD2ucT.js +0 -1284
  374. package/core/built/admin/assets/activitypub/label-FHSh6ZAw.js +0 -16
  375. package/core/built/admin/assets/activitypub/layout-Cq4NG0Xr.js +0 -1
  376. package/core/built/admin/assets/activitypub/settings-DQDkr06X.js +0 -315
  377. package/core/built/admin/assets/add-integration-modal-BC0jExDZ.js +0 -1
  378. package/core/built/admin/assets/add-newsletter-modal-DchTkA7l.js +0 -1
  379. package/core/built/admin/assets/add-recommendation-modal-DMvaJZKp.js +0 -1
  380. package/core/built/admin/assets/alert-dialog-QhXzdHfc.js +0 -1
  381. package/core/built/admin/assets/analytics-No1DDY3A.js +0 -1
  382. package/core/built/admin/assets/automations-DpUNUdcZ.js +0 -1
  383. package/core/built/admin/assets/bluesky-sharing-Cjrv_f62.js +0 -1
  384. package/core/built/admin/assets/color-picker-BTY_NdEm.js +0 -3
  385. package/core/built/admin/assets/color-picker-field-CPlkzOH0.js +0 -1
  386. package/core/built/admin/assets/combobox-DrMtv_4P.js +0 -1
  387. package/core/built/admin/assets/command-ZdgYJpoI.js +0 -1
  388. package/core/built/admin/assets/comments-kidj60-h.js +0 -1
  389. package/core/built/admin/assets/confirmation-context-BhbmQQEl.js +0 -1
  390. package/core/built/admin/assets/custom-field-type-option-CsGIZk1J.js +0 -10
  391. package/core/built/admin/assets/custom-integration-modal-BY37O_9X.js +0 -1
  392. package/core/built/admin/assets/design-and-theme-modal-DUSKM4uC.js +0 -22
  393. package/core/built/admin/assets/dialog-B44iRwlc.js +0 -1
  394. package/core/built/admin/assets/dirty-confirm-dialog-BxgQgQ6H.js +0 -1
  395. package/core/built/admin/assets/dist-Cy8tfrp_.js +0 -1
  396. package/core/built/admin/assets/domain-Ca6KhoQt.js +0 -1
  397. package/core/built/admin/assets/dropzone-Bb-5zQTk.js +0 -5
  398. package/core/built/admin/assets/edit-profile-BdupLlus.js +0 -1
  399. package/core/built/admin/assets/editor-BP883Lpn.js +0 -8
  400. package/core/built/admin/assets/explore-FB-CimXw.js +0 -1
  401. package/core/built/admin/assets/feed-C1GxsmI2.js +0 -1
  402. package/core/built/admin/assets/filter-sources-D5n5bFA2.js +0 -1
  403. package/core/built/admin/assets/filters-DJEzkMUK.js +0 -1
  404. package/core/built/admin/assets/filters-MZXvdH5D.js +0 -1
  405. package/core/built/admin/assets/first-promoter-modal-CGTGLCr5.js +0 -1
  406. package/core/built/admin/assets/gift-link-modal-B6v0tnRN.js +0 -1
  407. package/core/built/admin/assets/growth-BGAJD1rs.js +0 -3
  408. package/core/built/admin/assets/growth-D6mhcx3q.js +0 -1
  409. package/core/built/admin/assets/history-modal-iKwUY3XR.js +0 -1
  410. package/core/built/admin/assets/index-DjQe-e5s.js +0 -4
  411. package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
  412. package/core/built/admin/assets/index.es-VihPwfeH.js +0 -1
  413. package/core/built/admin/assets/input--W-rCTrX.js +0 -1
  414. package/core/built/admin/assets/invite-user-modal-MdImLCaJ.js +0 -1
  415. package/core/built/admin/assets/koenig-loader-DYZpm6El.js +0 -2
  416. package/core/built/admin/assets/label-picker-cB51xl1r.js +0 -1
  417. package/core/built/admin/assets/layout-c_B_1hax.js +0 -1
  418. package/core/built/admin/assets/loading-indicator-BpFWTVgh.js +0 -1
  419. package/core/built/admin/assets/member-custom-fields-qs0dIkxM.js +0 -1
  420. package/core/built/admin/assets/member-detail-B6uec2a6.js +0 -1
  421. package/core/built/admin/assets/members-BQF3CqhI.js +0 -2
  422. package/core/built/admin/assets/moderation-DY4wF1Q3.js +0 -1
  423. package/core/built/admin/assets/navigation-modal-DX-gNF3X.js +0 -1
  424. package/core/built/admin/assets/newsletter-CyQA7m3m.js +0 -1
  425. package/core/built/admin/assets/newsletter-detail-modal-BDrptuxn.js +0 -1
  426. package/core/built/admin/assets/newsletters-DXuNmC42.js +0 -1
  427. package/core/built/admin/assets/note-Cgo2LCJ6.js +0 -1
  428. package/core/built/admin/assets/notifications-BC50AMku.js +0 -1
  429. package/core/built/admin/assets/offers-container-modal-DWycIMzT.js +0 -1
  430. package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
  431. package/core/built/admin/assets/overview-CVbFtn-k.js +0 -1
  432. package/core/built/admin/assets/overview-YKj7SZaK.js +0 -1
  433. package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
  434. package/core/built/admin/assets/popover-CCy0h5rq.js +0 -1
  435. package/core/built/admin/assets/portal-frame-dc4XKr0e.js +0 -1
  436. package/core/built/admin/assets/portal-modal-BvvdF_B9.js +0 -1
  437. package/core/built/admin/assets/post-analytics-DX470WRG.js +0 -1
  438. package/core/built/admin/assets/post-analytics-header-CXpJmdDv.js +0 -1
  439. package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
  440. package/core/built/admin/assets/preferences-DO0UUWFp.js +0 -5
  441. package/core/built/admin/assets/profile-CxT-0l4d.js +0 -1
  442. package/core/built/admin/assets/radio-group-Bgz60i81.js +0 -1
  443. package/core/built/admin/assets/select-DuDUFdPq.js +0 -1
  444. package/core/built/admin/assets/settings-BjCii7BM.js +0 -1
  445. package/core/built/admin/assets/settings-b8kNzZSQ.js +0 -4
  446. package/core/built/admin/assets/share-modal-BV70mr9k.js +0 -1
  447. package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
  448. package/core/built/admin/assets/slack-modal-Be2_KK-z.js +0 -1
  449. package/core/built/admin/assets/stats-C4reGh9O.js +0 -1
  450. package/core/built/admin/assets/stats-view-DP9pQ62k.js +0 -1
  451. package/core/built/admin/assets/stripe-connect-modal-Z-UT_BGc.js +0 -1
  452. package/core/built/admin/assets/tag-detail-Dc0nTOtU.js +0 -2
  453. package/core/built/admin/assets/tags-BLaXBwnb.js +0 -1
  454. package/core/built/admin/assets/testimonials-modal-sFwRnNLh.js +0 -1
  455. package/core/built/admin/assets/tier-detail-modal-BCFpWwUS.js +0 -1
  456. package/core/built/admin/assets/use-filter-params-CAvfDvf1.js +0 -1
  457. package/core/built/admin/assets/use-growth-stats-D6mZXGhK.js +0 -1
  458. package/core/built/admin/assets/use-post-referrers-DbY-mzci.js +0 -1
  459. package/core/built/admin/assets/use-reply-chain-data-BeQwz8oF.js +0 -1
  460. package/core/built/admin/assets/use-settings-navigation-BbrSUVcf.js +0 -1
  461. package/core/built/admin/assets/use-tinybird-query-B1IMyAcv.js +0 -39
  462. package/core/built/admin/assets/use-tinybird-token-Bow0Zwn8.js +0 -1
  463. package/core/built/admin/assets/user-detail-modal-yipSoQfv.js +0 -1
  464. package/core/built/admin/assets/users-5msE1WMs.js +0 -1
  465. package/core/built/admin/assets/web-CKcXAu86.js +0 -1
  466. package/core/built/admin/assets/web-DR4TqM3E.js +0 -2
  467. package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
  468. package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
  469. package/core/server/services/stripe/services/checkout/allowed-countries.js +0 -267
  470. package/core/server/services/stripe/services/checkout/field-ports.js +0 -34
  471. package/core/server/services/tier-checkout-config/destinations.js +0 -17
  472. package/core/server/services/update-check/run-update-check.js +0 -63
@@ -38,6 +38,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  const moment_timezone_1 = __importDefault(require("moment-timezone"));
40
40
  const post_data_1 = __importStar(require("./post-data"));
41
+ const media_1 = require("./media");
42
+ const content_csv_import_job_1 = __importDefault(require("../jobs/content-csv-import-job"));
41
43
  const errors = require('@tryghost/errors');
42
44
  const logging = require('@tryghost/logging');
43
45
  const tpl = require('@tryghost/tpl');
@@ -49,7 +51,7 @@ const messages = {
49
51
  };
50
52
  function logLifecycle(message) {
51
53
  try {
52
- logging.info(`[Background Job] content-import ${message}`);
54
+ logging.info(`[Background Job] ${content_csv_import_job_1.default.type} ${message}`);
53
55
  }
54
56
  catch {
55
57
  // Observability must not change whether an import is queued or resolves.
@@ -69,21 +71,27 @@ class ContentCSVImporter {
69
71
  _getHtmlToLexical;
70
72
  _getMarkdownToHtml;
71
73
  _getCleanHTML;
72
- _addJob;
74
+ _createMediaInliner;
75
+ _email;
76
+ _dispatchJob;
77
+ _fileStager;
73
78
  _report;
74
79
  _store;
75
80
  _urlForPost;
76
81
  _newRunId;
77
82
  _getTimezone;
78
83
  _now;
79
- constructor({ readRows, prepareSource = async ({ filePath }) => ({ filePath, cleanup: async () => { } }), posts, getHtmlToLexical, getMarkdownToHtml, getCleanHTML, addJob, report, store, urlForPost, newRunId, getTimezone, now = () => new Date(), }) {
84
+ constructor({ readRows, prepareSource = async ({ filePath }) => ({ filePath, cleanup: async () => { } }), posts, getHtmlToLexical, getMarkdownToHtml, getCleanHTML, createMediaInliner, email, dispatchJob, fileStager, report, store, urlForPost, newRunId, getTimezone, now = () => new Date(), }) {
80
85
  this._readRows = readRows;
81
86
  this._prepareSource = prepareSource;
82
87
  this._posts = posts;
83
88
  this._getHtmlToLexical = getHtmlToLexical;
84
89
  this._getMarkdownToHtml = getMarkdownToHtml;
85
90
  this._getCleanHTML = getCleanHTML;
86
- this._addJob = addJob;
91
+ this._createMediaInliner = createMediaInliner;
92
+ this._email = email;
93
+ this._dispatchJob = dispatchJob;
94
+ this._fileStager = fileStager;
87
95
  this._report = report;
88
96
  this._store = store;
89
97
  this._urlForPost = urlForPost;
@@ -92,75 +100,114 @@ class ContentCSVImporter {
92
100
  this._now = now;
93
101
  }
94
102
  async importCSV(request) {
95
- const source = await this._prepareSource(request);
96
- let rows;
103
+ const emailRecipient = request.requestUserEmail ?? (await this._email.getDefaultRecipient());
104
+ let stagedFile;
97
105
  try {
98
- rows = await this._readRows(source.filePath, request.mapping);
106
+ stagedFile = await this._fileStager.stage(request);
99
107
  }
100
108
  catch (error) {
101
- await this.cleanupSource(source.cleanup);
102
109
  throw new errors.ValidationError({
103
110
  message: tpl(messages.unreadableFile),
104
111
  err: error,
105
112
  });
106
113
  }
107
- // Temporary while import state is held in memory: the durable job
108
- // system milestone removes the cap.
109
- if (rows.length > MAX_POSTS) {
114
+ let handedOff = false;
115
+ try {
116
+ const stagedRequest = {
117
+ filePath: stagedFile.path,
118
+ fileName: stagedFile.name,
119
+ mapping: request.mapping,
120
+ requestUserEmail: request.requestUserEmail,
121
+ };
122
+ const { source, preparedRows } = await this.readPreparedRows(stagedRequest);
110
123
  await this.cleanupSource(source.cleanup);
111
- throw new errors.ValidationError({
112
- message: tpl(messages.tooManyPosts, { max: MAX_POSTS }),
124
+ this.assertWithinPostLimit(preparedRows.rows);
125
+ const runId = this._newRunId();
126
+ const importTagNames = buildImportTagNames(runId, this._getTimezone(), this._now());
127
+ this._store.create(runId, preparedRows.rows.length, preparedRows.columns);
128
+ const job = new content_csv_import_job_1.default({
129
+ importId: runId,
130
+ file: stagedFile,
131
+ mapping: request.mapping,
132
+ importTagNames,
133
+ emailRecipient,
113
134
  });
135
+ logLifecycle('queued');
136
+ try {
137
+ await this._dispatchJob(job);
138
+ }
139
+ catch (error) {
140
+ this._store.fail(runId, messageOf(error));
141
+ this._store.release(runId);
142
+ throw error;
143
+ }
144
+ handedOff = true;
145
+ return { importId: runId, total: preparedRows.rows.length };
114
146
  }
115
- const runId = this._newRunId();
116
- const importTagNames = buildImportTagNames(runId, this._getTimezone(), this._now());
117
- this._store.create(runId, rows.length);
118
- logLifecycle('queued');
147
+ finally {
148
+ if (!handedOff) {
149
+ await this.cleanupStagedFile(stagedFile);
150
+ }
151
+ }
152
+ }
153
+ async handle(job) {
154
+ let source;
119
155
  try {
120
- this._addJob({
121
- job: () => this.runImportJob(runId, importTagNames, rows, source),
122
- offloaded: false,
123
- name: 'content-import',
156
+ const prepared = await this.readPreparedRows({
157
+ filePath: job.file.path,
158
+ fileName: job.file.name,
159
+ mapping: job.mapping,
124
160
  });
161
+ source = prepared.source;
162
+ this.assertWithinPostLimit(prepared.preparedRows.rows);
163
+ await this.processRows(job.importId, job.importTagNames, prepared.preparedRows.rows, prepared.source);
125
164
  }
126
165
  catch (error) {
127
- this._store.fail(runId, messageOf(error));
128
- await this.cleanupSource(source.cleanup);
166
+ this._store.fail(job.importId, messageOf(error));
129
167
  throw error;
130
168
  }
131
- return { importId: runId, total: rows.length };
169
+ finally {
170
+ if (source) {
171
+ await this.cleanupSource(source.cleanup);
172
+ }
173
+ const run = this._store.get(job.importId);
174
+ if (run) {
175
+ await this.settle(() => this._email.send(run, job.emailRecipient));
176
+ }
177
+ this._store.release(job.importId);
178
+ await this.cleanupStagedFile(job.file);
179
+ }
180
+ }
181
+ allSettled() {
182
+ return this._store.allSettled();
132
183
  }
133
- // Must resolve in every case: the job manager reads a rejected inline job as a
134
- // defect in the job itself, and there is no retry behind it.
135
- async runImportJob(runId, importTagNames, rows, source) {
136
- const startedAt = Date.now();
137
- logLifecycle('started');
184
+ async processRows(runId, importTagNames, rows, source) {
138
185
  let urlFailureCount = 0;
139
186
  let firstUrlFailure;
140
- let failed = false;
141
187
  try {
142
188
  if (source.assets) {
143
189
  await source.assets.store();
144
- source.assets.rewriteRows(rows);
190
+ source.assets.rewriteRows(rows.map(({ data }) => data));
145
191
  }
146
192
  const htmlToLexical = this._getHtmlToLexical();
147
193
  const markdownToHtml = this._getMarkdownToHtml();
148
194
  const cleanHTML = this._getCleanHTML();
195
+ const media = this._createMediaInliner();
149
196
  let successfulWrites = 0;
150
- let failedWrites = 0;
151
- let firstWriteFailure;
152
- for (const [index, row] of rows.entries()) {
153
- const line = index + 2;
197
+ let failedRows = 0;
198
+ let firstRowFailure;
199
+ for (const preparedRow of rows) {
200
+ const { data: row, source: sourceCells, line } = preparedRow;
154
201
  let data;
155
202
  try {
156
203
  data = (0, post_data_1.default)(row, htmlToLexical, importTagNames, markdownToHtml, cleanHTML);
157
204
  }
158
205
  catch (error) {
159
206
  if (error instanceof post_data_1.RowSkipped) {
160
- this._store.record(runId, {
207
+ this.recordOutcome(runId, sourceCells, {
161
208
  line,
162
209
  title: row.title || null,
163
- status: 'skipped',
210
+ status: 'failed',
164
211
  reason: messageOf(error),
165
212
  });
166
213
  continue;
@@ -169,6 +216,26 @@ class ContentCSVImporter {
169
216
  // failure. Stop the run before misclassifying it as a lost write.
170
217
  throw error;
171
218
  }
219
+ try {
220
+ await media.inline(data);
221
+ }
222
+ catch (error) {
223
+ if (error instanceof media_1.MediaInliningFailure) {
224
+ if (failedRows === 0) {
225
+ firstRowFailure = error;
226
+ }
227
+ failedRows += 1;
228
+ this.recordOutcome(runId, sourceCells, {
229
+ line,
230
+ title: row.title,
231
+ status: 'failed',
232
+ reason: messageOf(error),
233
+ mediaFailures: error.failures,
234
+ });
235
+ continue;
236
+ }
237
+ throw error;
238
+ }
172
239
  let post;
173
240
  let writeStatus;
174
241
  let warnings;
@@ -184,16 +251,18 @@ class ContentCSVImporter {
184
251
  context: { internal: true },
185
252
  }, {
186
253
  sourceUpdatedAt: row.updated_at,
254
+ runTagName: importTagNames[1],
187
255
  authorNames: row.authors,
188
256
  authorEmails: row.author_emails,
189
257
  tagNames: row.tags,
190
258
  });
191
259
  if (result.status === 'skipped') {
192
- this._store.record(runId, {
260
+ this.recordOutcome(runId, sourceCells, {
193
261
  line,
194
262
  title: row.title,
195
263
  status: 'skipped',
196
264
  reason: result.reason,
265
+ duplicate: result.duplicate,
197
266
  });
198
267
  continue;
199
268
  }
@@ -203,11 +272,11 @@ class ContentCSVImporter {
203
272
  successfulWrites += 1;
204
273
  }
205
274
  catch (error) {
206
- if (failedWrites === 0) {
207
- firstWriteFailure = error;
275
+ if (failedRows === 0) {
276
+ firstRowFailure = error;
208
277
  }
209
- failedWrites += 1;
210
- this._store.record(runId, {
278
+ failedRows += 1;
279
+ this.recordOutcome(runId, sourceCells, {
211
280
  line,
212
281
  title: row.title,
213
282
  status: 'failed',
@@ -220,6 +289,7 @@ class ContentCSVImporter {
220
289
  title: row.title,
221
290
  status: writeStatus,
222
291
  postId: post.id,
292
+ postType: data.type,
223
293
  ...(warnings.length > 0 ? { warnings } : {}),
224
294
  };
225
295
  try {
@@ -231,32 +301,53 @@ class ContentCSVImporter {
231
301
  }
232
302
  urlFailureCount += 1;
233
303
  }
234
- this._store.record(runId, outcome);
304
+ this.recordOutcome(runId, sourceCells, outcome);
235
305
  }
236
- if (failedWrites > 0 && successfulWrites === 0) {
306
+ if (failedRows > 0 && successfulWrites === 0) {
237
307
  this._report(new errors.InternalServerError({
238
308
  message: tpl(messages.allWritesFailed, {
239
- count: failedWrites,
240
- postNoun: failedWrites === 1 ? 'post' : 'posts',
309
+ count: failedRows,
310
+ postNoun: failedRows === 1 ? 'post' : 'posts',
241
311
  }),
242
- err: firstWriteFailure,
312
+ err: firstRowFailure,
243
313
  }));
244
314
  }
245
315
  this.reportUrlFailures(urlFailureCount, firstUrlFailure);
246
316
  this._store.finish(runId);
247
317
  }
248
318
  catch (error) {
249
- failed = true;
250
319
  this.reportUrlFailures(urlFailureCount, firstUrlFailure);
251
- this._report(error);
252
- this._store.fail(runId, messageOf(error));
320
+ throw error;
253
321
  }
254
- finally {
322
+ }
323
+ async readPreparedRows(request) {
324
+ const source = await this._prepareSource(request);
325
+ try {
326
+ const result = await this._readRows(source.filePath, request.mapping);
327
+ const preparedRows = Array.isArray(result)
328
+ ? { columns: [], rows: result.map((data, index) => ({ data, line: index + 2 })) }
329
+ : result;
330
+ return { source, preparedRows };
331
+ }
332
+ catch (error) {
255
333
  await this.cleanupSource(source.cleanup);
256
- const outcome = failed ? 'failed after' : 'completed in';
257
- logLifecycle(`${outcome} ${Date.now() - startedAt}ms`);
334
+ throw new errors.ValidationError({
335
+ message: tpl(messages.unreadableFile),
336
+ err: error,
337
+ });
338
+ }
339
+ }
340
+ assertWithinPostLimit(rows) {
341
+ // Temporary while import state is held in memory: M8 removes the cap.
342
+ if (rows.length > MAX_POSTS) {
343
+ throw new errors.ValidationError({
344
+ message: tpl(messages.tooManyPosts, { max: MAX_POSTS }),
345
+ });
258
346
  }
259
347
  }
348
+ recordOutcome(runId, source, outcome) {
349
+ this._store.record(runId, source ? { ...outcome, source } : outcome);
350
+ }
260
351
  reportUrlFailures(count, firstFailure) {
261
352
  if (count > 0) {
262
353
  this._report(new errors.InternalServerError({
@@ -276,6 +367,22 @@ class ContentCSVImporter {
276
367
  this._report(error);
277
368
  }
278
369
  }
370
+ async cleanupStagedFile(file) {
371
+ try {
372
+ await this._fileStager.remove(file);
373
+ }
374
+ catch (error) {
375
+ this._report(error);
376
+ }
377
+ }
378
+ async settle(operation) {
379
+ try {
380
+ await operation();
381
+ }
382
+ catch (error) {
383
+ this._report(error);
384
+ }
385
+ }
279
386
  }
280
387
  function messageOf(error) {
281
388
  if (error &&
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isLocalMediaUrl = isLocalMediaUrl;
4
+ const CONTENT_PATH_PREFIXES = ['/content/images', '/content/media', '/content/files'];
5
+ function normalizedPathPrefix(value) {
6
+ if (!value.startsWith('/')) {
7
+ return `/${value}`.replace(/\/+$/, '');
8
+ }
9
+ return value.replace(/\/+$/, '');
10
+ }
11
+ function pathHasPrefix(pathname, prefix) {
12
+ return pathname === prefix || pathname.startsWith(`${prefix}/`);
13
+ }
14
+ function isContentPath(pathname, subdirs) {
15
+ const normalizedPathname = normalizedPathPrefix(pathname);
16
+ const prefixes = subdirs.flatMap((subdir) => {
17
+ const normalizedSubdir = normalizedPathPrefix(subdir);
18
+ return CONTENT_PATH_PREFIXES.map((prefix) => `${normalizedSubdir}${prefix}`);
19
+ });
20
+ return [...CONTENT_PATH_PREFIXES, ...prefixes].some((prefix) => pathHasPrefix(normalizedPathname, prefix));
21
+ }
22
+ function parseUrl(value) {
23
+ try {
24
+ return new URL(value.startsWith('//') ? `https:${value}` : value);
25
+ }
26
+ catch {
27
+ return undefined;
28
+ }
29
+ }
30
+ function matchesBaseUrl(source, baseUrl) {
31
+ const base = parseUrl(baseUrl.trim());
32
+ if (!base || source.host !== base.host) {
33
+ return false;
34
+ }
35
+ const basePath = normalizedPathPrefix(base.pathname);
36
+ return basePath === '' || basePath === '/' || pathHasPrefix(source.pathname, basePath);
37
+ }
38
+ /**
39
+ * Returns whether a media reference already belongs to this Ghost site or one
40
+ * of its configured asset hosts. This only classifies URLs; it never checks
41
+ * whether the referenced file exists.
42
+ */
43
+ function isLocalMediaUrl(sourceUrl, options) {
44
+ const value = sourceUrl.trim();
45
+ if (value.startsWith('__GHOST_URL__')) {
46
+ return true;
47
+ }
48
+ if (value.startsWith('/') && !value.startsWith('//')) {
49
+ return isContentPath(value, [options.subdir]);
50
+ }
51
+ const source = parseUrl(value);
52
+ if (!source) {
53
+ return false;
54
+ }
55
+ if (options.assetBaseUrls.some((baseUrl) => typeof baseUrl === 'string' && matchesBaseUrl(source, baseUrl))) {
56
+ return true;
57
+ }
58
+ const site = parseUrl(options.siteUrl);
59
+ if (!site || source.host !== site.host) {
60
+ return false;
61
+ }
62
+ return isContentPath(source.pathname, [options.subdir, site.pathname]);
63
+ }
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostMediaInliner = exports.MediaInliningFailure = void 0;
4
+ exports.isBlockedMediaUrl = isBlockedMediaUrl;
5
+ const cheerio = require('cheerio');
6
+ class MediaInliningFailure extends Error {
7
+ failures;
8
+ constructor(failures) {
9
+ const noun = failures.length === 1 ? 'file' : 'files';
10
+ super(`Could not import ${failures.length} media ${noun}.`);
11
+ this.name = 'MediaInliningFailure';
12
+ this.failures = failures;
13
+ }
14
+ }
15
+ exports.MediaInliningFailure = MediaInliningFailure;
16
+ const DIRECT_MEDIA_FIELDS = {
17
+ image: ['src'],
18
+ audio: ['src', 'thumbnailSrc'],
19
+ video: ['src', 'thumbnailSrc', 'customThumbnailSrc'],
20
+ file: ['src'],
21
+ product: ['productImageSrc'],
22
+ header: ['backgroundImageSrc'],
23
+ signup: ['backgroundImageSrc'],
24
+ 'call-to-action': ['imageUrl'],
25
+ bookmark: ['metadata.icon', 'metadata.thumbnail'],
26
+ embed: ['metadata.thumbnail_url'],
27
+ 'before-after': ['beforeImage.src', 'afterImage.src'],
28
+ };
29
+ const HTML_MEDIA_FIELDS = {
30
+ html: ['html'],
31
+ email: ['html'],
32
+ 'email-cta': ['html'],
33
+ toggle: ['heading', 'content'],
34
+ image: ['caption'],
35
+ gallery: ['caption'],
36
+ video: ['caption'],
37
+ product: ['productTitle', 'productDescription'],
38
+ header: ['header', 'subheader'],
39
+ bookmark: ['caption'],
40
+ codeblock: ['caption'],
41
+ };
42
+ const MARKDOWN_MEDIA_FIELDS = {
43
+ markdown: ['markdown'],
44
+ };
45
+ const BLOCKED_MEDIA_DOMAINS = ['images.unsplash.com', 'gravatar.com'];
46
+ function isRecord(value) {
47
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
48
+ }
49
+ function isRemoteMediaUrl(value) {
50
+ return /^(?:https?:)?\/\//i.test(value.trim());
51
+ }
52
+ function isBlockedMediaUrl(value) {
53
+ try {
54
+ const url = new URL(value.trim().replace(/^\/\//, 'https://'));
55
+ return BLOCKED_MEDIA_DOMAINS.some((domain) => url.hostname === domain || url.hostname.endsWith(`.${domain}`));
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }
61
+ function getPath(record, path) {
62
+ return path.split('.').reduce((value, part) => {
63
+ return isRecord(value) ? value[part] : undefined;
64
+ }, record);
65
+ }
66
+ function setPath(record, path, value) {
67
+ const parts = path.split('.');
68
+ const leaf = parts.pop();
69
+ let target = record;
70
+ for (const part of parts) {
71
+ target = target[part];
72
+ }
73
+ target[leaf] = value;
74
+ }
75
+ async function replaceAsync(input, pattern, replacer) {
76
+ let result = '';
77
+ let lastIndex = 0;
78
+ for (const match of input.matchAll(pattern)) {
79
+ const index = match.index;
80
+ result += input.slice(lastIndex, index);
81
+ result += await replacer(match);
82
+ lastIndex = index + match[0].length;
83
+ }
84
+ return result + input.slice(lastIndex);
85
+ }
86
+ class PostMediaInliner {
87
+ _media;
88
+ _isLocalMediaUrl;
89
+ _cache = new Map();
90
+ _failures = new Map();
91
+ constructor({ media, isLocalMediaUrl, }) {
92
+ this._media = media;
93
+ this._isLocalMediaUrl = isLocalMediaUrl;
94
+ }
95
+ async inline(data) {
96
+ this._failures = new Map();
97
+ if (data.feature_image) {
98
+ data.feature_image = await this.inlineUrl(data.feature_image);
99
+ }
100
+ if (data.posts_meta?.og_image) {
101
+ data.posts_meta.og_image = await this.inlineUrl(data.posts_meta.og_image);
102
+ }
103
+ if (data.posts_meta?.twitter_image) {
104
+ data.posts_meta.twitter_image = await this.inlineUrl(data.posts_meta.twitter_image);
105
+ }
106
+ if (data.lexical) {
107
+ data.lexical = await this.inlineLexical(data.lexical);
108
+ }
109
+ if (this._failures.size > 0) {
110
+ throw new MediaInliningFailure([...this._failures.values()]);
111
+ }
112
+ }
113
+ async inlineUrl(sourceUrl) {
114
+ if (!isRemoteMediaUrl(sourceUrl) ||
115
+ isBlockedMediaUrl(sourceUrl) ||
116
+ this._isLocalMediaUrl(sourceUrl)) {
117
+ return sourceUrl;
118
+ }
119
+ let resultPromise = this._cache.get(sourceUrl);
120
+ if (!resultPromise) {
121
+ resultPromise = this._media.importUrl(sourceUrl);
122
+ this._cache.set(sourceUrl, resultPromise);
123
+ }
124
+ const result = await resultPromise;
125
+ if (result.status === 'failed') {
126
+ this.recordFailure(sourceUrl, result.reason);
127
+ return sourceUrl;
128
+ }
129
+ return result.storedUrl;
130
+ }
131
+ recordFailure(sourceUrl, reason) {
132
+ if (!this._failures.has(sourceUrl)) {
133
+ this._failures.set(sourceUrl, { sourceUrl, reason });
134
+ }
135
+ }
136
+ async inlineLexical(serializedLexical) {
137
+ const lexical = JSON.parse(serializedLexical);
138
+ if (!isRecord(lexical) || !isRecord(lexical.root) || !Array.isArray(lexical.root.children)) {
139
+ return serializedLexical;
140
+ }
141
+ await this.inlineLexicalChildren(lexical.root.children);
142
+ return JSON.stringify(lexical);
143
+ }
144
+ async inlineLexicalChildren(children) {
145
+ for (const child of children) {
146
+ if (!isRecord(child)) {
147
+ continue;
148
+ }
149
+ const type = typeof child.type === 'string' ? child.type : '';
150
+ for (const path of DIRECT_MEDIA_FIELDS[type] ?? []) {
151
+ const value = getPath(child, path);
152
+ if (typeof value === 'string' && value) {
153
+ setPath(child, path, await this.inlineUrl(value));
154
+ }
155
+ }
156
+ if (type === 'gallery' && Array.isArray(child.images)) {
157
+ for (const image of child.images) {
158
+ if (isRecord(image) && typeof image.src === 'string' && image.src) {
159
+ image.src = await this.inlineUrl(image.src);
160
+ }
161
+ }
162
+ }
163
+ for (const path of HTML_MEDIA_FIELDS[type] ?? []) {
164
+ const value = getPath(child, path);
165
+ if (typeof value === 'string' && value) {
166
+ setPath(child, path, await this.inlineHtml(value));
167
+ }
168
+ }
169
+ for (const path of MARKDOWN_MEDIA_FIELDS[type] ?? []) {
170
+ const value = getPath(child, path);
171
+ if (typeof value === 'string' && value) {
172
+ setPath(child, path, await this.inlineMarkdown(value));
173
+ }
174
+ }
175
+ if (Array.isArray(child.children)) {
176
+ await this.inlineLexicalChildren(child.children);
177
+ }
178
+ }
179
+ }
180
+ async inlineHtml(html) {
181
+ const $ = cheerio.load(html, { decodeEntities: false }, false);
182
+ const attributes = [
183
+ ['img[src]', 'src'],
184
+ ['img[data-src]', 'data-src'],
185
+ ['video[src]', 'src'],
186
+ ['video[poster]', 'poster'],
187
+ ['audio[src]', 'src'],
188
+ ['source[src]', 'src'],
189
+ ];
190
+ for (const [selector, attribute] of attributes) {
191
+ for (const element of $(selector).toArray()) {
192
+ const value = $(element).attr(attribute);
193
+ if (value) {
194
+ $(element).attr(attribute, await this.inlineUrl(value));
195
+ }
196
+ }
197
+ }
198
+ for (const element of $('[srcset]').toArray()) {
199
+ const value = $(element).attr('srcset');
200
+ if (value) {
201
+ $(element).attr('srcset', await this.inlineSrcset(value));
202
+ }
203
+ }
204
+ for (const element of $('[style]').toArray()) {
205
+ const value = $(element).attr('style');
206
+ if (value) {
207
+ $(element).attr('style', await this.inlineCss(value));
208
+ }
209
+ }
210
+ for (const element of $('style').toArray()) {
211
+ const value = $(element).html();
212
+ if (value) {
213
+ $(element).html(await this.inlineCss(value));
214
+ }
215
+ }
216
+ return $.root().html();
217
+ }
218
+ async inlineSrcset(srcset) {
219
+ if (srcset.trimStart().startsWith('data:')) {
220
+ return srcset;
221
+ }
222
+ const candidates = srcset.split(',');
223
+ const inlined = [];
224
+ for (const candidate of candidates) {
225
+ const match = candidate.match(/^(\s*)(\S+)(.*)$/s);
226
+ if (!match) {
227
+ inlined.push(candidate);
228
+ continue;
229
+ }
230
+ const [, leading, sourceUrl, descriptor] = match;
231
+ inlined.push(`${leading}${await this.inlineUrl(sourceUrl)}${descriptor}`);
232
+ }
233
+ return inlined.join(',');
234
+ }
235
+ inlineCss(css) {
236
+ return replaceAsync(css, /url\(\s*(?:(["'])(.*?)\1|([^)'"\s][^)]*?))\s*\)/gi, async (match) => {
237
+ const sourceUrl = (match[2] ?? match[3]).trim();
238
+ if (!sourceUrl) {
239
+ return match[0];
240
+ }
241
+ const storedUrl = await this.inlineUrl(sourceUrl);
242
+ return match[0].replace(sourceUrl, storedUrl);
243
+ });
244
+ }
245
+ async inlineMarkdown(markdown) {
246
+ let result = await replaceAsync(markdown, /!\[[^\]]*]\(\s*(?:<([^>\s]+)>|((?:https?:)?\/\/[^\s)]+))(?=[\s)])/gi, async (match) => {
247
+ const sourceUrl = (match[1] ?? match[2]);
248
+ return match[0].replace(sourceUrl, await this.inlineUrl(sourceUrl));
249
+ });
250
+ result = await replaceAsync(result, /<(?:img|video|audio|source)\b[^>]*>/gi, async (match) => this.inlineHtml(match[0]));
251
+ return replaceAsync(result, /<style\b[^>]*>[\s\S]*?<\/style>/gi, async (match) => this.inlineHtml(match[0]));
252
+ }
253
+ }
254
+ exports.PostMediaInliner = PostMediaInliner;
@@ -33,7 +33,6 @@ const META_FIELDS = [
33
33
  'twitter_image',
34
34
  'twitter_title',
35
35
  'twitter_description',
36
- 'frontmatter',
37
36
  ];
38
37
  function buildPostData(row, htmlToLexical, importTagNames, markdownToHtml, cleanHTML) {
39
38
  const check = row_1.importableRowSchema.safeParse(row);