ghost 6.54.0 → 6.55.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 (327) 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-scheduling-0.2.0.tgz +0 -0
  4. package/components/tryghost-adapter-base-sso-0.1.1.tgz +0 -0
  5. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  6. package/components/tryghost-kg-default-cards-10.3.3.tgz +0 -0
  7. package/core/boot.js +3 -6
  8. package/core/built/admin/assets/{account-migration-DLvVA5yq.js → account-migration-sjHLx5dy.js} +1 -1
  9. package/core/built/admin/assets/activitypub/{account-migration-DHbZcxGM.js → account-migration-DoYXtnZ8.js} +4 -4
  10. package/core/built/admin/assets/activitypub/activitypub.js +2 -2
  11. package/core/built/admin/assets/activitypub/{bluesky-sharing-zfxUey_L.js → bluesky-sharing-Bxeh6MKW.js} +4 -4
  12. package/core/built/admin/assets/activitypub/{dist-BqkDUQxJ2.js → dist-ByFmDSNP2.js} +64 -63
  13. package/core/built/admin/assets/activitypub/{dist-Ba_QxHHl.js → dist-D8sFfdpC.js} +2 -2
  14. package/core/built/admin/assets/activitypub/{domain-CmwSZLHK.js → domain-CWueFW6q.js} +5 -5
  15. package/core/built/admin/assets/activitypub/{edit-profile-CXdwNmVG.js → edit-profile-BGxPU7N5.js} +3 -3
  16. package/core/built/admin/assets/activitypub/{explore-DfbjzGM1.js → explore-DBK-u0Ch.js} +3 -3
  17. package/core/built/admin/assets/activitypub/{feed-DSEBJOqf.js → feed-Bcir5RQZ.js} +3 -3
  18. package/core/built/admin/assets/activitypub/{field-CY7XVcx6.js → field-BV-CIT3d.js} +2 -2
  19. package/core/built/admin/assets/activitypub/{inbox-DtQ0kytT.js → inbox-yC0nfvzl.js} +4 -4
  20. package/core/built/admin/assets/activitypub/{label-Dw96GQ7u.js → label-DTRS9TDk.js} +2 -2
  21. package/core/built/admin/assets/activitypub/layout-qx-bUL1k.js +1 -0
  22. package/core/built/admin/assets/activitypub/{moderation-Dg_-I-8C.js → moderation-Dwl9t0pb.js} +4 -4
  23. package/core/built/admin/assets/activitypub/{note-Cy1-uKMY.js → note-B-zKsZ7r.js} +3 -3
  24. package/core/built/admin/assets/activitypub/{notifications-B_fvoLIM.js → notifications-DjJZD54t.js} +3 -3
  25. package/core/built/admin/assets/activitypub/{preferences-ByJseZp6.js → preferences-CoU8vs6d.js} +6 -6
  26. package/core/built/admin/assets/activitypub/{profile-BFtbnIjz.js → profile-BAsaJekx.js} +6 -6
  27. package/core/built/admin/assets/activitypub/{routes-Dh3xXfce.js → routes-CLH3OVTP.js} +28 -25
  28. package/core/built/admin/assets/activitypub/{settings-DTgqJPxM.js → settings-DA6pNJ-Q.js} +3 -3
  29. package/core/built/admin/assets/activitypub/{site-CdL9ZLqm.js → site-CQD42Pw5.js} +2 -2
  30. package/core/built/admin/assets/activitypub/{tabs-ogqwoBlb.js → tabs-Cg0saow1.js} +7 -7
  31. package/core/built/admin/assets/activitypub/{use-reply-chain-data-CxonteFD.js → use-reply-chain-data-Br4aOWOh.js} +2 -2
  32. package/core/built/admin/assets/audience-DjEWNhp3.js +1 -0
  33. package/core/built/admin/assets/{automated-emails-Cn87L5Md.js → automated-emails-DRy7qY-J.js} +2 -2
  34. package/core/built/admin/assets/{automations-BP_aHamJ.js → automations-Bx3VcFIL.js} +1 -1
  35. package/core/built/admin/assets/{automations-B7-y3dXt.js → automations-DhKeS_U5.js} +1 -1
  36. package/core/built/admin/assets/{bluesky-sharing-Bh36XPh4.js → bluesky-sharing-ClMd0-Ft.js} +1 -1
  37. package/core/built/admin/assets/{breadcrumb-D34YWnaw.js → breadcrumb-BD0U2ygg.js} +1 -1
  38. package/core/built/admin/assets/{chart-helpers-DbklaJw9.js → chart-helpers-fjQKRVyY.js} +1 -1
  39. package/core/built/admin/assets/checkbox-CWa28lgO.js +1 -0
  40. package/core/built/admin/assets/{chunk.962.b73442b07be930bb5d85.js → chunk.211.6f7328d63c41536451b3.js} +737 -559
  41. package/core/built/admin/assets/{chunk.962.b73442b07be930bb5d85.js.LICENSE.txt → chunk.211.6f7328d63c41536451b3.js.LICENSE.txt} +2 -0
  42. package/core/built/admin/assets/{chunk.589.096f4d0bb775e5229aa9.js → chunk.481.6c7395a49484bb4583aa.js} +41 -38
  43. package/core/built/admin/assets/chunk.524.cffd399783a519e404a9.js +25 -0
  44. package/core/built/admin/assets/chunk.582.eebf0d0b2d202bb746a5.js +27 -0
  45. package/core/built/admin/assets/code-editor-view-CCr0rBWS.js +1 -0
  46. package/core/built/admin/assets/comments-DyUSMUdj.js +1 -0
  47. package/core/built/admin/assets/{date-range-select-B5vSsrpx.js → date-range-select-BFp58EMk.js} +1 -1
  48. package/core/built/admin/assets/{disabled-sources-indicator-NkOIoMue.js → disabled-sources-indicator-CUxMfiPa.js} +1 -1
  49. package/core/built/admin/assets/dist-2Tnz2Yfq.js +1 -0
  50. package/core/built/admin/assets/dist-CjY-f5Z1.js +1 -0
  51. package/core/built/admin/assets/dist-DIC8yz5C.js +1 -0
  52. package/core/built/admin/assets/domain-C0bV2UV8.js +1 -0
  53. package/core/built/admin/assets/dropzone-DlK-K2DQ.js +5 -0
  54. package/core/built/admin/assets/{edit-profile-rvDGrS8J.js → edit-profile-BKT-REJw.js} +1 -1
  55. package/core/built/admin/assets/editor-Dp865O-4.js +8 -0
  56. package/core/built/admin/assets/{explore-BZAZOg5X.js → explore-ClUpJZOp.js} +1 -1
  57. package/core/built/admin/assets/{feed-CFV8xDw9.js → feed-DF92dUMP.js} +1 -1
  58. package/core/built/admin/assets/field-Do7lieBA.js +1 -0
  59. package/core/built/admin/assets/{filter-sources-Fx8wiYYw.js → filter-sources-BV2rnpfA.js} +1 -1
  60. package/core/built/admin/assets/filters-CUXJ2Nm9.js +1 -0
  61. package/core/built/admin/assets/{filters-CGX_pf2N.js → filters-DfbIWc_l.js} +1 -1
  62. package/core/built/admin/assets/{ghost-3063eae29e6c9cc6d6e7131928a27da0.css → ghost-a9c788f6f0b1ea6cf0f14ca4b13f4496.css} +1 -1
  63. package/core/built/admin/assets/{ghost-b1dce91ad3232cc259ee5fbbf9526243.js → ghost-c4057474943effc568c5659ccc4909d7.js} +407 -406
  64. package/core/built/admin/assets/{ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css → ghost-dark-db36d795d21c61426837df40af270966.css} +1 -1
  65. package/core/built/admin/assets/gift-link-modal-f9VIMNDv.js +1 -0
  66. package/core/built/admin/assets/{gift-links-nBxJjZiQ.js → gift-links-CsUhefWG.js} +1 -1
  67. package/core/built/admin/assets/growth-B3I6gNLm.js +1 -0
  68. package/core/built/admin/assets/{Growth-CSaHoSVD.js → growth-CVw1My4S.js} +2 -2
  69. package/core/built/admin/assets/{hooks-BApwwBE0.js → hooks-CixO01lL.js} +1 -1
  70. package/core/built/admin/assets/{inbox-BRp1_aaC.js → inbox-CFBSu4Ed.js} +12 -12
  71. package/core/built/admin/assets/index-9Cw8z3rA.css +1 -0
  72. package/core/built/admin/assets/index-BGG7NckO.js +67 -0
  73. package/core/built/admin/assets/input-group-BSgG_lVw.js +1 -0
  74. package/core/built/admin/assets/input-surface-BpAjZXY5.js +1 -0
  75. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +974 -937
  76. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +28 -28
  77. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  78. package/core/built/admin/assets/{koenig-lexical-CM7UFNdL.js → koenig-lexical-f8vHRYvz.js} +28 -28
  79. package/core/built/admin/assets/{kpi-card-BrGH6FsT.js → kpi-card-DSap9rAy.js} +1 -1
  80. package/core/built/admin/assets/{kpi-card-CIGyijjx.js → kpi-card-DU0rn9Cj.js} +1 -1
  81. package/core/built/admin/assets/{kpi-helpers-_HRRsklE.js → kpi-helpers-Dz33AV6h.js} +1 -1
  82. package/core/built/admin/assets/{kpi-tabs-BSvh9eoq.js → kpi-tabs-BtTTrKvJ.js} +1 -1
  83. package/core/built/admin/assets/{label-BOR9XdKl.js → label-DS8Mi6G5.js} +1 -1
  84. package/core/built/admin/assets/label-picker-1DvSuLA1.js +1 -0
  85. package/core/built/admin/assets/labels-CDSUt4J_.js +1 -0
  86. package/core/built/admin/assets/layout-yQEi2qDM.js +1 -0
  87. package/core/built/admin/assets/{link-helpers-tOlxmuH5.js → link-helpers-7EYqvvHs.js} +1 -1
  88. package/core/built/admin/assets/member-custom-fields-yOMHyAg9.js +1 -0
  89. package/core/built/admin/assets/member-detail-BAq7gDaa.js +1 -0
  90. package/core/built/admin/assets/members-CQpVFJu4.js +10 -0
  91. package/core/built/admin/assets/modals-ReORvWnu.js +31 -0
  92. package/core/built/admin/assets/moderation-DySbgyUS.js +1 -0
  93. package/core/built/admin/assets/newsletter-CJQvtHqN.js +1 -0
  94. package/core/built/admin/assets/{Newsletters-C5cs6FGo.js → newsletters-B3QQXfGT.js} +1 -1
  95. package/core/built/admin/assets/{newsletters-D1jbtV-h.js → newsletters-BXJbJgA-.js} +1 -1
  96. package/core/built/admin/assets/note-C8kxrz6w.js +1 -0
  97. package/core/built/admin/assets/notifications-CgtSfX7t.js +1 -0
  98. package/core/built/admin/assets/{offers-CrY6nSRR.js → offers-DEniVRD5.js} +1 -1
  99. package/core/built/admin/assets/onboarding-route-4qtziA9d.js +1 -0
  100. package/core/built/admin/assets/overview-Bf2sbznq.js +1 -0
  101. package/core/built/admin/assets/overview-CBfePxcr.js +1 -0
  102. package/core/built/admin/assets/{page-header-C0jVxtS8.js → page-header-B3Wb9Jqv.js} +1 -1
  103. package/core/built/admin/assets/{pages-BbNWFcGj.js → pages-B4goRPUn.js} +1 -1
  104. package/core/built/admin/assets/{post-analytics-Iw7dk1mT.js → post-analytics-We-ko5Cb.js} +1 -1
  105. package/core/built/admin/assets/post-analytics-header-Bmc9su6q.js +1 -0
  106. package/core/built/admin/assets/post-analytics-provider-B6UynTGb.js +1 -0
  107. package/core/built/admin/assets/{post-share-modal-DBfKl2GZ.js → post-share-modal-DFfO93_0.js} +1 -1
  108. package/core/built/admin/assets/{posts-EWpZIjkr.js → posts-DhXE7b6r.js} +1 -1
  109. package/core/built/admin/assets/{preferences-D4EANGoc.js → preferences-DJPfHEGu.js} +2 -2
  110. package/core/built/admin/assets/profile-DqBQp-gT.js +1 -0
  111. package/core/built/admin/assets/{referrers-BCfFYSHc.js → referrers-pmJT4k3-.js} +1 -1
  112. package/core/built/admin/assets/select-C5_xEt5b.js +1 -0
  113. package/core/built/admin/assets/settings-BwiVIXau.js +4 -0
  114. package/core/built/admin/assets/{settings-Bz3RZRmE.js → settings-WXNeWyU1.js} +1 -1
  115. package/core/built/admin/assets/shade-app-B3heOAfz-CGXQwWeO.js +3 -0
  116. package/core/built/admin/assets/{share-modal-CkdTTMJd.js → share-modal-DsgW3wbg.js} +1 -1
  117. package/core/built/admin/assets/social-urls-BQPFEk1_.js +8 -0
  118. package/core/built/admin/assets/{sort-button-DZp9Y2r1.js → sort-button-Bb_FCl7e.js} +1 -1
  119. package/core/built/admin/assets/{source-icon-CHr9qJ2Y.js → source-icon-BeaRxUn9.js} +1 -1
  120. package/core/built/admin/assets/{stats-DGoXZxWE.js → stats-Bjj_kmJ1.js} +1 -1
  121. package/core/built/admin/assets/{stats-view-D2-1L0ms.js → stats-view-BxPbW6K1.js} +1 -1
  122. package/core/built/admin/assets/{step-1-RdahbwyG.js → step-1-B1e3-1F8.js} +1 -1
  123. package/core/built/admin/assets/{step-2-D83PeRwd.js → step-2-C5WaeBJo.js} +1 -1
  124. package/core/built/admin/assets/{step-3-p_Op4wv4.js → step-3-B46iVPwu.js} +2 -2
  125. package/core/built/admin/assets/switch-z5Y6Uzt6.js +1 -0
  126. package/core/built/admin/assets/{table-B8LgTQJZ.js → table-CB-4_HBJ.js} +1 -1
  127. package/core/built/admin/assets/tabs-CCEgKYzq.js +1 -0
  128. package/core/built/admin/assets/{tags-B4l891z2.js → tags-Cg2VJGmG.js} +1 -1
  129. package/core/built/admin/assets/textarea-Bjccvh_E.js +1 -0
  130. package/core/built/admin/assets/{tiers-BgYLWRJv.js → tiers-DYsa4DCo.js} +1 -1
  131. package/core/built/admin/assets/{toggle-group-DNXDkAwf.js → toggle-group-b3IlxvhV.js} +1 -1
  132. package/core/built/admin/assets/{topic-filter-DZGjEcz3.js → topic-filter-DAFT87tQ.js} +1 -1
  133. package/core/built/admin/assets/{use-analytics-data-CaT8RirX.js → use-analytics-data-S0FTd43s.js} +1 -1
  134. package/core/built/admin/assets/use-filter-params-Gpoq2E1L.js +1 -0
  135. package/core/built/admin/assets/{use-growth-stats-9Db2CuJe.js → use-growth-stats-CIaiHOVb.js} +1 -1
  136. package/core/built/admin/assets/{use-post-referrers-BV54YcQS.js → use-post-referrers-Cq2vBPrA.js} +1 -1
  137. package/core/built/admin/assets/{use-reply-chain-data-DuYZGDan.js → use-reply-chain-data-DBDRtGu-.js} +1 -1
  138. package/core/built/admin/assets/{use-simple-pagination-8fTua9Nt.js → use-simple-pagination-CjYNxdwe.js} +1 -1
  139. package/core/built/admin/assets/{use-tinybird-query-Dz156HvZ.js → use-tinybird-query-falHAtuK.js} +1 -1
  140. package/core/built/admin/assets/{use-tinybird-token-C9RUdL_n.js → use-tinybird-token-D7-8ND1y.js} +1 -1
  141. package/core/built/admin/assets/{users-CcSCQFcQ.js → users-Dkv8NQZe.js} +1 -1
  142. package/core/built/admin/assets/{virtual-list-BCvP0YF-.js → virtual-list-CvnC9zF2.js} +1 -1
  143. package/core/built/admin/assets/web-B_5GZRvH.js +1 -0
  144. package/core/built/admin/assets/web-jFYWCKDn.js +2 -0
  145. package/core/built/admin/index.html +14 -10
  146. package/core/frontend/services/proxy.js +10 -1
  147. package/core/frontend/services/routing/router-manager.js +14 -14
  148. package/core/frontend/services/routing/static-routes-router.js +8 -10
  149. package/core/server/adapters/storage/LocalFilesStorage.js +13 -11
  150. package/core/server/adapters/storage/LocalFilesStorage.ts +24 -0
  151. package/core/server/adapters/storage/LocalImagesStorage.js +14 -12
  152. package/core/server/adapters/storage/LocalImagesStorage.ts +24 -0
  153. package/core/server/adapters/storage/LocalMediaStorage.js +13 -11
  154. package/core/server/adapters/storage/LocalMediaStorage.ts +24 -0
  155. package/core/server/adapters/storage/LocalStorageBase.js +107 -167
  156. package/core/server/adapters/storage/LocalStorageBase.ts +342 -0
  157. package/core/server/adapters/storage/utils.js +36 -50
  158. package/core/server/adapters/storage/utils.ts +60 -0
  159. package/core/server/api/endpoints/automation-action-links.js +68 -0
  160. package/core/server/api/endpoints/automation-action-links.ts +46 -0
  161. package/core/server/api/endpoints/db.js +6 -0
  162. package/core/server/api/endpoints/index.js +4 -0
  163. package/core/server/api/endpoints/members.js +25 -28
  164. package/core/server/api/endpoints/pages.js +6 -1
  165. package/core/server/api/endpoints/posts.js +11 -2
  166. package/core/server/api/endpoints/settings.js +0 -2
  167. package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +4 -1
  168. package/core/server/api/endpoints/utils/serializers/output/members.js +18 -87
  169. package/core/server/api/endpoints/utils/serializers/output/utils/url.js +11 -1
  170. package/core/server/data/exporter/export-filename.js +2 -1
  171. package/core/server/data/importer/importers/data/revue-subscriber-importer.js +6 -10
  172. package/core/server/data/importer/importers/json-to-html.js +24 -4
  173. package/core/server/data/migrations/versions/6.55/2026-07-27-11-25-44-add-to-hash-to-redirects.js +51 -0
  174. package/core/server/data/migrations/versions/6.55/2026-07-28-12-08-00-remove-routes-hash-from-settings.js +5 -0
  175. package/core/server/data/schema/commands.js +5 -0
  176. package/core/server/data/schema/default-settings/default-settings.json +0 -4
  177. package/core/server/data/schema/schema.js +5 -1
  178. package/core/server/lib/image/image-size.js +3 -17
  179. package/core/server/lib/image/image-utils.js +15 -1
  180. package/core/server/lib/request-external.js +1 -1
  181. package/core/server/models/user.js +46 -70
  182. package/core/server/services/auth/session/session-service.js +28 -1
  183. package/core/server/services/automations/automations-api.js +21 -6
  184. package/core/server/services/automations/automations-api.ts +25 -6
  185. package/core/server/services/automations/automations-repository.ts +19 -0
  186. package/core/server/services/automations/database-automations-repository.js +116 -28
  187. package/core/server/services/automations/database-automations-repository.ts +118 -9
  188. package/core/server/services/automations/database-date.js +10 -0
  189. package/core/server/services/automations/database-date.ts +5 -0
  190. package/core/server/services/automations/poll.js +5 -2
  191. package/core/server/services/automations/poll.ts +7 -2
  192. package/core/server/services/automations/scheduler-poll-time.js +40 -0
  193. package/core/server/services/automations/scheduler-poll-time.ts +38 -0
  194. package/core/server/services/automations/service.js +15 -3
  195. package/core/server/services/automations/service.ts +16 -3
  196. package/core/server/services/comments/comments-service-emails.js +14 -8
  197. package/core/server/services/comments/comments-service.js +9 -4
  198. package/core/server/services/email-rendering/partials/email-wrapper.hbs +3 -1
  199. package/core/server/services/email-service/email-service-wrapper.js +6 -1
  200. package/core/server/services/email-service/email-templates/partials/styles.hbs +8 -0
  201. package/core/server/services/email-service/newsletter-email-event-storage.js +41 -10
  202. package/core/server/services/lib/dynamic-redirect-manager.js +12 -3
  203. package/core/server/services/link-redirection/link-redirect-repository.js +41 -4
  204. package/core/server/services/link-redirection/link-redirect.js +2 -0
  205. package/core/server/services/link-redirection/link-redirect.ts +3 -1
  206. package/core/server/services/link-redirection/link-redirects-service.js +38 -2
  207. package/core/server/services/link-tracking/click-event.js +3 -0
  208. package/core/server/services/link-tracking/index.js +38 -6
  209. package/core/server/services/link-tracking/link-click-repository.js +30 -9
  210. package/core/server/services/link-tracking/link-click-tracking-service.js +44 -3
  211. package/core/server/services/member-attribution/outbound-link-tagger.js +3 -1
  212. package/core/server/services/member-welcome-emails/member-welcome-email-renderer.js +19 -4
  213. package/core/server/services/member-welcome-emails/service.js +11 -3
  214. package/core/server/services/members/{importer → import-export}/config.js +4 -9
  215. package/core/server/services/members/{importer → import-export}/config.ts +4 -9
  216. package/core/server/services/members/import-export/csv/formula.js +16 -0
  217. package/core/server/services/members/import-export/csv/formula.ts +14 -0
  218. package/core/server/services/members/import-export/csv/index.js +12 -0
  219. package/core/server/services/members/import-export/csv/index.ts +3 -0
  220. package/core/server/services/members/import-export/csv/parse.js +64 -0
  221. package/core/server/services/members/import-export/csv/parse.ts +69 -0
  222. package/core/server/services/members/import-export/csv/serialize.js +13 -0
  223. package/core/server/services/members/import-export/csv/serialize.ts +18 -0
  224. package/core/server/services/members/import-export/export/exporter.js +202 -0
  225. package/core/server/services/members/import-export/export/exporter.ts +325 -0
  226. package/core/server/services/members/import-export/import/completion-email.js +84 -0
  227. package/core/server/services/members/import-export/import/completion-email.ts +141 -0
  228. package/core/server/services/members/import-export/import/importer.js +297 -0
  229. package/core/server/services/members/import-export/import/importer.ts +468 -0
  230. package/core/server/services/members/import-export/import/reader.js +32 -0
  231. package/core/server/services/members/import-export/import/reader.ts +33 -0
  232. package/core/server/services/members/import-export/import/row.js +33 -0
  233. package/core/server/services/members/import-export/import/row.ts +52 -0
  234. package/core/server/services/members/import-export/import/spool.js +30 -0
  235. package/core/server/services/members/import-export/import/spool.ts +38 -0
  236. package/core/server/services/members/import-export/index.js +99 -0
  237. package/core/server/services/members/import-export/index.ts +137 -0
  238. package/core/server/services/members/members-api/controllers/router-controller.js +7 -0
  239. package/core/server/services/members/service.js +25 -20
  240. package/core/server/services/members-custom-fields/values-service.js +19 -7
  241. package/core/server/services/members-custom-fields/values-service.ts +19 -7
  242. package/core/server/services/mentions/service.js +5 -1
  243. package/core/server/services/posts/posts-exporter.js +6 -4
  244. package/core/server/services/posts/posts-service.js +2 -2
  245. package/core/server/services/route-settings/activation-bridge.js +59 -49
  246. package/core/server/services/route-settings/activation-bridge.ts +91 -51
  247. package/core/server/services/route-settings/dynamic-routing-service.js +22 -51
  248. package/core/server/services/route-settings/index.js +1 -16
  249. package/core/server/services/settings/settings-service.js +0 -18
  250. package/core/server/services/themes/storage.js +9 -0
  251. package/core/server/services/themes/theme-storage.js +1 -1
  252. package/core/server/services/url/url-service-facade.js +1 -1
  253. package/core/server/services/url/url-service-facade.ts +8 -1
  254. package/core/server/web/api/endpoints/admin/routes.js +1 -0
  255. package/core/shared/config/defaults.json +2 -1
  256. package/core/shared/express.js +6 -1
  257. package/core/shared/labs.js +2 -1
  258. package/package.json +11 -11
  259. package/pnpm-lock.yaml +18 -18
  260. package/pnpm-workspace.yaml +8 -7
  261. package/components/tryghost-adapter-base-scheduling-0.1.1.tgz +0 -0
  262. package/core/built/admin/assets/Overview-j4NaeUNm.js +0 -1
  263. package/core/built/admin/assets/Web-_fD935OX.js +0 -2
  264. package/core/built/admin/assets/activitypub/layout-IdVq3lRy.js +0 -1
  265. package/core/built/admin/assets/audience-BKRdsFmy.js +0 -1
  266. package/core/built/admin/assets/checkbox-DA4-1UiI.js +0 -1
  267. package/core/built/admin/assets/chunk.524.45e0875f41b71e46e849.js +0 -25
  268. package/core/built/admin/assets/chunk.582.51defd4b009f0de8d4d5.js +0 -27
  269. package/core/built/admin/assets/code-editor-view-BKBrkffZ.js +0 -1
  270. package/core/built/admin/assets/comments-CzVNIT8b.js +0 -1
  271. package/core/built/admin/assets/constants-c-JNF9c2.js +0 -1
  272. package/core/built/admin/assets/dist-CT46_f_J.js +0 -1
  273. package/core/built/admin/assets/domain-B7_n5nfx.js +0 -1
  274. package/core/built/admin/assets/dropzone-DcuJEEUf.js +0 -5
  275. package/core/built/admin/assets/editor-BCiIyFjm.js +0 -8
  276. package/core/built/admin/assets/field-BW-M2Zwp.js +0 -1
  277. package/core/built/admin/assets/filters-DtcXMZDU.js +0 -1
  278. package/core/built/admin/assets/gift-link-modal-Bk8qpnMw.js +0 -1
  279. package/core/built/admin/assets/growth-Ck2s3JjR.js +0 -1
  280. package/core/built/admin/assets/index-BBf502Wg.js +0 -69
  281. package/core/built/admin/assets/index-BCCZKxP2.css +0 -1
  282. package/core/built/admin/assets/input-group-DjuYnNCd.js +0 -1
  283. package/core/built/admin/assets/label-picker-BdNAWuUX.js +0 -1
  284. package/core/built/admin/assets/labels-Cyayfd-e.js +0 -1
  285. package/core/built/admin/assets/layout-Bw4GnxXp.js +0 -1
  286. package/core/built/admin/assets/member-custom-fields-DvFyamLu.js +0 -1
  287. package/core/built/admin/assets/member-detail-Cg2vTqvJ.js +0 -1
  288. package/core/built/admin/assets/members-DsPxYAVm.js +0 -10
  289. package/core/built/admin/assets/modals-Bf_fyvHZ.js +0 -31
  290. package/core/built/admin/assets/moderation-Dlp7M5sa.js +0 -1
  291. package/core/built/admin/assets/multi-select-combobox-CH1o8XXQ.js +0 -1
  292. package/core/built/admin/assets/newsletter-CQ5CAYUI.js +0 -1
  293. package/core/built/admin/assets/note-BrAZ7Z0o.js +0 -1
  294. package/core/built/admin/assets/notifications-BnbHLOPC.js +0 -1
  295. package/core/built/admin/assets/onboarding-route-eU146kuA.js +0 -1
  296. package/core/built/admin/assets/overview-BpbaK-xu.js +0 -1
  297. package/core/built/admin/assets/post-analytics-header-D9pJ4iNm.js +0 -1
  298. package/core/built/admin/assets/post-analytics-provider-BDqcfBor.js +0 -1
  299. package/core/built/admin/assets/profile-dJ44Bn_W.js +0 -1
  300. package/core/built/admin/assets/select--2uVN9_-.js +0 -1
  301. package/core/built/admin/assets/settings-SD9bxIpt.js +0 -4
  302. package/core/built/admin/assets/social-urls-BvFZwYcE.js +0 -8
  303. package/core/built/admin/assets/switch-qp518gFQ.js +0 -1
  304. package/core/built/admin/assets/tabs-D3ZOYkM7.js +0 -1
  305. package/core/built/admin/assets/textarea-CTlb3Uu6.js +0 -1
  306. package/core/built/admin/assets/use-filter-params-DeQ8sX4N.js +0 -1
  307. package/core/built/admin/assets/web-DTZnnUGr.js +0 -1
  308. package/core/server/services/mail/templates/newsletter.html +0 -876
  309. package/core/server/services/members/csv/index.js +0 -10
  310. package/core/server/services/members/csv/index.ts +0 -3
  311. package/core/server/services/members/csv/parse.js +0 -94
  312. package/core/server/services/members/csv/parse.ts +0 -111
  313. package/core/server/services/members/csv/types.js +0 -2
  314. package/core/server/services/members/csv/types.ts +0 -39
  315. package/core/server/services/members/csv/unparse.js +0 -69
  316. package/core/server/services/members/csv/unparse.ts +0 -79
  317. package/core/server/services/members/exporter/query.js +0 -233
  318. package/core/server/services/members/importer/index.js +0 -30
  319. package/core/server/services/members/importer/labels.js +0 -125
  320. package/core/server/services/members/importer/members-csv-importer.js +0 -520
  321. package/core/server/services/route-settings/default-settings-manager.js +0 -63
  322. package/core/server/services/route-settings/route-settings.js +0 -170
  323. package/core/server/services/route-settings/settings-loader.js +0 -60
  324. package/core/server/services/route-settings/settings-path-manager.js +0 -47
  325. package/core/server/services/route-settings/validate.js +0 -440
  326. /package/core/server/services/members/{importer → import-export/import}/email-template.js +0 -0
  327. /package/core/server/services/members/{importer/members-csv-importer-stripe-utils.js → import-export/import/stripe-utils.js} +0 -0
@@ -6,7 +6,6 @@ const limitService = require('../services/limits');
6
6
  const tpl = require('@tryghost/tpl');
7
7
  const errors = require('@tryghost/errors');
8
8
  const security = require('@tryghost/security');
9
- const {pipeline} = require('@tryghost/promise');
10
9
  const validatePassword = require('../lib/validate-password');
11
10
  const permissions = require('../services/permissions');
12
11
  const urlUtils = require('../../shared/url-utils').default;
@@ -572,91 +571,68 @@ User = ghostBookshelf.Model.extend({
572
571
  * @extends ghostBookshelf.Model.edit to handle returning the full object
573
572
  * **See:** [ghostBookshelf.Model.edit](base.js.html#edit)
574
573
  */
575
- edit: function edit(data, unfilteredOptions) {
574
+ edit: async function edit(data, unfilteredOptions) {
576
575
  const options = this.filterOptions(unfilteredOptions, 'edit');
577
576
  const self = this;
578
- const ops = [];
579
577
 
580
578
  if (data.roles && data.roles.length > 1) {
581
- return Promise.reject(
582
- new errors.ValidationError({
583
- message: tpl(messages.onlyOneRolePerUserSupported)
584
- })
585
- );
579
+ throw new errors.ValidationError({
580
+ message: tpl(messages.onlyOneRolePerUserSupported)
581
+ });
586
582
  }
587
583
 
588
584
  if (data.email) {
589
- ops.push(function checkForDuplicateEmail() {
590
- return self.getByEmail(data.email, options).then(function then(user) {
591
- if (user && user.id !== options.id) {
592
- return Promise.reject(new errors.ValidationError({
593
- message: tpl(messages.userUpdateError.emailIsAlreadyInUse)
594
- }));
595
- }
585
+ const existingUser = await self.getByEmail(data.email, options);
586
+ if (existingUser && existingUser.id !== options.id) {
587
+ throw new errors.ValidationError({
588
+ message: tpl(messages.userUpdateError.emailIsAlreadyInUse)
596
589
  });
597
- });
590
+ }
598
591
  }
599
592
 
600
- ops.push(function update() {
601
- return ghostBookshelf.Model.edit.call(self, data, options).then(async (user) => {
602
- let roleId;
593
+ const user = await ghostBookshelf.Model.edit.call(self, data, options);
603
594
 
604
- if (!data.roles || !data.roles.length) {
605
- return user;
606
- }
607
-
608
- roleId = data.roles[0].id || data.roles[0];
609
-
610
- return user.roles().fetch().then((roles) => {
611
- // return if the role is already assigned
612
- if (roles.models[0].id === roleId) {
613
- return;
614
- }
595
+ if (!data.roles || !data.roles.length) {
596
+ return user;
597
+ }
615
598
 
616
- if (ASSIGNABLE_ROLES.includes(roleId)) {
617
- // return if the role is already assigned
618
- if (roles.models[0].get('name') === roleId) {
619
- return;
620
- }
599
+ const roleId = data.roles[0].id || data.roles[0];
600
+ const roles = await user.roles().fetch();
601
+ let roleToAssign;
621
602
 
622
- return ghostBookshelf.model('Role').findOne({
623
- name: roleId
624
- });
625
- } else if (ObjectId.isValid(roleId)){
626
- return ghostBookshelf.model('Role').findOne({
627
- id: roleId
628
- });
629
- } else {
630
- return Promise.reject(
631
- new errors.ValidationError({
632
- message: tpl(messages.invalidRoleValue.message),
633
- context: tpl(messages.invalidRoleValue.context),
634
- help: tpl(messages.invalidRoleValue.help)
635
- })
636
- );
637
- }
638
- }).then((roleToAssign) => {
639
- if (roleToAssign && roleToAssign.get('name') === 'Owner') {
640
- return Promise.reject(
641
- new errors.ValidationError({
642
- message: tpl(messages.methodDoesNotSupportOwnerRole)
643
- })
644
- );
645
- } else if (roleToAssign) {
646
- // assign all other roles
647
- return user.roles().updatePivot({role_id: roleToAssign.id});
648
- }
649
- }).then(() => {
650
- options.status = 'all';
651
- return self.findOne({id: user.id}, options);
652
- }).then((model) => {
653
- model._changed = user._changed;
654
- return model;
603
+ if (roles.models[0].id !== roleId) {
604
+ if (ASSIGNABLE_ROLES.includes(roleId)) {
605
+ if (roles.models[0].get('name') !== roleId) {
606
+ roleToAssign = await ghostBookshelf.model('Role').findOne({
607
+ name: roleId
608
+ });
609
+ }
610
+ } else if (ObjectId.isValid(roleId)) {
611
+ roleToAssign = await ghostBookshelf.model('Role').findOne({
612
+ id: roleId
655
613
  });
614
+ } else {
615
+ throw new errors.ValidationError({
616
+ message: tpl(messages.invalidRoleValue.message),
617
+ context: tpl(messages.invalidRoleValue.context),
618
+ help: tpl(messages.invalidRoleValue.help)
619
+ });
620
+ }
621
+ }
622
+
623
+ if (roleToAssign && roleToAssign.get('name') === 'Owner') {
624
+ throw new errors.ValidationError({
625
+ message: tpl(messages.methodDoesNotSupportOwnerRole)
656
626
  });
657
- });
627
+ } else if (roleToAssign) {
628
+ // assign all other roles
629
+ await user.roles().updatePivot({role_id: roleToAssign.id});
630
+ }
658
631
 
659
- return pipeline(ops);
632
+ options.status = 'all';
633
+ const model = await self.findOne({id: user.id}, options);
634
+ model._changed = user._changed;
635
+ return model;
660
636
  },
661
637
 
662
638
  /**
@@ -208,7 +208,34 @@ module.exports = function createSessionService({
208
208
  * @returns {Promise<void>}
209
209
  */
210
210
  async function createSessionForUser(req, res, user) {
211
- const session = await getSession(req, res);
211
+ const previousSession = await getSession(req, res);
212
+
213
+ // Carried over to the new session so verification state survives login
214
+ const {
215
+ user_id: previousUserId,
216
+ verified: previousVerified,
217
+ auth_code_challenge: previousAuthCodeChallenge,
218
+ auth_code_generated_at: previousAuthCodeGeneratedAt
219
+ } = previousSession;
220
+
221
+ // Ensure a new session is always created
222
+ await new Promise((resolve, reject) => {
223
+ req.session.regenerate((err) => {
224
+ if (err) {
225
+ reject(err);
226
+ return;
227
+ }
228
+ resolve();
229
+ });
230
+ });
231
+
232
+ const session = req.session;
233
+ session.user_id = previousUserId;
234
+ // A different user doesn't inherit the previous user's verification
235
+ session.verified = previousUserId && previousUserId !== user.id ? undefined : previousVerified;
236
+ session.auth_code_challenge = previousAuthCodeChallenge;
237
+ session.auth_code_generated_at = previousAuthCodeGeneratedAt;
238
+
212
239
  const origin = getOriginOfRequest(req);
213
240
  await assignUserToSession({
214
241
  session,
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.browse = browse;
7
7
  exports.read = read;
8
+ exports.browseActionLinks = browseActionLinks;
8
9
  exports.edit = edit;
9
10
  exports.requestPoll = requestPoll;
10
11
  exports.trigger = trigger;
@@ -15,6 +16,7 @@ exports.retryStep = retryStep;
15
16
  exports.recordEmailSent = recordEmailSent;
16
17
  exports.getAutomatedEmailRecipientsByMailgunIds = getAutomatedEmailRecipientsByMailgunIds;
17
18
  exports.trackEmailDeliveredAndOpened = trackEmailDeliveredAndOpened;
19
+ exports.trackEmailClicked = trackEmailClicked;
18
20
  const errors_1 = __importDefault(require("@tryghost/errors"));
19
21
  const tpl_1 = __importDefault(require("@tryghost/tpl"));
20
22
  const bson_objectid_1 = __importDefault(require("bson-objectid"));
@@ -30,6 +32,7 @@ const StartAutomationsPollEvent = require('./events/start-automations-poll-event
30
32
  const MAX_AUTOMATION_ACTIONS = 20;
31
33
  const messages = {
32
34
  automationNotFound: 'Automation not found.',
35
+ automationActionNotFound: 'Automation action not found.',
33
36
  invalidAutomationPayload: 'Automation edit payload must include status, actions, and edges.',
34
37
  invalidAutomationStatus: 'Automation status must be one of: active, inactive.',
35
38
  duplicateAutomationActionIdentity: 'Automation action identifiers must be unique.',
@@ -47,8 +50,8 @@ const waitActionSchema = zod_1.z.object({
47
50
  type: zod_1.z.literal('wait'),
48
51
  data: zod_1.z.object({
49
52
  wait_hours: zod_1.z.number().int().positive()
50
- }).strict()
51
- }).strict();
53
+ })
54
+ });
52
55
  const sendEmailActionSchema = zod_1.z.object({
53
56
  id: objectIdSchema,
54
57
  type: zod_1.z.literal('send_email'),
@@ -56,12 +59,12 @@ const sendEmailActionSchema = zod_1.z.object({
56
59
  email_subject: zod_1.z.string(),
57
60
  email_lexical: zod_1.z.string(),
58
61
  email_design_setting_id: zod_1.z.string().min(1)
59
- }).strict()
60
- }).strict();
62
+ })
63
+ });
61
64
  const edgeSchema = zod_1.z.object({
62
65
  source_action_id: objectIdSchema,
63
66
  target_action_id: objectIdSchema
64
- }).strict();
67
+ });
65
68
  const editAutomationDataSchema = zod_1.z.object({
66
69
  status: zod_1.z.enum(['active', 'inactive']),
67
70
  actions: zod_1.z.array(zod_1.z.discriminatedUnion('type', [
@@ -69,7 +72,7 @@ const editAutomationDataSchema = zod_1.z.object({
69
72
  sendEmailActionSchema
70
73
  ])).min(1).max(MAX_AUTOMATION_ACTIONS),
71
74
  edges: zod_1.z.array(edgeSchema)
72
- }).strict();
75
+ });
73
76
  const repository = (0, database_automations_repository_1.createDatabaseAutomationsRepository)({
74
77
  knex,
75
78
  fakeWaitHoursMultiplier: (0, fake_wait_hours_multiplier_1.parseFakeWaitHoursMultiplier)(config.get('automations:fakeWaitHoursMultiplier'))
@@ -86,6 +89,15 @@ async function read(automationId) {
86
89
  }
87
90
  return automation;
88
91
  }
92
+ async function browseActionLinks(automationId, actionId) {
93
+ const links = await repository.getAutomationActionLinks(automationId, actionId);
94
+ if (!links) {
95
+ throw new errors_1.default.NotFoundError({
96
+ message: (0, tpl_1.default)(messages.automationActionNotFound)
97
+ });
98
+ }
99
+ return links;
100
+ }
89
101
  async function edit(automationId, data) {
90
102
  const parsedData = await validateEditData(data);
91
103
  const automation = await repository.edit(automationId, parsedData);
@@ -311,3 +323,6 @@ async function getAutomatedEmailRecipientsByMailgunIds(...args) {
311
323
  async function trackEmailDeliveredAndOpened(...args) {
312
324
  return await repository.trackEmailDeliveredAndOpened(...args);
313
325
  }
326
+ async function trackEmailClicked(...args) {
327
+ await repository.trackEmailClicked(...args);
328
+ }
@@ -20,6 +20,7 @@ const MAX_AUTOMATION_ACTIONS = 20;
20
20
 
21
21
  const messages = {
22
22
  automationNotFound: 'Automation not found.',
23
+ automationActionNotFound: 'Automation action not found.',
23
24
  invalidAutomationPayload: 'Automation edit payload must include status, actions, and edges.',
24
25
  invalidAutomationStatus: 'Automation status must be one of: active, inactive.',
25
26
  duplicateAutomationActionIdentity: 'Automation action identifiers must be unique.',
@@ -39,8 +40,8 @@ const waitActionSchema = z.object({
39
40
  type: z.literal('wait'),
40
41
  data: z.object({
41
42
  wait_hours: z.number().int().positive()
42
- }).strict()
43
- }).strict();
43
+ })
44
+ });
44
45
 
45
46
  const sendEmailActionSchema = z.object({
46
47
  id: objectIdSchema,
@@ -49,13 +50,13 @@ const sendEmailActionSchema = z.object({
49
50
  email_subject: z.string(),
50
51
  email_lexical: z.string(),
51
52
  email_design_setting_id: z.string().min(1)
52
- }).strict()
53
- }).strict();
53
+ })
54
+ });
54
55
 
55
56
  const edgeSchema = z.object({
56
57
  source_action_id: objectIdSchema,
57
58
  target_action_id: objectIdSchema
58
- }).strict();
59
+ });
59
60
 
60
61
  const editAutomationDataSchema = z.object({
61
62
  status: z.enum(['active', 'inactive']),
@@ -64,7 +65,7 @@ const editAutomationDataSchema = z.object({
64
65
  sendEmailActionSchema
65
66
  ])).min(1).max(MAX_AUTOMATION_ACTIONS),
66
67
  edges: z.array(edgeSchema)
67
- }).strict();
68
+ });
68
69
 
69
70
  const repository = createDatabaseAutomationsRepository({
70
71
  knex,
@@ -87,6 +88,18 @@ export async function read(automationId: string) {
87
88
  return automation;
88
89
  }
89
90
 
91
+ export async function browseActionLinks(automationId: string, actionId: string) {
92
+ const links = await repository.getAutomationActionLinks(automationId, actionId);
93
+
94
+ if (!links) {
95
+ throw new errors.NotFoundError({
96
+ message: tpl(messages.automationActionNotFound)
97
+ });
98
+ }
99
+
100
+ return links;
101
+ }
102
+
90
103
  export async function edit(automationId: string, data: unknown) {
91
104
  const parsedData = await validateEditData(data);
92
105
 
@@ -375,3 +388,9 @@ export async function trackEmailDeliveredAndOpened(
375
388
  ) {
376
389
  return await repository.trackEmailDeliveredAndOpened(...args);
377
390
  }
391
+
392
+ export async function trackEmailClicked(
393
+ ...args: Parameters<AutomationsRepository['trackEmailClicked']>
394
+ ) {
395
+ await repository.trackEmailClicked(...args);
396
+ }
@@ -1,4 +1,5 @@
1
1
  import type {ReadonlyDeep} from 'type-fest';
2
+ import type {Knex} from 'knex';
2
3
 
3
4
  export interface Pagination {
4
5
  page: number;
@@ -25,12 +26,18 @@ export interface WaitAction {
25
26
  }
26
27
 
27
28
  export interface AutomationEmailStats {
29
+ email_clicked_count: number;
28
30
  email_sent_count: number;
29
31
  email_opened_count: number;
30
32
  opened_rate: number | null;
31
33
  clicked_rate: number | null;
32
34
  }
33
35
 
36
+ export interface AutomationActionLink {
37
+ url: string;
38
+ clicked_count: number;
39
+ }
40
+
34
41
  export interface SendEmailAction {
35
42
  id: string;
36
43
  type: 'send_email';
@@ -130,6 +137,7 @@ export type AutomationStepTerminalStatus =
130
137
  export interface AutomationsRepository {
131
138
  browse(): Promise<Page<AutomationSummary>>;
132
139
  getById(id: string): Promise<Automation | null>;
140
+ getAutomationActionLinks(automationId: string, actionId: string): Promise<AutomationActionLink[] | null>;
133
141
  edit(id: string, data: EditAutomationData): Promise<Automation | null>;
134
142
  trigger(options: {
135
143
  memberEmail: string;
@@ -194,4 +202,15 @@ export interface AutomationsRepository {
194
202
  trackEmailDeliveredAndOpened(
195
203
  eventsByAutomatedEmailRecipientId: ReadonlyDeep<Map<string, AutomatedEmailEvents>>
196
204
  ): Promise<void>;
205
+ /**
206
+ * Track the first click for an automated email recipient.
207
+ *
208
+ */
209
+ trackEmailClicked(options: {
210
+ automationActionRevisionId: string;
211
+ memberId: string;
212
+ clickedAt: Readonly<Date>;
213
+ }, transactionOptions?: {
214
+ transacting?: Knex.Transaction;
215
+ }): Promise<void>;
197
216
  }