ghost 6.37.1 → 6.38.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 (258) hide show
  1. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  2. package/core/boot.js +13 -9
  3. package/core/bridge.js +10 -6
  4. package/core/built/admin/assets/{PolarAngleAxis-Cavik65s.js → PolarAngleAxis-CB-FJBDa.js} +1 -1
  5. package/core/built/admin/assets/{_baseAssignValue-CnqN6ZMT.js → _baseAssignValue-BEAjPAfy.js} +1 -1
  6. package/core/built/admin/assets/{a-large-small-Wi4LtZX-.js → a-large-small-L1BJa6mG.js} +1 -1
  7. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
  8. package/core/built/admin/assets/admin-x-settings/{code-editor-view-Cf8T5Jfd.mjs → code-editor-view-bOZzJ3a1.mjs} +2 -2
  9. package/core/built/admin/assets/admin-x-settings/{index-BMWEh-vR.mjs → index-BRuMxaCz.mjs} +2 -2
  10. package/core/built/admin/assets/admin-x-settings/{index-Aj-hFSnY.mjs → index-CTAQj489.mjs} +5 -5
  11. package/core/built/admin/assets/admin-x-settings/{index-DjBJrXYn.mjs → index-WoKKBOe4.mjs} +2 -2
  12. package/core/built/admin/assets/admin-x-settings/{modals-8WpWZZdI.mjs → modals-BQ5M-RTA.mjs} +3 -3
  13. package/core/built/admin/assets/{arrow-right-BiAOKOto.js → arrow-right-B2j-ecEK.js} +1 -1
  14. package/core/built/admin/assets/{at-sign-z5gBMxDW.js → at-sign-CtAw8_lw.js} +1 -1
  15. package/core/built/admin/assets/{audience-DxNilLIv.js → audience-CvSOqHuo.js} +1 -1
  16. package/core/built/admin/assets/automations-BVUNuVOh.js +1 -0
  17. package/core/built/admin/assets/automations-Bi9RJq5E.js +1 -0
  18. package/core/built/admin/assets/{avatar-flipboard-5OzseZFV.js → avatar-flipboard-DocLTXLh.js} +1 -1
  19. package/core/built/admin/assets/{bluesky-sharing-D9YcSpW8.js → bluesky-sharing-DafX2lE1.js} +1 -1
  20. package/core/built/admin/assets/chart-BRQeD9eh.js +67 -0
  21. package/core/built/admin/assets/{chevron-up-DVt6fhV3.js → chevron-up-v4_QwmnL.js} +1 -1
  22. package/core/built/admin/assets/{chunk.524.fcd26ef812d73e2b0620.js → chunk.524.c3d844070c24d7984fd7.js} +4 -4
  23. package/core/built/admin/assets/{chunk.582.b61ffaad1c2fa4aba820.js → chunk.582.0e0ede1eac12926acceb.js} +6 -6
  24. package/core/built/admin/assets/{chunk.383.adb5a3fe32b6b98c43ff.js → chunk.995.4b32363ab39da3e7f5d7.js} +3 -3
  25. package/core/built/admin/assets/circle-alert-Dbz54fYb.js +1 -0
  26. package/core/built/admin/assets/{code-editor-view-CbQIqTrK.js → code-editor-view-D-pYCcdu.js} +1 -1
  27. package/core/built/admin/assets/comments-DSv09jRn.js +1 -0
  28. package/core/built/admin/assets/{content-helpers-jANWGIfA.js → content-helpers-DQdPPDGb.js} +1 -1
  29. package/core/built/admin/assets/{copy-BBLeLEnG.js → copy-BULQsPZ4.js} +1 -1
  30. package/core/built/admin/assets/{data-list-BveeOSGI.js → data-list-WxXC0iKE.js} +1 -1
  31. package/core/built/admin/assets/{deleted-feed-item-DupAEk4P.js → deleted-feed-item-ZBLfgRkK.js} +1 -1
  32. package/core/built/admin/assets/{dropzone-D3PSdAHN.js → dropzone-B8mAoWrn.js} +1 -1
  33. package/core/built/admin/assets/{edit-profile-NrCR9_bi.js → edit-profile-Bj3th8H0.js} +1 -1
  34. package/core/built/admin/assets/editor-BZV40eAE.css +1 -0
  35. package/core/built/admin/assets/editor-u20VuPzn.js +7 -0
  36. package/core/built/admin/assets/{empty-indicator-Dhi_KeYX.js → empty-indicator-P3IsUguf.js} +1 -1
  37. package/core/built/admin/assets/{en-BontI3SP.js → en-C9bUnuy7.js} +1 -1
  38. package/core/built/admin/assets/{feed-B3Kfiz5R.js → feed-B94mO944.js} +1 -1
  39. package/core/built/admin/assets/{filter-query-core-Dwh4Qulu.js → filter-query-core-CM0KKIr2.js} +1 -1
  40. package/core/built/admin/assets/filters-D52FTE0z.js +1 -0
  41. package/core/built/admin/assets/gh-chart-Xa6Nvzwz.js +1 -0
  42. package/core/built/admin/assets/{ghost-c25434d5bbf5a5429883d4c3590f1946.js → ghost-82f1c4ffe0e1cd058ce4b66b5253b620.js} +159 -201
  43. package/core/built/admin/assets/{ghost-dark-52df27573e5f2a75e6cf4b1d06eea9e4.css → ghost-dark-9897cf5102772faedf566e5e54d4fbee.css} +1 -1
  44. package/core/built/admin/assets/{ghost-fcf460028e04192f392f16e173f2e3a8.css → ghost-e11f1814be0f38e98bb77b49eba11178.css} +1 -1
  45. package/core/built/admin/assets/{growth-DRH8zUIJ.js → growth-D3TW3JIB.js} +1 -1
  46. package/core/built/admin/assets/{hash-UvX5iOa9.js → hash-CstXS-iB.js} +1 -1
  47. package/core/built/admin/assets/{header-G1a38jnf.js → header-StkTITw-.js} +1 -1
  48. package/core/built/admin/assets/{inbox-By7HZskI.js → inbox-D1RM3kVF.js} +1 -1
  49. package/core/built/admin/assets/index-BEkJ9xtY.css +1 -0
  50. package/core/built/admin/assets/{index-CS_ZmI8F.js → index-BJx5Uas5.js} +1 -1
  51. package/core/built/admin/assets/index-BKzg6OE7.js +1 -0
  52. package/core/built/admin/assets/{index-D7JyKf1m.js → index-BM-MBdD0.js} +1 -1
  53. package/core/built/admin/assets/index-BRzvVuXt.js +2 -0
  54. package/core/built/admin/assets/index-B_3xqeM9.js +1 -0
  55. package/core/built/admin/assets/{index-ydyrczVl.js → index-C-OdR2wJ.js} +1 -1
  56. package/core/built/admin/assets/{index-X-MG1ikg.js → index-C59QlJqT.js} +1 -1
  57. package/core/built/admin/assets/{index-CJo0Qh4V.js → index-CCq_1tCo.js} +1 -1
  58. package/core/built/admin/assets/{index-qHUvPjQB.js → index-CYyEyBYw.js} +11 -11
  59. package/core/built/admin/assets/{index-CX4ztLSk.js → index-DHbiBjyq.js} +1 -1
  60. package/core/built/admin/assets/{index-BP6hBbPK.js → index-DTVgSMyL.js} +2 -2
  61. package/core/built/admin/assets/{index-vZMbI8e8.js → index-DiUjEgRw.js} +1 -1
  62. package/core/built/admin/assets/{index-YM4ZplGj.js → index-DugxKzA6.js} +1 -1
  63. package/core/built/admin/assets/{index-D8InZCr2.js → index-DzVHlhO1.js} +1 -1
  64. package/core/built/admin/assets/{index-D4b7U6K-.js → index-LsaD9Cq7.js} +1 -1
  65. package/core/built/admin/assets/{index-DRUPF8nN.js → index-x0hNfyqU.js} +1 -1
  66. package/core/built/admin/assets/{inline-Bc9zHR7e.js → inline-B4cWemrJ.js} +1 -1
  67. package/core/built/admin/assets/{koenig-lexical-B-ZnqRE1.js → koenig-lexical-BOdeH3QJ.js} +1 -1
  68. package/core/built/admin/assets/{kpi-card-zyi5Onb0.js → kpi-card-P7zSpcx0.js} +1 -1
  69. package/core/built/admin/assets/{kpi-card-CzlPIEPE.js → kpi-card-plhYOEtA.js} +1 -1
  70. package/core/built/admin/assets/{kpi-tabs-Dsa5ldXK.js → kpi-tabs-DZw2Qktb.js} +1 -1
  71. package/core/built/admin/assets/{kpis-Cw5ZRQhk.js → kpis-CDHM0xhW.js} +1 -1
  72. package/core/built/admin/assets/{label-BvxmsD1M.js → label-Ckacdx14.js} +1 -1
  73. package/core/built/admin/assets/{links-CiS5BPKS.js → links-BtXE5d0Y.js} +1 -1
  74. package/core/built/admin/assets/{list-filter-zmkB7rg4.js → list-filter-DLjjiktn.js} +1 -1
  75. package/core/built/admin/assets/{list-header-Cp779e3H.js → list-header-Cc7Ia3nr.js} +1 -1
  76. package/core/built/admin/assets/loader-circle-DLJd-dNm.js +1 -0
  77. package/core/built/admin/assets/{mail-i2qs8CIG.js → mail-B97w28e2.js} +1 -1
  78. package/core/built/admin/assets/{main-layout-KCvKOX8F.js → main-layout-bwWvzc9B.js} +1 -1
  79. package/core/built/admin/assets/{members-w601v5JJ.js → members-CokS8MI2.js} +5 -5
  80. package/core/built/admin/assets/{message-square-text-bG9IoWIt.js → message-square-text-D3rsjDFR.js} +1 -1
  81. package/core/built/admin/assets/minus-BzXQVmMw.js +1 -0
  82. package/core/built/admin/assets/{modals-lNzhiL0o.js → modals-D0lip-iy.js} +2 -2
  83. package/core/built/admin/assets/{moderation-CyfNRSWj.js → moderation-Dv7AadCV.js} +1 -1
  84. package/core/built/admin/assets/newsletter-BazC5rIj.js +1 -0
  85. package/core/built/admin/assets/{newsletters-B8xSXSr_.js → newsletters-m6HQgU5J.js} +1 -1
  86. package/core/built/admin/assets/{note-dNfKEpxw.js → note-CCGiEKz-.js} +1 -1
  87. package/core/built/admin/assets/{onboarding-route-Drbw0QtT.js → onboarding-route-Cbt7qWNE.js} +1 -1
  88. package/core/built/admin/assets/overview-TN50tzUh.js +1 -0
  89. package/core/built/admin/assets/{pagemenu-VJXMoMB4.js → pagemenu-BXrHWtsU.js} +1 -1
  90. package/core/built/admin/assets/{pencil-DHNmlLjO.js → pencil-BL1r8KVy.js} +1 -1
  91. package/core/built/admin/assets/{post-analytics-PsqLsS2e.js → post-analytics-BqEXi6Ps.js} +1 -1
  92. package/core/built/admin/assets/{post-analytics-context-QLZsZCFg.js → post-analytics-context-DekYNlb3.js} +1 -1
  93. package/core/built/admin/assets/{post-analytics-header-PecXsIT-.js → post-analytics-header-AkNbn6uc.js} +1 -1
  94. package/core/built/admin/assets/{post-share-modal-B4Rvo7W1.js → post-share-modal-CXDGVKoQ.js} +1 -1
  95. package/core/built/admin/assets/posts/{app-utils-DIc5TmxO.mjs → app-utils-DxA7edI_.mjs} +2 -2
  96. package/core/built/admin/assets/posts/{automations-BZpT35kJ.mjs → automations-Cwu_gHl4.mjs} +64 -67
  97. package/core/built/admin/assets/posts/automations-D81hV_2c.mjs +13 -0
  98. package/core/built/admin/assets/posts/{avatar-K63cvqSS.mjs → avatar-IkjEzEjI.mjs} +19 -19
  99. package/core/built/admin/assets/posts/{button-ufGBCcsV.mjs → button-KaJZKcou.mjs} +21 -21
  100. package/core/built/admin/assets/posts/{check-IcEnuTpD.mjs → check-Cf74RvZ1.mjs} +21 -21
  101. package/core/built/admin/assets/posts/{comments-CyJU9Ums.mjs → comments-pdKhYbYG.mjs} +54 -52
  102. package/core/built/admin/assets/posts/createLucideIcon-Cj7h3r9g.mjs +320 -0
  103. package/core/built/admin/assets/posts/{dialog-D6_lBvtT.mjs → dialog-Ci3W8fjx.mjs} +71 -76
  104. package/core/built/admin/assets/posts/{dropdown-menu-BSSmAory.mjs → dropdown-menu-DZ9XCHSw.mjs} +5 -5
  105. package/core/built/admin/assets/posts/editor-Bb-xle0o.mjs +6084 -0
  106. package/core/built/admin/assets/posts/ellipsis-ChhZo9aT.mjs +10 -0
  107. package/core/built/admin/assets/posts/{empty-indicator-DvGCvRAX.mjs → empty-indicator-DnFs7hDy.mjs} +2 -2
  108. package/core/built/admin/assets/posts/{filters-BLBaHhJz.mjs → filters-CO_FUPX-.mjs} +42 -40
  109. package/core/built/admin/assets/posts/get-site-timezone-C21yKZT_.mjs +87 -0
  110. package/core/built/admin/assets/posts/{growth-Bz1ChJNB.mjs → growth-CtX9Efm2.mjs} +12 -12
  111. package/core/built/admin/assets/posts/heading-DZ_KtDTL.mjs +138 -0
  112. package/core/built/admin/assets/posts/{hooks-BEngBys9.mjs → hooks-DVhBDVlA.mjs} +3 -2
  113. package/core/built/admin/assets/posts/{index-BAF0YXsp.mjs → index-B4db8w_H.mjs} +181 -172
  114. package/core/built/admin/assets/posts/{inline-C2YFQAdU.mjs → inline-BfB-SNk0.mjs} +2 -2
  115. package/core/built/admin/assets/posts/{input-surface-TqJlNSp_.mjs → input-surface-CNwZJloi.mjs} +2 -2
  116. package/core/built/admin/assets/posts/{kpis-DAX5_0-Q.mjs → kpis-BvY_5Y1u.mjs} +8792 -8803
  117. package/core/built/admin/assets/posts/{links-A1YTsBbF.mjs → links-Ck-h7SKg.mjs} +57 -57
  118. package/core/built/admin/assets/posts/{loading-indicator-BZsjmp8g.mjs → loading-indicator-B_rU9Lie.mjs} +3 -3
  119. package/core/built/admin/assets/posts/mail-DiZ3oKEW.mjs +9 -0
  120. package/core/built/admin/assets/posts/{main-layout-D_HHTP_n.mjs → main-layout-aYo6qOBZ.mjs} +2 -2
  121. package/core/built/admin/assets/posts/{newsletter-BRzgjOIa.mjs → newsletter-BQc53TF2.mjs} +31 -30
  122. package/core/built/admin/assets/posts/{overview-C41VFjn7.mjs → overview-blz9Ak9q.mjs} +42 -41
  123. package/core/built/admin/assets/posts/plus-YVjtYaK3.mjs +15 -0
  124. package/core/built/admin/assets/posts/{post-analytics-DGgMkFaf.mjs → post-analytics-BQbWGoeu.mjs} +6 -6
  125. package/core/built/admin/assets/posts/{post-analytics-context-B1r3HBrp.mjs → post-analytics-context-Be7THgnd.mjs} +7 -7
  126. package/core/built/admin/assets/posts/{post-analytics-header-DTWSO0Aq.mjs → post-analytics-header-iDFy7Bao.mjs} +2762 -2764
  127. package/core/built/admin/assets/posts/{post-share-modal-ohHwk0Yt.mjs → post-share-modal-akP16idN.mjs} +50 -48
  128. package/core/built/admin/assets/posts/posts.js +2 -1
  129. package/core/built/admin/assets/posts/{settings-CZYL6Jhr.mjs → settings-BdQhfHxY.mjs} +2 -2
  130. package/core/built/admin/assets/posts/{sheet-D7YesQJE.mjs → sheet-3dBlKeXf.mjs} +14 -13
  131. package/core/built/admin/assets/posts/{skeleton-S1k58YKa.mjs → skeleton-DMgSvYqr.mjs} +11 -11
  132. package/core/built/admin/assets/posts/{source-icon-DnpCy5N4.mjs → source-icon-Bp5Qxq1E.mjs} +4 -4
  133. package/core/built/admin/assets/posts/{stats-CbOpowXb.mjs → stats-DJx9qc_u.mjs} +4 -4
  134. package/core/built/admin/assets/posts/{table-Cw3Wxf1C.mjs → table-BpVwuzeH.mjs} +2 -2
  135. package/core/built/admin/assets/posts/{data-list-BnZARP88.mjs → tabs-CbZCpxfI.mjs} +4885 -5284
  136. package/core/built/admin/assets/posts/{tags-BoMt6Ce3.mjs → tags-CNtvDS6f.mjs} +33 -33
  137. package/core/built/admin/assets/posts/{tags-CNdsvTtZ.mjs → tags-DFOoFZ_3.mjs} +2 -2
  138. package/core/built/admin/assets/posts/{tooltip-CTcyINxz.mjs → tooltip-Cc_09RDU.mjs} +106 -117
  139. package/core/built/admin/assets/posts/value-CwGM7M-1.mjs +410 -0
  140. package/core/built/admin/assets/posts/{virtual-list-window-Bs88yrut.mjs → virtual-list-window-D6nRoL0y.mjs} +5 -5
  141. package/core/built/admin/assets/posts/{web-Bsd8eTP6.mjs → web-yfPssEt8.mjs} +1042 -1040
  142. package/core/built/admin/assets/posts/x-DrUGcpfp.mjs +9 -0
  143. package/core/built/admin/assets/posts/zap-DAN0ur-o.mjs +24 -0
  144. package/core/built/admin/assets/posts-D-jyPPE6.js +1 -0
  145. package/core/built/admin/assets/power-Cc5ncYVl.js +1 -0
  146. package/core/built/admin/assets/{referrers-kcBT5smx.js → referrers-qnXsKsuv.js} +1 -1
  147. package/core/built/admin/assets/{repeat-Cn2sKd-L.js → repeat-BGIBynZH.js} +1 -1
  148. package/core/built/admin/assets/{reply-D7E-ZMd5.js → reply-DOKdAsL_.js} +1 -1
  149. package/core/built/admin/assets/{rocket-DnH0XAGW.js → rocket-CAN2NB82.js} +1 -1
  150. package/core/built/admin/assets/{select-f0MMMQWu.js → select-8S9kYGSM.js} +1 -1
  151. package/core/built/admin/assets/{settings-BAQNP3gU.js → settings-DeD-bmZc.js} +4 -4
  152. package/core/built/admin/assets/{settings-ORttG1jT.js → settings-e4IB9sx6.js} +1 -1
  153. package/core/built/admin/assets/{share-modal-CXU4tGY8.js → share-modal-CBavk20I.js} +1 -1
  154. package/core/built/admin/assets/{sort-button-BXMrChFu.js → sort-button-DlSKBzUq.js} +1 -1
  155. package/core/built/admin/assets/{source-icon-cjy79jGT.js → source-icon-27VIJSXr.js} +1 -1
  156. package/core/built/admin/assets/{sprout-DZ4tZ78G.js → sprout-D66nqc79.js} +1 -1
  157. package/core/built/admin/assets/{square-vOzqJf7x.js → square-DccaXQWe.js} +1 -1
  158. package/core/built/admin/assets/stats/{audience-5NeJICtP.mjs → audience-B84ClTDM.mjs} +3 -3
  159. package/core/built/admin/assets/stats/{content-helpers-DFSTl3uB.mjs → content-helpers-CBAddUg7.mjs} +4 -4
  160. package/core/built/admin/assets/stats/{index-C4T7u699.mjs → index-Bz5oVpED.mjs} +5 -5
  161. package/core/built/admin/assets/stats/{index-B8bp6qe2.mjs → index-Cs8i1uR4.mjs} +74 -75
  162. package/core/built/admin/assets/stats/{index-wvi17m79.mjs → index-DEsP_Tbd.mjs} +8 -8
  163. package/core/built/admin/assets/stats/{index-CFfAYHdD.mjs → index-Ds-pM47x.mjs} +5 -5
  164. package/core/built/admin/assets/stats/{index-Chqk7VlR.mjs → index-Wzk1IcAz.mjs} +6 -6
  165. package/core/built/admin/assets/stats/{kpi-tabs-Df9yOI2P.mjs → kpi-tabs-Cs4l8B_M.mjs} +7 -7
  166. package/core/built/admin/assets/stats/{sort-button-Doi8OgMU.mjs → sort-button-rR-GA9Hu.mjs} +3 -3
  167. package/core/built/admin/assets/stats/{stats-FXeCefyd.mjs → stats-RFpEJpEq.mjs} +34 -34
  168. package/core/built/admin/assets/stats/stats.js +1 -1
  169. package/core/built/admin/assets/stats/{use-growth-stats-93C_3EZk.mjs → use-growth-stats-DwgFzbq9.mjs} +3 -3
  170. package/core/built/admin/assets/{stats-CIGz2Win.js → stats-B4OybenW.js} +1 -1
  171. package/core/built/admin/assets/{stats-view-BTKRxYTQ.js → stats-view-BuExwFXa.js} +1 -1
  172. package/core/built/admin/assets/{step-1-BSMHbT-q.js → step-1-D_5LOQrC.js} +1 -1
  173. package/core/built/admin/assets/{step-2-_YC0LCZv.js → step-2-BZLBj8cj.js} +1 -1
  174. package/core/built/admin/assets/{step-3-DWMqP2bO.js → step-3-s5uNbcOH.js} +1 -1
  175. package/core/built/admin/assets/{table-mHKjXQba.js → table-pGS7EeJe.js} +1 -1
  176. package/core/built/admin/assets/{tabs-B93IVRBz.js → tabs-CjdKssUe.js} +1 -1
  177. package/core/built/admin/assets/{tags-DCb-x2ZB.js → tags-B0vRk0A6.js} +1 -1
  178. package/core/built/admin/assets/{tags-kUHJ1MZo.js → tags-Dso4-FA_.js} +1 -1
  179. package/core/built/admin/assets/{textarea-DswCtM7_.js → textarea-DzFnun0_.js} +1 -1
  180. package/core/built/admin/assets/{tiers-DueraQKd.js → tiers-4Vkr_D-L.js} +1 -1
  181. package/core/built/admin/assets/{toggle-group-ChTo8MPD.js → toggle-group-hDsr47IB.js} +1 -1
  182. package/core/built/admin/assets/{topic-filter-DrW3fYWo.js → topic-filter-C7TpPe1G.js} +1 -1
  183. package/core/built/admin/assets/{trash-B2ESGftj.js → trash-DCVuk7ZX.js} +1 -1
  184. package/core/built/admin/assets/{underline-vo-bPRac.js → underline-CjK8la2G.js} +1 -1
  185. package/core/built/admin/assets/{upload-DXQRkBBq.js → upload-CPYhmtWZ.js} +1 -1
  186. package/core/built/admin/assets/{use-growth-stats-CoB8-lsd.js → use-growth-stats-CaFSgp_R.js} +1 -1
  187. package/core/built/admin/assets/{use-simple-pagination-Y_Wv2N6g.js → use-simple-pagination-D0vJBMvF.js} +1 -1
  188. package/core/built/admin/assets/{user-round-check-Dp9a2x-e.js → user-round-check-CzQQeFd8.js} +1 -1
  189. package/core/built/admin/assets/{user-round-x-DwCTGlxc.js → user-round-x-BDFm8yQj.js} +1 -1
  190. package/core/built/admin/assets/value-BGBiTkF3.js +1 -0
  191. package/core/built/admin/assets/{vendor-17f3b979ba6f3898d1a8c5249cc22ff1.js → vendor-ce3fc901ccbcf37f36eb791b4e454138.js} +29 -31
  192. package/core/built/admin/assets/{virtual-list-window-BF7IvGMC.js → virtual-list-window-EKtWZ5cP.js} +1 -1
  193. package/core/built/admin/assets/{wallet-cards-IEmcxJvG.js → wallet-cards-C1NOBbWE.js} +1 -1
  194. package/core/built/admin/assets/web-DCA7HR1S.js +1 -0
  195. package/core/built/admin/index.html +8 -8
  196. package/core/frontend/helpers/social_accounts.js +91 -0
  197. package/core/frontend/services/sitemap/handler.js +14 -2
  198. package/core/frontend/services/sitemap/site-map-manager.js +133 -9
  199. package/core/frontend/web/middleware/handle-image-sizes.js +4 -0
  200. package/core/server/api/endpoints/automations.js +38 -45
  201. package/core/server/models/member.js +30 -25
  202. package/core/server/services/automations/automations-api.js +58 -0
  203. package/core/server/services/automations/automations-api.ts +71 -0
  204. package/core/server/services/automations/automations-repository.js +2 -0
  205. package/core/server/services/automations/automations-repository.ts +63 -0
  206. package/core/server/services/automations/fake-database-automations-repository.js +210 -0
  207. package/core/server/services/automations/fake-database-automations-repository.ts +273 -0
  208. package/core/server/services/automations/temporary-fake-database.js +5 -4
  209. package/core/server/services/gifts/email-templates/gift-purchase-confirmation.hbs +10 -32
  210. package/core/server/services/gifts/email-templates/gift-purchase-confirmation.js +6 -8
  211. package/core/server/services/gifts/email-templates/gift-purchase-confirmation.ts +6 -8
  212. package/core/server/services/gifts/email-templates/gift-reminder.hbs +12 -37
  213. package/core/server/services/gifts/email-templates/gift-reminder.js +5 -9
  214. package/core/server/services/gifts/email-templates/gift-reminder.ts +5 -9
  215. package/core/server/services/gifts/gift-service.js +1 -1
  216. package/core/server/services/gifts/gift-service.ts +2 -2
  217. package/core/server/services/member-welcome-emails/service.js +0 -1
  218. package/core/server/services/members/members-api/controllers/router-controller.js +52 -7
  219. package/core/server/services/members/members-api/services/member-bread-service.js +0 -8
  220. package/core/server/services/route-settings/route-settings.js +18 -2
  221. package/core/server/services/staff/email-templates/gift.hbs +1 -1
  222. package/core/server/services/staff/email-templates/gift.txt.js +1 -1
  223. package/core/server/services/staff/email-templates/new-gift-subscription.hbs +1 -1
  224. package/core/server/services/staff/email-templates/new-gift-subscription.txt.js +1 -1
  225. package/core/server/services/staff/staff-service-emails.js +1 -1
  226. package/core/server/services/url/index.js +16 -1
  227. package/core/server/services/url/lazy-find-resource.js +49 -0
  228. package/core/server/services/url/lazy-find-resource.ts +62 -0
  229. package/core/server/services/url/lazy-url-service.js +220 -0
  230. package/core/server/services/url/lazy-url-service.ts +265 -0
  231. package/core/server/web/api/endpoints/admin/routes.js +1 -0
  232. package/core/server/web/gift-preview/Inter.ttf +0 -0
  233. package/core/server/web/gift-preview/controller.js +56 -6
  234. package/core/server/web/gift-preview/gift-card-noise.png +0 -0
  235. package/core/server/web/gift-preview/gift-card-orb.png +0 -0
  236. package/core/server/web/gift-preview/image.js +170 -43
  237. package/core/shared/config/defaults.json +1 -0
  238. package/core/shared/one-at-a-time.js +28 -33
  239. package/core/shared/one-at-a-time.ts +58 -0
  240. package/package.json +18 -16
  241. package/pnpm-lock.yaml +989 -356
  242. package/core/built/admin/assets/automations-D1uMjd06.js +0 -1
  243. package/core/built/admin/assets/chart-_EXssQtm.js +0 -67
  244. package/core/built/admin/assets/comments-E00h1SbR.js +0 -1
  245. package/core/built/admin/assets/filters-CC7XfjOS.js +0 -1
  246. package/core/built/admin/assets/gh-chart-B9_ywrJJ.js +0 -1
  247. package/core/built/admin/assets/index-AsV-aY0z.css +0 -1
  248. package/core/built/admin/assets/index-B0y_ynZw.js +0 -1
  249. package/core/built/admin/assets/index-Bs6wWbLA.js +0 -2
  250. package/core/built/admin/assets/index-Cb4641XW.js +0 -1
  251. package/core/built/admin/assets/loader-circle-B5UPqSok.js +0 -1
  252. package/core/built/admin/assets/minus-DWx9VUtr.js +0 -1
  253. package/core/built/admin/assets/newsletter-fkQye9OK.js +0 -1
  254. package/core/built/admin/assets/overview-CZ-VrnXy.js +0 -1
  255. package/core/built/admin/assets/posts/createLucideIcon-DcUfTBt_.mjs +0 -454
  256. package/core/built/admin/assets/posts/get-site-timezone-DlXmHA3y.mjs +0 -93
  257. package/core/built/admin/assets/posts-Bx1RWrub.js +0 -1
  258. package/core/built/admin/assets/web-DSME3e8c.js +0 -1
@@ -0,0 +1,91 @@
1
+ // # Social Accounts Helper
2
+ // Usage:
3
+ // {{#social_accounts @site}}
4
+ // <a href="{{href}}" target="_blank" rel="noopener" aria-label="{{name}}">
5
+ // {{> (concat "icons/" type)}}
6
+ // </a>
7
+ // {{/social_accounts}}
8
+ //
9
+ // Iterates over the social accounts on the given source object in canonical
10
+ // order, yielding `{type, href, username, name}` for each platform with a
11
+ // username set.
12
+ //
13
+ // A source must be passed explicitly:
14
+ // {{#social_accounts @site}} - site-level accounts
15
+ // {{#social_accounts author}} - a specific author
16
+ // {{#social_accounts this}} - the current context (e.g. inside {{#foreach authors}})
17
+ const errors = require('@tryghost/errors');
18
+ const tpl = require('@tryghost/tpl');
19
+ const {socialUrls} = require('../services/proxy');
20
+ const {hbs} = require('../services/handlebars');
21
+
22
+ const createFrame = hbs.handlebars.createFrame;
23
+
24
+ const messages = {
25
+ sourceRequired: 'The {{#social_accounts}} helper requires a source argument, e.g. {{#social_accounts @site}}...{{/social_accounts}}.',
26
+ blockRequired: 'The {{#social_accounts}} helper must be used as a block helper, e.g. {{#social_accounts @site}}...{{/social_accounts}}.'
27
+ };
28
+
29
+ // Canonical order mirrors the admin settings UI (SOCIAL_PLATFORM_KEYS).
30
+ const SOCIAL_PLATFORMS = [
31
+ {type: 'twitter', name: 'X'},
32
+ {type: 'facebook', name: 'Facebook'},
33
+ {type: 'linkedin', name: 'LinkedIn'},
34
+ {type: 'bluesky', name: 'Bluesky'},
35
+ {type: 'threads', name: 'Threads'},
36
+ {type: 'mastodon', name: 'Mastodon'},
37
+ {type: 'tiktok', name: 'TikTok'},
38
+ {type: 'youtube', name: 'YouTube'},
39
+ {type: 'instagram', name: 'Instagram'}
40
+ ];
41
+
42
+ module.exports = function social_accounts(source, options) { // eslint-disable-line camelcase
43
+ // {{#social_accounts}} with no positional arg: handlebars passes only options.
44
+ if (arguments.length < 2) {
45
+ throw new errors.IncorrectUsageError({
46
+ level: 'normal',
47
+ message: tpl(messages.sourceRequired),
48
+ help: 'https://ghost.org/docs/themes/helpers/social-accounts/'
49
+ });
50
+ }
51
+
52
+ options = options || {};
53
+ options.data = options.data || {};
54
+
55
+ const {fn, inverse, data} = options;
56
+
57
+ if (typeof fn !== 'function') {
58
+ throw new errors.IncorrectUsageError({
59
+ level: 'normal',
60
+ message: tpl(messages.blockRequired),
61
+ help: 'https://ghost.org/docs/themes/helpers/social-accounts/'
62
+ });
63
+ }
64
+
65
+ const accounts = SOCIAL_PLATFORMS.reduce((acc, {type, name}) => {
66
+ const username = source && source[type];
67
+ if (username && typeof socialUrls[type] === 'function') {
68
+ acc.push({type, name, username, href: socialUrls[type](username)});
69
+ }
70
+ return acc;
71
+ }, []);
72
+
73
+ if (!accounts.length) {
74
+ return inverse ? inverse(this) : '';
75
+ }
76
+
77
+ const frame = createFrame(data);
78
+ let output = '';
79
+
80
+ accounts.forEach((account, index) => {
81
+ frame.index = index;
82
+ frame.number = index + 1;
83
+ frame.first = index === 0;
84
+ frame.last = index === accounts.length - 1;
85
+ frame.even = index % 2 === 1;
86
+ frame.odd = !frame.even;
87
+ output += fn(account, {data: frame});
88
+ });
89
+
90
+ return output;
91
+ };
@@ -13,7 +13,13 @@ module.exports = function handler(siteApp) {
13
13
  next();
14
14
  };
15
15
 
16
- siteApp.get('/sitemap.xml', function sitemapXML(req, res) {
16
+ siteApp.get('/sitemap.xml', async function sitemapXML(req, res, next) {
17
+ try {
18
+ await manager.ensurePopulatedFromDatabase();
19
+ } catch (err) {
20
+ return next(err);
21
+ }
22
+
17
23
  res.set({
18
24
  'Cache-Control': 'public, max-age=' + config.get('caching:sitemap:maxAge'),
19
25
  'Content-Type': 'text/xml'
@@ -22,11 +28,17 @@ module.exports = function handler(siteApp) {
22
28
  res.send(manager.getIndexXml());
23
29
  });
24
30
 
25
- siteApp.get('/sitemap-:resource.xml', verifyResourceType, function sitemapResourceXML(req, res) {
31
+ siteApp.get('/sitemap-:resource.xml', verifyResourceType, async function sitemapResourceXML(req, res, next) {
26
32
  const type = req.params.resource.replace(/-\d+$/, '');
27
33
  const pageParam = (req.params.resource.match(/-(\d+)$/) || [null, null])[1];
28
34
  const page = pageParam ? parseInt(pageParam, 10) : 1;
29
35
 
36
+ try {
37
+ await manager.ensurePopulatedFromDatabase();
38
+ } catch (err) {
39
+ return next(err);
40
+ }
41
+
30
42
  const content = manager.getSiteMapXml(type, page);
31
43
  // Prevent x-1.xml as it is a duplicate of x.xml and empty sitemaps
32
44
  // (except for the first page so that at least one sitemap exists per type)
@@ -1,5 +1,7 @@
1
1
  const DomainEvents = require('@tryghost/domain-events');
2
+ const config = require('../../../shared/config');
2
3
  const {URLResourceUpdatedEvent} = require('../../../shared/events');
4
+ const toPlain = require('../../../server/lib/common/to-plain');
3
5
  const IndexMapGenerator = require('./site-map-index-generator');
4
6
  const PagesMapGenerator = require('./page-map-generator');
5
7
  const PostsMapGenerator = require('./post-map-generator');
@@ -21,6 +23,20 @@ class SiteMapManager {
21
23
  this.tags = options.tags || this.createTagsGenerator(options);
22
24
  this.index = options.index || this.createIndexGenerator(options);
23
25
 
26
+ // The lazy URL service does not fire url.added / url.removed /
27
+ // URLResourceUpdatedEvent. When that mode is active the sitemap
28
+ // populates itself from the database on first request instead.
29
+ this._lazyRouting = options.lazyRouting === undefined
30
+ ? config.get('lazyRouting')
31
+ : options.lazyRouting;
32
+ this._populated = false;
33
+ this._populating = null;
34
+ // Each routers.reset bumps this generation. An in-flight populate
35
+ // captures the generation it started in; if that generation is no
36
+ // longer current when the populate settles, its result is discarded
37
+ // so we don't mark a stale (potentially mid-reset) lookup as ready.
38
+ this._populationGeneration = 0;
39
+
24
40
  events.on('router.created', (router) => {
25
41
  if (router.name === 'StaticRoutesRouter') {
26
42
  this.pages.addUrl(router.getRoute({absolute: true}), {id: router.identifier, staticRoute: true});
@@ -31,23 +47,31 @@ class SiteMapManager {
31
47
  }
32
48
  });
33
49
 
34
- DomainEvents.subscribe(URLResourceUpdatedEvent, (event) => {
35
- this[event.data.resourceType].updateURL(event.data);
36
- });
50
+ if (!this._lazyRouting) {
51
+ DomainEvents.subscribe(URLResourceUpdatedEvent, (event) => {
52
+ this[event.data.resourceType].updateURL(event.data);
53
+ });
37
54
 
38
- events.on('url.added', (obj) => {
39
- this[obj.resource.config.type].addUrl(obj.url.absolute, obj.resource.data);
40
- });
55
+ events.on('url.added', (obj) => {
56
+ this[obj.resource.config.type].addUrl(obj.url.absolute, obj.resource.data);
57
+ });
41
58
 
42
- events.on('url.removed', (obj) => {
43
- this[obj.resource.config.type].removeUrl(obj.url.absolute, obj.resource.data);
44
- });
59
+ events.on('url.removed', (obj) => {
60
+ this[obj.resource.config.type].removeUrl(obj.url.absolute, obj.resource.data);
61
+ });
62
+ }
45
63
 
46
64
  events.on('routers.reset', () => {
47
65
  this.pages && this.pages.reset();
48
66
  this.posts && this.posts.reset();
49
67
  this.users && this.users.reset();
50
68
  this.tags && this.tags.reset();
69
+ // Force the next sitemap request to repopulate from the DB.
70
+ // Bumping the generation invalidates any populate currently in
71
+ // flight (its `.then` will see a stale generation and bail).
72
+ this._populated = false;
73
+ this._populating = null;
74
+ this._populationGeneration += 1;
51
75
  });
52
76
  }
53
77
 
@@ -86,6 +110,106 @@ class SiteMapManager {
86
110
  getSiteMapXml(type, page) {
87
111
  return this[type].getXml(page);
88
112
  }
113
+
114
+ /**
115
+ * Populate the sitemap from the database. Used when the lazy URL service
116
+ * is active and the URL-added/-removed events are not firing. Idempotent;
117
+ * a second call is a no-op while the first is in flight or has finished.
118
+ */
119
+ async ensurePopulatedFromDatabase() {
120
+ if (!this._lazyRouting || this._populated) {
121
+ return;
122
+ }
123
+ if (this._populating) {
124
+ return this._populating;
125
+ }
126
+ const generation = this._populationGeneration;
127
+ const populating = this._populateFromDatabase().then(
128
+ () => {
129
+ // If a routers.reset happened while we were running, the
130
+ // generators have been wiped. Don't flip _populated; let the
131
+ // next request kick off a fresh populate.
132
+ if (this._populationGeneration === generation) {
133
+ this._populated = true;
134
+ }
135
+ // Only clear our own handle. routers.reset already nulled
136
+ // _populating and a successor populate may have replaced it
137
+ // — clobbering would orphan the successor.
138
+ if (this._populating === populating) {
139
+ this._populating = null;
140
+ }
141
+ },
142
+ (err) => {
143
+ if (this._populating === populating) {
144
+ this._populating = null;
145
+ }
146
+ throw err;
147
+ }
148
+ );
149
+ this._populating = populating;
150
+ return this._populating;
151
+ }
152
+
153
+ async _populateFromDatabase() {
154
+ const models = require('../../../server/models');
155
+ const urlService = require('../../../server/services/url');
156
+ const facade = urlService.facade;
157
+
158
+ // Use TagPublic/Author for the shouldHavePosts gate (so tags/users
159
+ // with no published posts are excluded). The visibility filter is
160
+ // applied in TYPE_BROWSE_OPTIONS below; together these mirror what
161
+ // the eager URL service does in services/url/config.js.
162
+ await Promise.all([
163
+ this._loadType(models.Post, 'posts', this.posts, facade),
164
+ this._loadType(models.Post, 'pages', this.pages, facade),
165
+ this._loadType(models.TagPublic, 'tags', this.tags, facade),
166
+ this._loadType(models.Author, 'authors', this.users, facade)
167
+ ]);
168
+ }
169
+
170
+ async _loadType(Model, type, generator, facade) {
171
+ const baseOptions = browseOptionsFor(type);
172
+ let page = 1;
173
+ // eslint-disable-next-line no-constant-condition
174
+ while (true) {
175
+ const result = await Model.findPage({...baseOptions, page});
176
+ for (const model of result.data) {
177
+ const datum = toPlain(model);
178
+ const url = facade.getUrlForResource({...datum, type}, {absolute: true});
179
+ if (url && !url.match(/\/404\//)) {
180
+ generator.addUrl(url, datum);
181
+ }
182
+ }
183
+ const totalPages = result?.meta?.pagination?.pages;
184
+ // Guard against unexpected response shapes (missing meta,
185
+ // empty page) so we don't loop forever.
186
+ if (!totalPages || page >= totalPages || result.data.length === 0) {
187
+ break;
188
+ }
189
+ page += 1;
190
+ }
191
+ }
192
+ }
193
+
194
+ // Per-router-type browse options for the lazy populate path. Mirrors the
195
+ // eager URL service's resource queries (services/url/config.js): posts/pages
196
+ // filter by published+type, tags/authors by visibility:public.
197
+ //
198
+ // `withRelated: ['tags', 'authors']` for posts: needed so the Bookshelf
199
+ // model's toJSON output includes `primary_tag` and `primary_author`, which
200
+ // custom permalink templates like `/:primary_tag/:slug/` evaluate against.
201
+ // Without this preload the lazy sitemap would emit `/undefined/.../` for
202
+ // any site using a primary_tag/primary_author permalink. Pages exclude
203
+ // these in the eager config so we mirror that.
204
+ const TYPE_BROWSE_OPTIONS = {
205
+ posts: {limit: 200, status: 'published', filter: 'type:post', withRelated: ['tags', 'authors']},
206
+ pages: {limit: 200, status: 'published', filter: 'type:page'},
207
+ tags: {limit: 200, filter: 'visibility:public'},
208
+ authors: {limit: 200, filter: 'visibility:public'}
209
+ };
210
+
211
+ function browseOptionsFor(type) {
212
+ return TYPE_BROWSE_OPTIONS[type] || {limit: 200};
89
213
  }
90
214
 
91
215
  module.exports = SiteMapManager;
@@ -48,6 +48,10 @@ module.exports = function handleImageSizes(req, res, next) {
48
48
  if (format) {
49
49
  url = url.replace(`/format/${format}`, '');
50
50
  }
51
+
52
+ // Strip multiple leading slashes to prevent protocol-relative redirects
53
+ url = url.replace(/^\/+/, '/');
54
+
51
55
  return res.redirect(url);
52
56
  };
53
57
 
@@ -1,6 +1,12 @@
1
- const domainEvents = require('@tryghost/domain-events');
2
- const models = require('../../models');
3
- const StartAutomationsPollEvent = require('../../services/automations/events/start-automations-poll-event');
1
+ const errors = require('@tryghost/errors');
2
+ const automationsApi = require('../../services/automations/automations-api');
3
+
4
+ const VALID_AUTOMATION_STATUSES = ['active', 'inactive'];
5
+
6
+ const messages = {
7
+ invalidAutomationStatus: 'Automation status must be one of: active, inactive.',
8
+ invalidAutomationStatusHelp: 'Use "active" or "inactive" for automation status.'
9
+ };
4
10
 
5
11
  /** @type {import('@tryghost/api-framework').Controller} */
6
12
  const controller = {
@@ -12,15 +18,7 @@ const controller = {
12
18
  },
13
19
  permissions: true,
14
20
  async query() {
15
- const automations = await models.WelcomeEmailAutomation.findAll();
16
- return {
17
- data: automations.map(automation => ({
18
- id: automation.get('id'),
19
- name: automation.get('name'),
20
- slug: automation.get('slug'),
21
- status: automation.get('status')
22
- }))
23
- };
21
+ return await automationsApi.browse();
24
22
  }
25
23
  },
26
24
 
@@ -32,38 +30,33 @@ const controller = {
32
30
  'id'
33
31
  ],
34
32
  permissions: true,
35
- query(frame) {
36
- // TODO: NY-1265 - replace this static payload with persisted automation data.
37
- return {
38
- id: frame.data.id,
39
- slug: 'member-welcome-email-free',
40
- name: 'Welcome email',
41
- status: 'active',
42
- created_at: '2026-05-05T00:00:00.000Z',
43
- updated_at: '2026-05-05T00:00:00.000Z',
44
- actions: [{
45
- id: '67f3f3f3f3f3f3f3f3f3f3f4',
46
- type: 'delay',
47
- data: {
48
- delay_hours: 24
49
- }
50
- }, {
51
- id: '67f3f3f3f3f3f3f3f3f3f3f5',
52
- type: 'send email',
53
- data: {
54
- email_subject: 'Welcome!',
55
- email_lexical: '{"root":{"children":[]}}',
56
- email_sender_name: null,
57
- email_sender_email: null,
58
- email_sender_reply_to: null,
59
- email_design_setting_id: '680000000000000000000001'
60
- }
61
- }],
62
- edges: [{
63
- source_action_id: '67f3f3f3f3f3f3f3f3f3f3f4',
64
- target_action_id: '67f3f3f3f3f3f3f3f3f3f3f5'
65
- }]
66
- };
33
+ async query(frame) {
34
+ return await automationsApi.read(frame.data.id);
35
+ }
36
+ },
37
+
38
+ edit: {
39
+ headers: {
40
+ cacheInvalidate: false
41
+ },
42
+ options: [
43
+ 'id'
44
+ ],
45
+ validation(frame) {
46
+ const status = frame.data?.automations?.[0]?.status;
47
+
48
+ if (!VALID_AUTOMATION_STATUSES.includes(status)) {
49
+ throw new errors.ValidationError({
50
+ message: messages.invalidAutomationStatus,
51
+ context: status === undefined ? undefined : `Received status "${status}".`,
52
+ help: messages.invalidAutomationStatusHelp,
53
+ property: 'status'
54
+ });
55
+ }
56
+ },
57
+ permissions: true,
58
+ async query(frame) {
59
+ return await automationsApi.edit(frame.options.id, frame.data.automations[0]);
67
60
  }
68
61
  },
69
62
 
@@ -77,7 +70,7 @@ const controller = {
77
70
  method: 'poll'
78
71
  },
79
72
  query() {
80
- domainEvents.dispatch(StartAutomationsPollEvent.create());
73
+ automationsApi.requestPoll();
81
74
  }
82
75
  }
83
76
  };
@@ -312,32 +312,29 @@ const Member = ghostBookshelf.Model.extend({
312
312
  },
313
313
 
314
314
  onSaving: function onSaving(model, attr, options) {
315
- let labelsToSave = [];
315
+ const rawLabels = this.get('labels');
316
316
 
317
- if (_.isUndefined(this.get('labels'))) {
317
+ if (_.isUndefined(rawLabels)) {
318
318
  this.unset('labels');
319
319
  return;
320
320
  }
321
321
 
322
- // CASE: detect lowercase/uppercase label slugs
323
- if (!_.isUndefined(this.get('labels')) && !_.isNull(this.get('labels'))) {
324
- labelsToSave = [];
325
-
326
- // and deduplicate upper/lowercase tags
327
- _.each(this.get('labels'), function each(item) {
328
- item.name = item.name && item.name.trim();
329
- for (let i = 0; i < labelsToSave.length; i = i + 1) {
330
- if (labelsToSave[i].name && item.name && labelsToSave[i].name.toLocaleLowerCase() === item.name.toLocaleLowerCase()) {
331
- return;
332
- }
333
- }
334
-
335
- labelsToSave.push(item);
336
- });
337
-
338
- this.set('labels', labelsToSave);
339
- }
322
+ // CASE: trim, drop nameless, and dedupe by case-insensitive name (first wins)
323
+ const seen = new Set();
324
+ const labelsToSave = (rawLabels || []).filter((item) => {
325
+ item.name = item.name && item.name.trim();
326
+ if (!item.name) {
327
+ return false;
328
+ }
329
+ const key = item.name.toLowerCase();
330
+ if (seen.has(key)) {
331
+ return false;
332
+ }
333
+ seen.add(key);
334
+ return true;
335
+ });
340
336
 
337
+ this.set('labels', labelsToSave);
341
338
  this.handleAttachedModels(model);
342
339
 
343
340
  // CASE: Detect existing labels with same case-insensitive name and replace
@@ -346,12 +343,20 @@ const Member = ghostBookshelf.Model.extend({
346
343
  columns: ['id', 'name']
347
344
  }, _.pick(options, 'transacting')))
348
345
  .then((labels) => {
346
+ const existingByName = new Map();
347
+ for (const lab of labels.models) {
348
+ const name = lab.get('name');
349
+ if (name) {
350
+ existingByName.set(name.toLowerCase(), lab);
351
+ }
352
+ }
353
+
349
354
  labelsToSave.forEach((label) => {
350
- let existingLabel = labels.find((lab) => {
351
- return label.name.toLowerCase() === lab.get('name').toLowerCase();
352
- });
353
- label.name = (existingLabel && existingLabel.get('name')) || label.name;
354
- label.id = (existingLabel && existingLabel.id) || label.id;
355
+ const match = existingByName.get(label.name.toLowerCase());
356
+ if (match) {
357
+ label.name = match.get('name');
358
+ label.id = match.id;
359
+ }
355
360
  });
356
361
 
357
362
  model.set('labels', labelsToSave);
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ /* eslint-disable @typescript-eslint/no-require-imports */
7
+ const errors_1 = __importDefault(require("@tryghost/errors"));
8
+ const tpl_1 = __importDefault(require("@tryghost/tpl"));
9
+ const fake_database_automations_repository_1 = require("./fake-database-automations-repository");
10
+ const domainEvents = require('@tryghost/domain-events');
11
+ const StartAutomationsPollEvent = require('./events/start-automations-poll-event');
12
+ const temporaryFakeAutomationsDatabase = require('./temporary-fake-database');
13
+ const messages = {
14
+ automationNotFound: 'Automation not found.'
15
+ };
16
+ let testDatabase = null;
17
+ const repository = (0, fake_database_automations_repository_1.createFakeDatabaseAutomationsRepository)({
18
+ getDatabase: () => {
19
+ if (process.env.NODE_ENV?.startsWith('testing')) {
20
+ testDatabase ??= temporaryFakeAutomationsDatabase.createTemporaryFakeAutomationsDatabase();
21
+ return testDatabase;
22
+ }
23
+ return temporaryFakeAutomationsDatabase.getTemporaryFakeAutomationsDatabase();
24
+ }
25
+ });
26
+ async function browse() {
27
+ return await repository.browse();
28
+ }
29
+ async function read(automationId) {
30
+ const automation = await repository.getById(automationId);
31
+ if (!automation) {
32
+ throw new errors_1.default.NotFoundError({
33
+ message: (0, tpl_1.default)(messages.automationNotFound)
34
+ });
35
+ }
36
+ return automation;
37
+ }
38
+ async function edit(automationId, data) {
39
+ // TODO (NY-1229): Allow updating other fields and actions/edges.
40
+ const automation = await repository.edit(automationId, {
41
+ status: data.status
42
+ });
43
+ if (!automation) {
44
+ throw new errors_1.default.NotFoundError({
45
+ message: (0, tpl_1.default)(messages.automationNotFound)
46
+ });
47
+ }
48
+ return automation;
49
+ }
50
+ function requestPoll() {
51
+ domainEvents.dispatch(StartAutomationsPollEvent.create());
52
+ }
53
+ module.exports = {
54
+ browse,
55
+ edit,
56
+ read,
57
+ requestPoll
58
+ };
@@ -0,0 +1,71 @@
1
+ /* eslint-disable @typescript-eslint/no-require-imports */
2
+ import errors from '@tryghost/errors';
3
+ import tpl from '@tryghost/tpl';
4
+ import type {DatabaseSync} from 'node:sqlite';
5
+ import {createFakeDatabaseAutomationsRepository} from './fake-database-automations-repository';
6
+
7
+ const domainEvents = require('@tryghost/domain-events');
8
+ const StartAutomationsPollEvent = require('./events/start-automations-poll-event');
9
+ const temporaryFakeAutomationsDatabase = require('./temporary-fake-database');
10
+
11
+ const messages = {
12
+ automationNotFound: 'Automation not found.'
13
+ };
14
+
15
+ interface EditAutomationData {
16
+ status: string;
17
+ }
18
+
19
+ let testDatabase: DatabaseSync | null = null;
20
+
21
+ const repository = createFakeDatabaseAutomationsRepository({
22
+ getDatabase: () => {
23
+ if (process.env.NODE_ENV?.startsWith('testing')) {
24
+ testDatabase ??= temporaryFakeAutomationsDatabase.createTemporaryFakeAutomationsDatabase();
25
+ return testDatabase;
26
+ }
27
+ return temporaryFakeAutomationsDatabase.getTemporaryFakeAutomationsDatabase();
28
+ }
29
+ });
30
+
31
+ async function browse() {
32
+ return await repository.browse();
33
+ }
34
+
35
+ async function read(automationId: string) {
36
+ const automation = await repository.getById(automationId);
37
+
38
+ if (!automation) {
39
+ throw new errors.NotFoundError({
40
+ message: tpl(messages.automationNotFound)
41
+ });
42
+ }
43
+
44
+ return automation;
45
+ }
46
+
47
+ async function edit(automationId: string, data: EditAutomationData) {
48
+ // TODO (NY-1229): Allow updating other fields and actions/edges.
49
+ const automation = await repository.edit(automationId, {
50
+ status: data.status
51
+ });
52
+
53
+ if (!automation) {
54
+ throw new errors.NotFoundError({
55
+ message: tpl(messages.automationNotFound)
56
+ });
57
+ }
58
+
59
+ return automation;
60
+ }
61
+
62
+ function requestPoll() {
63
+ domainEvents.dispatch(StartAutomationsPollEvent.create());
64
+ }
65
+
66
+ module.exports = {
67
+ browse,
68
+ edit,
69
+ read,
70
+ requestPoll
71
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });