ghost 6.44.0 → 6.44.1

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 (267) hide show
  1. package/core/boot.js +9 -13
  2. package/core/bridge.js +6 -10
  3. package/core/built/admin/assets/{PolarAngleAxis-eFuSrR7S.js → PolarAngleAxis-DWP6qq-Z.js} +2 -2
  4. package/core/built/admin/assets/{_baseAssignValue-XVHfKew7.js → _baseAssignValue-N9f4o_XK.js} +1 -1
  5. package/core/built/admin/assets/{a-large-small-DOzPDzKp.js → a-large-small-BOAtcFiE.js} +1 -1
  6. package/core/built/admin/assets/{account-migration-Cx45M5qm.js → account-migration-CtZx_5ib.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-Bi8Orhyj.mjs → code-editor-view-BMovCjer.mjs} +2 -2
  9. package/core/built/admin/assets/admin-x-settings/{index-1_V9g9Pt.mjs → index-BT1n-g2b.mjs} +3 -3
  10. package/core/built/admin/assets/admin-x-settings/{index-e9saYQJa.mjs → index-BnowNBGd.mjs} +5 -5
  11. package/core/built/admin/assets/admin-x-settings/{index-CnvQi01U.mjs → index-CRpK6gF8.mjs} +3 -3
  12. package/core/built/admin/assets/admin-x-settings/{index-BmU6BOfy.mjs → index-CfXS3AZ8.mjs} +3 -3
  13. package/core/built/admin/assets/admin-x-settings/{index-EuMiBt6I.mjs → index-Cs8zML6u.mjs} +3 -3
  14. package/core/built/admin/assets/admin-x-settings/{index-B43MPc5u.mjs → index-DmpwO1w3.mjs} +2 -2
  15. package/core/built/admin/assets/admin-x-settings/{index-DOgG0XZa.mjs → index-DwFIdhcR.mjs} +3 -3
  16. package/core/built/admin/assets/admin-x-settings/{index-CWdxMIcZ.mjs → index-sNyPiIJA.mjs} +2 -2
  17. package/core/built/admin/assets/admin-x-settings/{index-Ojg_pBvq.mjs → index-xTILut54.mjs} +1259 -1259
  18. package/core/built/admin/assets/admin-x-settings/{modals-Ckbx9UQF.mjs → modals-Cm5t13os.mjs} +9 -9
  19. package/core/built/admin/assets/{arrow-right-DckEQtp9.js → arrow-right-BxdHN_En.js} +1 -1
  20. package/core/built/admin/assets/{at-sign-BChf68aS.js → at-sign-Cajf-dOf.js} +1 -1
  21. package/core/built/admin/assets/{audience-BYU5Bd7D.js → audience-CHNb9mCT.js} +1 -1
  22. package/core/built/admin/assets/{automated-email-design-Z26Qit0_.js → automated-email-design-B9C9mKUS.js} +2 -2
  23. package/core/built/admin/assets/{automated-emails-aBicreLv.js → automated-emails-DhLhkq8L.js} +1 -1
  24. package/core/built/admin/assets/{automations-vpH-d72N.js → automations-6-cgZovk.js} +1 -1
  25. package/core/built/admin/assets/{automations-Ddo22yPk.js → automations-CxJ-N_YK.js} +1 -1
  26. package/core/built/admin/assets/{avatar-flipboard-CoI3LQ-o.js → avatar-flipboard-f5nSMmek.js} +1 -1
  27. package/core/built/admin/assets/{bluesky-sharing-iVDkCMKN.js → bluesky-sharing-Dm2k8qZH.js} +1 -1
  28. package/core/built/admin/assets/{chart-CjM1VQqH.js → chart-BbJnjWey.js} +23 -23
  29. package/core/built/admin/assets/{checkbox-CC5kd_Kf.js → checkbox-CT7DNFAI.js} +1 -1
  30. package/core/built/admin/assets/{chevron-up-D__wzyXT.js → chevron-up-BxijmTT9.js} +1 -1
  31. package/core/built/admin/assets/{chunk.696.79505fa556d329d6e824.js → chunk.167.37bb0d7f6ac67fefa679.js} +3184 -3523
  32. package/core/built/admin/assets/{chunk.696.79505fa556d329d6e824.js.LICENSE.txt → chunk.167.37bb0d7f6ac67fefa679.js.LICENSE.txt} +1 -1
  33. package/core/built/admin/assets/{chunk.524.1ff649a6cc62dc38f538.js → chunk.524.ed812b62217210a913d4.js} +5 -5
  34. package/core/built/admin/assets/{chunk.582.408a40e0095e479e3d11.js → chunk.582.7db5c9f17bca5a484049.js} +6 -6
  35. package/core/built/admin/assets/{chunk.945.835812fcb16029abd7f9.js → chunk.834.f9db7c62b9457db93e8c.js} +3 -3
  36. package/core/built/admin/assets/{code-editor-view-C735d5EA.js → code-editor-view-D8slE0IA.js} +1 -1
  37. package/core/built/admin/assets/{comments-DgFPax3Y.js → comments-BvfR-fA8.js} +1 -1
  38. package/core/built/admin/assets/{content-helpers-DjugSfvm.js → content-helpers-DUWGLvgL.js} +1 -1
  39. package/core/built/admin/assets/{copy-D9JONGcK.js → copy-ht18t5gu.js} +1 -1
  40. package/core/built/admin/assets/{data-list-QWLEHG4y.js → data-list-Daha2dIs.js} +1 -1
  41. package/core/built/admin/assets/{deleted-feed-item-CwSCflTW.js → deleted-feed-item-ChP5bwgi.js} +1 -1
  42. package/core/built/admin/assets/{dropzone-lK_4vpWS.js → dropzone-h_qyk514.js} +1 -1
  43. package/core/built/admin/assets/{edit-profile-BmioJZHv.js → edit-profile-BT8RQpAG.js} +1 -1
  44. package/core/built/admin/assets/editor-s1mqd9_o.js +8 -0
  45. package/core/built/admin/assets/{empty-indicator-Dg64lT_g.js → empty-indicator-BIUvv6JE.js} +1 -1
  46. package/core/built/admin/assets/{en-DCwBNJ98.js → en-BEcDl42w.js} +1 -1
  47. package/core/built/admin/assets/{eye-psLxWnjO.js → eye-TPnIdamu.js} +1 -1
  48. package/core/built/admin/assets/{feed-TUcCSZHL.js → feed-BK3qvLWi.js} +1 -1
  49. package/core/built/admin/assets/{field-Uk8NOvtc.js → field-CSFsrvVy.js} +1 -1
  50. package/core/built/admin/assets/{filter-query-core-CbH_VKcG.js → filter-query-core-R8cQCO2w.js} +1 -1
  51. package/core/built/admin/assets/{filters-DmawZ5Uu.js → filters-Cp1voB1e.js} +1 -1
  52. package/core/built/admin/assets/gh-chart-BFsyOJD_.js +1 -0
  53. package/core/built/admin/assets/{ghost-2baa7ddc3630015f41c0efd13bd586b8.js → ghost-1881362e8a92dae1e3333a0484c173a3.js} +7 -6
  54. package/core/built/admin/assets/{growth-BAl-TyMy.js → growth-DIigOxF1.js} +1 -1
  55. package/core/built/admin/assets/{hash-Q1ou0OMZ.js → hash-B3iFVeCl.js} +1 -1
  56. package/core/built/admin/assets/{inbox-BAOtR6tN.js → inbox-2bPMLikt.js} +1 -1
  57. package/core/built/admin/assets/{index-BnJp51QE.js → index-52qUC8yv.js} +5 -5
  58. package/core/built/admin/assets/{index-BDIwushG.js → index-9j01Aj_X.js} +1 -1
  59. package/core/built/admin/assets/index-B9UVpmey.js +1 -0
  60. package/core/built/admin/assets/{index-DTeOW3Se.js → index-BXc5OF6x.js} +1 -1
  61. package/core/built/admin/assets/{index-Duc21aJ7.js → index-BaGL3IFe.js} +1 -1
  62. package/core/built/admin/assets/{index-DKC8uXHk.js → index-BdozZbt2.js} +2 -2
  63. package/core/built/admin/assets/{index-z951kI4K.js → index-Bgpz7M7i.js} +1 -1
  64. package/core/built/admin/assets/{index-BfSvX9is.js → index-Bp4O7TVf.js} +1 -1
  65. package/core/built/admin/assets/{index-C5S08C6P.js → index-BuqUmpe9.js} +1 -1
  66. package/core/built/admin/assets/{index-D7OtVnbo.js → index-CEF_Ofn0.js} +1 -1
  67. package/core/built/admin/assets/{index-Bs6rUYFS.js → index-CgSVv5Up.js} +58 -58
  68. package/core/built/admin/assets/{index-Ro9qXetv.js → index-Cr6x2czK.js} +1 -1
  69. package/core/built/admin/assets/{index-DJbgQjV6.js → index-CrbZj3Ju.js} +1 -1
  70. package/core/built/admin/assets/{index-BTBcWw_z.js → index-CrlAPDdD.js} +2 -2
  71. package/core/built/admin/assets/{index-B6SD2Qs-.js → index-CtrmMGWT.js} +1 -1
  72. package/core/built/admin/assets/{index-Bw0oyOFd.js → index-D-V_DAdt.js} +1 -1
  73. package/core/built/admin/assets/{index-DAJduTBl.js → index-D0poOSjw.js} +4 -4
  74. package/core/built/admin/assets/{index-CGT3W8fi.js → index-DWVGCPEC.js} +3 -3
  75. package/core/built/admin/assets/index-Dozbr_4s.css +1 -0
  76. package/core/built/admin/assets/{index-FyplpnYQ.js → index-S3Ai3lDy.js} +1 -1
  77. package/core/built/admin/assets/{index-DLr8D_Ks.js → index-VDhA5kgU.js} +1 -1
  78. package/core/built/admin/assets/{index-DRA1fORQ.js → index-fnIFqFMt.js} +1 -1
  79. package/core/built/admin/assets/{index-BhWQZObu.js → index-kA3UcdW7.js} +1 -1
  80. package/core/built/admin/assets/{input-group-DH32syTz.js → input-group-Fdl0S6pw.js} +1 -1
  81. package/core/built/admin/assets/{koenig-lexical-CxVcbgsH.js → koenig-lexical-REiYtzGD.js} +1 -1
  82. package/core/built/admin/assets/{kpi-card-DBWHDi3l.js → kpi-card-BS8vEj4c.js} +1 -1
  83. package/core/built/admin/assets/{kpi-card-BYhzWV5F.js → kpi-card-D3HEfOCP.js} +1 -1
  84. package/core/built/admin/assets/{kpi-tabs-Kxc-utyg.js → kpi-tabs-8vaI7yWq.js} +1 -1
  85. package/core/built/admin/assets/kpis-CkD0Xteg.js +1 -0
  86. package/core/built/admin/assets/label-DT38Gd2T.js +1 -0
  87. package/core/built/admin/assets/{links-Cg8O8ZGP.js → links-BK-azjCL.js} +1 -1
  88. package/core/built/admin/assets/{list-page-D2KCBsiy.js → list-page-DVpac3lc.js} +1 -1
  89. package/core/built/admin/assets/{loader-circle-nmLqhMZL.js → loader-circle-CIq5Cv-9.js} +1 -1
  90. package/core/built/admin/assets/{mail-D7cxYMd5.js → mail-gdeIU06V.js} +1 -1
  91. package/core/built/admin/assets/{main-layout-BXdUkeCo.js → main-layout-B2t-RiNE.js} +1 -1
  92. package/core/built/admin/assets/members-7z-tESWd.js +10 -0
  93. package/core/built/admin/assets/minus-BbGfVkll.js +1 -0
  94. package/core/built/admin/assets/{modals-VRvX8mK0.js → modals-DVIfijEz.js} +3 -3
  95. package/core/built/admin/assets/{moderation-DkT8qVJs.js → moderation-DwzDOhih.js} +1 -1
  96. package/core/built/admin/assets/{newsletter-sUT4ciRJ.js → newsletter-D1N8bUfp.js} +1 -1
  97. package/core/built/admin/assets/{newsletters-BNvAF2Oi.js → newsletters-7GSeQdQe.js} +1 -1
  98. package/core/built/admin/assets/{note-B0JhJv7s.js → note-Bn1-ZWDE.js} +1 -1
  99. package/core/built/admin/assets/offers-BsuLKYy9.js +1 -0
  100. package/core/built/admin/assets/{onboarding-route-IrO_SCb3.js → onboarding-route-C73r9kyO.js} +1 -1
  101. package/core/built/admin/assets/{overview-C2nk_B6i.js → overview-6U5p38zx.js} +1 -1
  102. package/core/built/admin/assets/{pagemenu-BGhty1iq.js → pagemenu-DrueoEX9.js} +1 -1
  103. package/core/built/admin/assets/{pencil-DiA3J4m5.js → pencil-Csnv8udS.js} +1 -1
  104. package/core/built/admin/assets/{pin-off-HWos3YHh.js → pin-off-BDeHGsSQ.js} +1 -1
  105. package/core/built/admin/assets/{post-analytics-context-BJwP-XAB.js → post-analytics-context-jKeUh2Ka.js} +1 -1
  106. package/core/built/admin/assets/{post-analytics-header-CZF5QmAD.js → post-analytics-header-C5QLn6Lm.js} +1 -1
  107. package/core/built/admin/assets/{post-analytics-DBUHbt1b.js → post-analytics-ngMqqbt9.js} +1 -1
  108. package/core/built/admin/assets/{post-share-modal-Bb8R05dH.js → post-share-modal-04B7JT4R.js} +1 -1
  109. package/core/built/admin/assets/posts/{alert-dialog-mmQvJUHQ.mjs → alert-dialog-CYvHtOQ5.mjs} +4 -4
  110. package/core/built/admin/assets/posts/{app-utils-CD0bhOLs.mjs → app-utils-Cs-8qje1.mjs} +3 -3
  111. package/core/built/admin/assets/posts/{automations-BL0WaXHA.mjs → automations-DE2rwx-Z.mjs} +25 -25
  112. package/core/built/admin/assets/posts/{automations-BmGKngyG.mjs → automations-Dq0_cprS.mjs} +4 -4
  113. package/core/built/admin/assets/posts/{avatar-CeJ0Zq_A.mjs → avatar-Dt_bGEgl.mjs} +7 -7
  114. package/core/built/admin/assets/posts/{button-CQCNdxY6.mjs → button-DO7JrPsL.mjs} +2 -2
  115. package/core/built/admin/assets/posts/{chevron-up-DaikhWC2.mjs → chevron-up-B8WyJjCr.mjs} +3 -3
  116. package/core/built/admin/assets/posts/{comments-DUSJ25vf.mjs → comments-B3-RpqJU.mjs} +1933 -1905
  117. package/core/built/admin/assets/posts/{data-list-BiiYXQes.mjs → data-list-BiZFP6Co.mjs} +5 -5
  118. package/core/built/admin/assets/posts/{dialog-DRN6olky.mjs → dialog-Bvl2PD8s.mjs} +3 -3
  119. package/core/built/admin/assets/posts/{editor-DN_Zz0m2.mjs → editor-BCtdAD74.mjs} +3230 -3130
  120. package/core/built/admin/assets/posts/{ellipsis-BIs4PL5-.mjs → ellipsis-B5H7Hudx.mjs} +2 -2
  121. package/core/built/admin/assets/posts/{empty-indicator-Wiukrx4T.mjs → empty-indicator-BRoAf6Jv.mjs} +2 -2
  122. package/core/built/admin/assets/posts/{filters-CJl5ebXd.mjs → filters-CffYQY_8.mjs} +12 -12
  123. package/core/built/admin/assets/posts/{get-site-timezone-JepxGwVr.mjs → get-site-timezone-CSrPVUfX.mjs} +2 -2
  124. package/core/built/admin/assets/posts/{growth-cNlqbz-x.mjs → growth--LVGRPtS.mjs} +13 -13
  125. package/core/built/admin/assets/posts/{heading-C_V6Ckxx.mjs → heading-BRQEP7IA.mjs} +2 -2
  126. package/core/built/admin/assets/posts/{heart-BMBWsLs2.mjs → heart-CC2f1qWb.mjs} +2 -2
  127. package/core/built/admin/assets/posts/{hooks-D4pJ_p_P.mjs → hooks-J2WpDj1d.mjs} +2 -2
  128. package/core/built/admin/assets/posts/{index-DzWTmJMy.mjs → index-D-vhKzUJ.mjs} +3 -3
  129. package/core/built/admin/assets/posts/{index-CDwlVw9E.mjs → index-LnPyGojr.mjs} +2 -2
  130. package/core/built/admin/assets/posts/{index-BuIZkUhD.mjs → index-nxfIbREV.mjs} +11 -11
  131. package/core/built/admin/assets/posts/{input-DUvSHOFz.mjs → input-DTtfruk_.mjs} +3 -3
  132. package/core/built/admin/assets/posts/{input-surface-CO8-j6V2.mjs → input-surface-DXTGCuo2.mjs} +2 -2
  133. package/core/built/admin/assets/posts/{koenig-lexical-cRm7bY-6.mjs → koenig-lexical-CNcifuT7.mjs} +2 -2
  134. package/core/built/admin/assets/posts/{kpis-BXukzbg6.mjs → kpis-n8L4BlMi.mjs} +5843 -5854
  135. package/core/built/admin/assets/posts/{label-TTt0QyDb.mjs → label-yl8B8ADj.mjs} +6 -6
  136. package/core/built/admin/assets/posts/{links-BAXELE82.mjs → links-DDApMJfk.mjs} +4 -4
  137. package/core/built/admin/assets/posts/{list-page-DQIiFvFP.mjs → list-page-BJJ9amzJ.mjs} +4 -4
  138. package/core/built/admin/assets/posts/{loading-indicator-BsY7eGY6.mjs → loading-indicator-CQBDNvdo.mjs} +3 -3
  139. package/core/built/admin/assets/posts/{mail-Bi1gt3MU.mjs → mail-BHg0SvNu.mjs} +2 -2
  140. package/core/built/admin/assets/posts/{main-layout-DejRuxP8.mjs → main-layout-DXveCJ5W.mjs} +2 -2
  141. package/core/built/admin/assets/posts/{newsletter-PCUtHW6Z.mjs → newsletter-DUpVmnKN.mjs} +19 -19
  142. package/core/built/admin/assets/posts/{overview-f4eDWazr.mjs → overview-sv6i-2h9.mjs} +18 -18
  143. package/core/built/admin/assets/posts/{pencil-DDnfXQqn.mjs → pencil-DsGDLJp6.mjs} +2 -2
  144. package/core/built/admin/assets/posts/{plus-DW3bG6ui.mjs → plus-DjZ_REvJ.mjs} +2 -2
  145. package/core/built/admin/assets/posts/{popover-Du2NcggM.mjs → popover-2PA9zdiD.mjs} +4 -4
  146. package/core/built/admin/assets/posts/{post-analytics-BmnHyWJq.mjs → post-analytics-CKHoiJFY.mjs} +6 -6
  147. package/core/built/admin/assets/posts/{post-analytics-context-0fieM91Y.mjs → post-analytics-context-D17CB7nm.mjs} +6 -6
  148. package/core/built/admin/assets/posts/{post-analytics-header-Bxi56AWV.mjs → post-analytics-header-aQLnrdWi.mjs} +12 -12
  149. package/core/built/admin/assets/posts/{post-share-modal-DiuT4GFO.mjs → post-share-modal-C8-8CZw8.mjs} +6 -6
  150. package/core/built/admin/assets/posts/{posts-CYjfxmgX.mjs → posts-BA2vu_T2.mjs} +2 -2
  151. package/core/built/admin/assets/posts/posts.js +1 -1
  152. package/core/built/admin/assets/posts/{search-Dz7F6ifc.mjs → search-Bx6BvCRk.mjs} +2 -2
  153. package/core/built/admin/assets/posts/{select-FX6QYAFU.mjs → select-QOJ2OvL0.mjs} +7 -7
  154. package/core/built/admin/assets/posts/{separator-C7QPCSjM.mjs → separator-CHtBa4OX.mjs} +3 -3
  155. package/core/built/admin/assets/posts/{settings-DJqx19W1.mjs → settings-CxhTCxXg.mjs} +2 -2
  156. package/core/built/admin/assets/posts/{sheet-wg_8-w45.mjs → sheet-DO5nhiru.mjs} +4 -4
  157. package/core/built/admin/assets/posts/{site-Bxv-L5Dn.mjs → site-6g4pKVnR.mjs} +2 -2
  158. package/core/built/admin/assets/posts/{skeleton-DrFcKwP3.mjs → skeleton-DgWx-52p.mjs} +3 -3
  159. package/core/built/admin/assets/posts/{source-icon-DD_bmIqg.mjs → source-icon-_zLbYeab.mjs} +4 -4
  160. package/core/built/admin/assets/posts/{stats-DkOg80Vt.mjs → stats-BGJFxx5f.mjs} +4 -4
  161. package/core/built/admin/assets/posts/{switch-DZFGAF_Y.mjs → switch-Djipx7gc.mjs} +5 -5
  162. package/core/built/admin/assets/posts/{table-CZCVviNy.mjs → table-DpDCE80J.mjs} +2 -2
  163. package/core/built/admin/assets/posts/{tabs-1fkhM4p8.mjs → tabs-CLWGiyQ4.mjs} +4 -4
  164. package/core/built/admin/assets/posts/{tags-CkyGqwqi.mjs → tags-B4KIn7er.mjs} +2 -2
  165. package/core/built/admin/assets/posts/{tags-BAmugIR1.mjs → tags-Dn1L_Z_4.mjs} +16 -16
  166. package/core/built/admin/assets/posts/{toggle-group-B_ubMZvo.mjs → toggle-group-DMMjXGB3.mjs} +4 -4
  167. package/core/built/admin/assets/posts/{tooltip-D1X0uVas.mjs → tooltip-DlCjZwmt.mjs} +5 -5
  168. package/core/built/admin/assets/posts/{underline-CV8OJ7qc.mjs → underline-WN3ZSFyI.mjs} +2 -2
  169. package/core/built/admin/assets/posts/{value-DhEK7_uT.mjs → value-BWiEmo45.mjs} +2 -2
  170. package/core/built/admin/assets/posts/{virtual-list-window-DqbQUkIo.mjs → virtual-list-window-F3Tvi9H5.mjs} +3 -3
  171. package/core/built/admin/assets/posts/{web-5jcYGeBz.mjs → web-C8PxkHvH.mjs} +18 -18
  172. package/core/built/admin/assets/posts/{x-Cl72IwQm.mjs → x-BdlZ3sG3.mjs} +2 -2
  173. package/core/built/admin/assets/posts/{zap-BPDyHF1u.mjs → zap-BuAk2C7n.mjs} +33 -21
  174. package/core/built/admin/assets/{posts-D6K0FKB9.js → posts-bRma2Aji.js} +1 -1
  175. package/core/built/admin/assets/power-B4VCYMPn.js +1 -0
  176. package/core/built/admin/assets/{referrers-C9UK_aF_.js → referrers-BgXy4ZDF.js} +1 -1
  177. package/core/built/admin/assets/{repeat-BwgUDBQn.js → repeat-BElPLZnh.js} +1 -1
  178. package/core/built/admin/assets/{reply-DbknkQhJ.js → reply-qlUFZ_G8.js} +1 -1
  179. package/core/built/admin/assets/{rocket-1EqU2MzS.js → rocket-CXYckFbm.js} +1 -1
  180. package/core/built/admin/assets/{select-BGJXWb8i.js → select-MGAxyhXP.js} +1 -1
  181. package/core/built/admin/assets/{send-_CqvCQBY.js → send-DcU5LcPI.js} +1 -1
  182. package/core/built/admin/assets/{settings-Bnep890F.js → settings-DGSAz4oa.js} +4 -4
  183. package/core/built/admin/assets/{settings-Ct244PHl.js → settings-DI95fXs5.js} +1 -1
  184. package/core/built/admin/assets/{share-modal-B8pN_3tk.js → share-modal-CsNAIPeN.js} +1 -1
  185. package/core/built/admin/assets/{sort-button-EXsVVSdw.js → sort-button-wV9PBd2P.js} +1 -1
  186. package/core/built/admin/assets/{source-icon-XMs0toB0.js → source-icon-CYt4X1-M.js} +1 -1
  187. package/core/built/admin/assets/{sprout-uA_pVmDr.js → sprout-5QqpAoO8.js} +1 -1
  188. package/core/built/admin/assets/{square-atKnWQyw.js → square-YHeYyKG9.js} +1 -1
  189. package/core/built/admin/assets/{stats-CPNnZGD9.js → stats-PD64opSw.js} +1 -1
  190. package/core/built/admin/assets/{stats-view-BP8LU5rf.js → stats-view-C4fnD3uG.js} +1 -1
  191. package/core/built/admin/assets/{step-1-FHeGC4GW.js → step-1-BqeM_LxC.js} +1 -1
  192. package/core/built/admin/assets/{step-2-BFhgD2N8.js → step-2-C7AcokE9.js} +1 -1
  193. package/core/built/admin/assets/{step-3-BZMKjY5n.js → step-3-9Z0qkfpM.js} +2 -2
  194. package/core/built/admin/assets/{table-kGA62bBZ.js → table-C8Mxw8fs.js} +1 -1
  195. package/core/built/admin/assets/{tabs-Dl3BXr4Z.js → tabs-2KXMNRG-.js} +1 -1
  196. package/core/built/admin/assets/{tags-CLhASxwZ.js → tags-Cx-Jx8Yb.js} +1 -1
  197. package/core/built/admin/assets/{tags-D-W0kJMe.js → tags-cn7wgGit.js} +1 -1
  198. package/core/built/admin/assets/{textarea-DMub6CsU.js → textarea-dKwIcAK5.js} +1 -1
  199. package/core/built/admin/assets/{thumbs-up-DZu4SX5N.js → thumbs-up-gzGza05L.js} +1 -1
  200. package/core/built/admin/assets/{tiers-2bg8BCFj.js → tiers-D--LgD9v.js} +1 -1
  201. package/core/built/admin/assets/{toggle-group-ByS0KZ3G.js → toggle-group-C8KbiBQS.js} +1 -1
  202. package/core/built/admin/assets/{topic-filter-oRqwlePZ.js → topic-filter--VQn4A7D.js} +1 -1
  203. package/core/built/admin/assets/{trash-BHoSD8mS.js → trash-CnBwlhjN.js} +1 -1
  204. package/core/built/admin/assets/{underline-1YSgOpPm.js → underline-B2FjHOE0.js} +1 -1
  205. package/core/built/admin/assets/{undo-2-BwYMlB8G.js → undo-2-fUPuO2Zt.js} +1 -1
  206. package/core/built/admin/assets/{upload-BDz0_o9b.js → upload-BPOrFdtp.js} +1 -1
  207. package/core/built/admin/assets/{use-growth-stats-PRVcCUT7.js → use-growth-stats-By0ZDqFi.js} +1 -1
  208. package/core/built/admin/assets/{use-pintura-config-CROsgSEd.js → use-pintura-config-0ykvCF7U.js} +1 -1
  209. package/core/built/admin/assets/{use-simple-pagination-CBjKBNNI.js → use-simple-pagination-TruuCHV6.js} +1 -1
  210. package/core/built/admin/assets/{user-round-check-DKooQiV7.js → user-round-check-C1Vahz0b.js} +1 -1
  211. package/core/built/admin/assets/{user-round-x-B94nAYJb.js → user-round-x-CzKFo5GY.js} +1 -1
  212. package/core/built/admin/assets/{virtual-list-window-Cf_vCQFb.js → virtual-list-window-BWEknk_A.js} +1 -1
  213. package/core/built/admin/assets/{wallet-cards-BorRQari.js → wallet-cards-CRHrrjiy.js} +1 -1
  214. package/core/built/admin/assets/{web-BVHy-80k.js → web-C2H0oAut.js} +1 -1
  215. package/core/built/admin/index.html +7 -7
  216. package/core/frontend/services/llms/service.js +37 -10
  217. package/core/frontend/services/routing/config.js +5 -3
  218. package/core/frontend/services/routing/config.ts +59 -0
  219. package/core/frontend/services/sitemap/handler.js +2 -14
  220. package/core/frontend/services/sitemap/site-map-manager.js +9 -214
  221. package/core/server/api/endpoints/comment-replies.js +1 -2
  222. package/core/server/api/endpoints/members.js +4 -1
  223. package/core/server/api/endpoints/search-index-public.js +12 -1
  224. package/core/server/api/endpoints/search-index.js +13 -2
  225. package/core/server/lib/bootstrap-socket.js +31 -36
  226. package/core/server/lib/bootstrap-socket.ts +114 -0
  227. package/core/server/lib/common/to-plain.js +9 -21
  228. package/core/server/lib/common/to-plain.ts +25 -0
  229. package/core/server/models/role-utils.js +5 -7
  230. package/core/server/models/role-utils.ts +56 -0
  231. package/core/server/services/adapter-manager/adapter-manager.js +5 -1
  232. package/core/server/services/audience-feedback/audience-feedback-service.js +1 -1
  233. package/core/server/services/automations/automations-api.js +37 -2
  234. package/core/server/services/automations/automations-api.ts +43 -2
  235. package/core/server/services/comments/comments-controller.js +87 -55
  236. package/core/server/services/comments/comments-service-emails.js +1 -1
  237. package/core/server/services/comments/comments-service.js +249 -79
  238. package/core/server/services/mail/templates/notification.html +157 -0
  239. package/core/server/services/member-attribution/url-translator.js +1 -1
  240. package/core/server/services/members/members-api/services/token-service.js +21 -2
  241. package/core/server/services/notifications/notification-email.js +38 -0
  242. package/core/server/services/notifications/notification-email.ts +66 -0
  243. package/core/server/services/notifications/sanitize-email-html.js +37 -0
  244. package/core/server/services/notifications/sanitize-email-html.ts +35 -0
  245. package/core/server/services/route-settings/route-settings.js +2 -18
  246. package/core/server/services/route-settings/validate.js +2 -1
  247. package/core/server/services/update-check/index.js +10 -3
  248. package/core/server/services/update-check/update-check-service.js +18 -25
  249. package/core/server/services/url/index.js +1 -16
  250. package/core/shared/config/defaults.json +0 -1
  251. package/package.json +2 -1
  252. package/pnpm-lock.yaml +11 -1
  253. package/pnpm-workspace.yaml +2 -0
  254. package/core/built/admin/assets/editor-G3BxjP48.js +0 -8
  255. package/core/built/admin/assets/gh-chart-vpcpdiS9.js +0 -1
  256. package/core/built/admin/assets/index-BP5ial3p.js +0 -1
  257. package/core/built/admin/assets/index-Bd9VZ28k.css +0 -1
  258. package/core/built/admin/assets/kpis-B8pv3wne.js +0 -1
  259. package/core/built/admin/assets/label-BjHICZC1.js +0 -1
  260. package/core/built/admin/assets/members-DcuuSs_v.js +0 -10
  261. package/core/built/admin/assets/minus-Dv51QEND.js +0 -1
  262. package/core/built/admin/assets/offers-DKZ0qsmb.js +0 -1
  263. package/core/built/admin/assets/power-D5QO6MjY.js +0 -1
  264. package/core/server/services/url/lazy-find-resource.js +0 -49
  265. package/core/server/services/url/lazy-find-resource.ts +0 -62
  266. package/core/server/services/url/lazy-url-service.js +0 -262
  267. package/core/server/services/url/lazy-url-service.ts +0 -308
@@ -13,13 +13,7 @@ module.exports = function handler(siteApp) {
13
13
  next();
14
14
  };
15
15
 
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
-
16
+ siteApp.get('/sitemap.xml', function sitemapXML(req, res) {
23
17
  res.set({
24
18
  'Cache-Control': 'public, max-age=' + config.get('caching:sitemap:maxAge'),
25
19
  'Content-Type': 'text/xml'
@@ -28,17 +22,11 @@ module.exports = function handler(siteApp) {
28
22
  res.send(manager.getIndexXml());
29
23
  });
30
24
 
31
- siteApp.get('/sitemap-:resource.xml', verifyResourceType, async function sitemapResourceXML(req, res, next) {
25
+ siteApp.get('/sitemap-:resource.xml', verifyResourceType, function sitemapResourceXML(req, res) {
32
26
  const type = req.params.resource.replace(/-\d+$/, '');
33
27
  const pageParam = (req.params.resource.match(/-(\d+)$/) || [null, null])[1];
34
28
  const page = pageParam ? parseInt(pageParam, 10) : 1;
35
29
 
36
- try {
37
- await manager.ensurePopulatedFromDatabase();
38
- } catch (err) {
39
- return next(err);
40
- }
41
-
42
30
  const content = manager.getSiteMapXml(type, page);
43
31
  // Prevent x-1.xml as it is a duplicate of x.xml and empty sitemaps
44
32
  // (except for the first page so that at least one sitemap exists per type)
@@ -1,5 +1,4 @@
1
1
  const DomainEvents = require('@tryghost/domain-events');
2
- const config = require('../../../shared/config');
3
2
  const {URLResourceUpdatedEvent} = require('../../../shared/events');
4
3
  const IndexMapGenerator = require('./site-map-index-generator');
5
4
  const PagesMapGenerator = require('./page-map-generator');
@@ -22,20 +21,6 @@ class SiteMapManager {
22
21
  this.tags = options.tags || this.createTagsGenerator(options);
23
22
  this.index = options.index || this.createIndexGenerator(options);
24
23
 
25
- // The lazy URL service does not fire url.added / url.removed /
26
- // URLResourceUpdatedEvent. When that mode is active the sitemap
27
- // populates itself from the database on first request instead.
28
- this._lazyRouting = options.lazyRouting === undefined
29
- ? config.get('lazyRouting')
30
- : options.lazyRouting;
31
- this._populated = false;
32
- this._populating = null;
33
- // Each routers.reset bumps this generation. An in-flight populate
34
- // captures the generation it started in; if that generation is no
35
- // longer current when the populate settles, its result is discarded
36
- // so we don't mark a stale (potentially mid-reset) lookup as ready.
37
- this._populationGeneration = 0;
38
-
39
24
  events.on('router.created', (router) => {
40
25
  if (router.name === 'StaticRoutesRouter') {
41
26
  this.pages.addUrl(router.getRoute({absolute: true}), {id: router.identifier, staticRoute: true});
@@ -46,31 +31,23 @@ class SiteMapManager {
46
31
  }
47
32
  });
48
33
 
49
- if (!this._lazyRouting) {
50
- DomainEvents.subscribe(URLResourceUpdatedEvent, (event) => {
51
- this[event.data.resourceType].updateURL(event.data);
52
- });
34
+ DomainEvents.subscribe(URLResourceUpdatedEvent, (event) => {
35
+ this[event.data.resourceType].updateURL(event.data);
36
+ });
53
37
 
54
- events.on('url.added', (obj) => {
55
- this[obj.resource.config.type].addUrl(obj.url.absolute, obj.resource.data);
56
- });
38
+ events.on('url.added', (obj) => {
39
+ this[obj.resource.config.type].addUrl(obj.url.absolute, obj.resource.data);
40
+ });
57
41
 
58
- events.on('url.removed', (obj) => {
59
- this[obj.resource.config.type].removeUrl(obj.url.absolute, obj.resource.data);
60
- });
61
- }
42
+ events.on('url.removed', (obj) => {
43
+ this[obj.resource.config.type].removeUrl(obj.url.absolute, obj.resource.data);
44
+ });
62
45
 
63
46
  events.on('routers.reset', () => {
64
47
  this.pages && this.pages.reset();
65
48
  this.posts && this.posts.reset();
66
49
  this.users && this.users.reset();
67
50
  this.tags && this.tags.reset();
68
- // Force the next sitemap request to repopulate from the DB.
69
- // Bumping the generation invalidates any populate currently in
70
- // flight (its `.then` will see a stale generation and bail).
71
- this._populated = false;
72
- this._populating = null;
73
- this._populationGeneration += 1;
74
51
  });
75
52
  }
76
53
 
@@ -109,188 +86,6 @@ class SiteMapManager {
109
86
  getSiteMapXml(type, page) {
110
87
  return this[type].getXml(page);
111
88
  }
112
-
113
- /**
114
- * Populate the sitemap from the database. Used when the lazy URL service
115
- * is active and the URL-added/-removed events are not firing. Idempotent;
116
- * a second call is a no-op while the first is in flight or has finished.
117
- */
118
- async ensurePopulatedFromDatabase() {
119
- if (!this._lazyRouting || this._populated) {
120
- return;
121
- }
122
- if (this._populating) {
123
- return this._populating;
124
- }
125
- const generation = this._populationGeneration;
126
- const populating = this._populateFromDatabase().then(
127
- () => {
128
- // If a routers.reset happened while we were running, the
129
- // generators have been wiped. Don't flip _populated; let the
130
- // next request kick off a fresh populate.
131
- if (this._populationGeneration === generation) {
132
- this._populated = true;
133
- }
134
- // Only clear our own handle. routers.reset already nulled
135
- // _populating and a successor populate may have replaced it
136
- // — clobbering would orphan the successor.
137
- if (this._populating === populating) {
138
- this._populating = null;
139
- }
140
- },
141
- (err) => {
142
- if (this._populating === populating) {
143
- this._populating = null;
144
- }
145
- throw err;
146
- }
147
- );
148
- this._populating = populating;
149
- return this._populating;
150
- }
151
-
152
- async _populateFromDatabase() {
153
- const models = require('../../../server/models');
154
- const urlService = require('../../../server/services/url');
155
- const facade = urlService.facade;
156
-
157
- await Promise.all([
158
- this._loadType('posts', this.posts, facade, models),
159
- this._loadType('pages', this.pages, facade, models),
160
- this._loadType('tags', this.tags, facade, models),
161
- this._loadType('authors', this.users, facade, models)
162
- ]);
163
- }
164
-
165
- async _loadType(type, generator, facade, models) {
166
- const fetchOptions = TYPE_FETCH_OPTIONS[type];
167
- if (!fetchOptions) {
168
- return;
169
- }
170
- // Use the same raw-knex path as the eager URL service's resource
171
- // fetcher (services/url/resources.js → raw_knex.fetchAll). The
172
- // previous implementation went through Bookshelf's findPage and
173
- // toPlain per row, which is minutes-not-seconds for 50k posts —
174
- // slow enough that edge proxies 503 on the first sitemap request.
175
- const objects = await models.Base.Model.raw_knex.fetchAll(fetchOptions);
176
- for (const datum of objects) {
177
- const url = facade.getUrlForResource({...datum, type}, {absolute: true});
178
- if (url && !url.match(/\/404\//)) {
179
- generator.addUrl(url, datum);
180
- }
181
- }
182
- }
183
89
  }
184
90
 
185
- // Mirrors the eager URL service's resource configs (services/url/config.js)
186
- // so the lazy sitemap renders the same URL set as the eager service would.
187
- // When the eager service is removed this becomes the only copy — kept
188
- // inline (rather than imported from services/url) so the eager removal is
189
- // a clean delete.
190
- //
191
- // The `exclude` lists trim heavy columns (mobiledoc, lexical, html,
192
- // plaintext, codeinjection, og/twitter card fields, …) before they ever
193
- // reach memory. Without them, fetchAll loads the full body of every post
194
- // — multiple GB on a 50k-post site.
195
- //
196
- // `withRelated: ['tags', 'authors']` for posts is what surfaces
197
- // `primary_tag` / `primary_author` on the result: Post.toJSON's computed
198
- // `primary_tag` field (models/post.js) and the authors-relation
199
- // serialize mixin both run as part of raw_knex.fetchAll's per-row
200
- // toJSON pass, gated only on the relation being loaded.
201
- const TYPE_FETCH_OPTIONS = {
202
- posts: {
203
- modelName: 'Post',
204
- filter: 'status:published+type:post',
205
- exclude: [
206
- 'title',
207
- 'mobiledoc',
208
- 'lexical',
209
- 'html',
210
- 'plaintext',
211
- 'status',
212
- 'codeinjection_head',
213
- 'codeinjection_foot',
214
- 'meta_title',
215
- 'meta_description',
216
- 'custom_excerpt',
217
- 'og_image',
218
- 'og_title',
219
- 'og_description',
220
- 'twitter_image',
221
- 'twitter_title',
222
- 'twitter_description',
223
- 'custom_template',
224
- 'locale',
225
- 'newsletter_id',
226
- 'show_title_and_feature_image',
227
- 'email_recipient_filter',
228
- 'comment_id',
229
- 'tiers'
230
- ],
231
- withRelated: ['tags', 'authors'],
232
- withRelatedFields: {
233
- tags: ['tags.id', 'tags.slug'],
234
- authors: ['users.id', 'users.slug']
235
- }
236
- },
237
- pages: {
238
- modelName: 'Post',
239
- filter: 'status:published+type:page',
240
- exclude: [
241
- 'title',
242
- 'mobiledoc',
243
- 'lexical',
244
- 'html',
245
- 'plaintext',
246
- 'codeinjection_head',
247
- 'codeinjection_foot',
248
- 'meta_title',
249
- 'meta_description',
250
- 'custom_excerpt',
251
- 'og_image',
252
- 'og_title',
253
- 'og_description',
254
- 'twitter_image',
255
- 'twitter_title',
256
- 'twitter_description',
257
- 'custom_template',
258
- 'locale',
259
- 'tags',
260
- 'authors',
261
- 'primary_tag',
262
- 'primary_author',
263
- 'newsletter_id',
264
- 'show_title_and_feature_image',
265
- 'email_recipient_filter',
266
- 'comment_id',
267
- 'tiers'
268
- ]
269
- },
270
- tags: {
271
- modelName: 'Tag',
272
- filter: 'visibility:public',
273
- exclude: ['description', 'meta_title', 'meta_description', 'parent_id'],
274
- shouldHavePosts: {joinTo: 'tag_id', joinTable: 'posts_tags'}
275
- },
276
- authors: {
277
- modelName: 'User',
278
- filter: 'visibility:public',
279
- exclude: [
280
- 'bio',
281
- 'website',
282
- 'location',
283
- 'facebook',
284
- 'twitter',
285
- 'locale',
286
- 'accessibility',
287
- 'meta_title',
288
- 'meta_description',
289
- 'tour',
290
- 'last_seen'
291
- ],
292
- shouldHavePosts: {joinTo: 'author_id', joinTable: 'posts_authors'}
293
- }
294
- };
295
-
296
91
  module.exports = SiteMapManager;
@@ -53,8 +53,7 @@ const controller = {
53
53
  },
54
54
  permissions: true,
55
55
  query(frame) {
56
- frame.options.isAdmin = true;
57
- return commentsService.controller.read(frame);
56
+ return commentsService.controller.adminRead(frame);
58
57
  }
59
58
  }
60
59
  };
@@ -9,6 +9,7 @@ const membersService = require('../../services/members');
9
9
  const settingsCache = require('../../../shared/settings-cache');
10
10
  const tpl = require('@tryghost/tpl');
11
11
  const _ = require('lodash');
12
+ const {slugify} = require('@tryghost/string');
12
13
 
13
14
  const messages = {
14
15
  memberNotFound: 'Member not found.',
@@ -378,7 +379,9 @@ const controller = {
378
379
  type: 'csv',
379
380
  value() {
380
381
  const datetime = (new Date()).toJSON().substring(0, 10);
381
- return `members.${datetime}.csv`;
382
+ const title = settingsCache.get('title');
383
+ const titlePrefix = title ? `${slugify(title)}.` : '';
384
+ return `${titlePrefix}ghost.members.${datetime}.csv`;
382
385
  }
383
386
  },
384
387
  contentType: 'text/csv',
@@ -1,7 +1,18 @@
1
1
  const models = require('../../models');
2
+ const config = require('../../../shared/config');
2
3
  const getPostServiceInstance = require('../../services/posts/posts-service-instance');
3
4
  const postsService = getPostServiceInstance();
4
5
 
6
+ const urlRelationsWhenLazyRouting = () => {
7
+ if (config.get('lazyRouting')) {
8
+ return {
9
+ withRelated: ['tags', 'authors']
10
+ };
11
+ }
12
+
13
+ return {};
14
+ };
15
+
5
16
  /** @type {import('@tryghost/api-framework').Controller} */
6
17
  const controller = {
7
18
  docName: 'search_index',
@@ -16,7 +27,7 @@ const controller = {
16
27
  limit: '10000',
17
28
  order: 'updated_at DESC',
18
29
  columns: ['id', 'slug', 'title', 'excerpt', 'url', 'updated_at', 'visibility'],
19
- withRelated: ['tags', 'authors']
30
+ ...urlRelationsWhenLazyRouting()
20
31
  };
21
32
 
22
33
  return postsService.browsePosts(options);
@@ -1,7 +1,18 @@
1
1
  const models = require('../../models');
2
+ const config = require('../../../shared/config');
2
3
  const getPostServiceInstance = require('../../services/posts/posts-service-instance');
3
4
  const postsService = getPostServiceInstance();
4
5
 
6
+ const urlRelationsWhenLazyRouting = () => {
7
+ if (config.get('lazyRouting')) {
8
+ return {
9
+ withRelated: ['tags', 'authors']
10
+ };
11
+ }
12
+
13
+ return {};
14
+ };
15
+
5
16
  /** @type {import('@tryghost/api-framework').Controller} */
6
17
  const controller = {
7
18
  docName: 'search_index',
@@ -19,7 +30,7 @@ const controller = {
19
30
  limit: '10000',
20
31
  order: 'updated_at DESC',
21
32
  columns: ['id', 'uuid', 'url', 'title', 'slug', 'status', 'published_at', 'visibility'],
22
- withRelated: ['tags', 'authors']
33
+ ...urlRelationsWhenLazyRouting()
23
34
  };
24
35
 
25
36
  return postsService.browsePosts(options);
@@ -39,7 +50,7 @@ const controller = {
39
50
  limit: '10000',
40
51
  order: 'updated_at DESC',
41
52
  columns: ['id', 'uuid', 'url', 'title', 'slug', 'status', 'published_at', 'visibility'],
42
- withRelated: ['tags', 'authors']
53
+ ...urlRelationsWhenLazyRouting()
43
54
  };
44
55
 
45
56
  return postsService.browsePosts(options);
@@ -1,87 +1,82 @@
1
- const logging = require('@tryghost/logging');
2
-
3
- module.exports.connectAndSend = (socketAddress, message) => {
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
+ exports.connectAndSend = void 0;
7
+ const node_net_1 = __importDefault(require("node:net"));
8
+ const logging_1 = __importDefault(require("@tryghost/logging"));
9
+ const getErrorCode = (err) => (err && typeof err === 'object' && 'code' in err && typeof err.code === 'string'
10
+ ? err.code
11
+ : undefined);
12
+ const isValidPort = (port) => (typeof port === 'number' &&
13
+ Number.isInteger(port) &&
14
+ port >= 1 &&
15
+ port <= 65535);
16
+ const hasSocketAddress = (socketAddress) => (typeof socketAddress?.host === 'string' && Boolean(socketAddress.host) &&
17
+ isValidPort(socketAddress.port));
18
+ const connectAndSend = (socketAddress, message) => {
4
19
  // Very basic guard against bad calls
5
- if (!socketAddress || !socketAddress.host || !socketAddress.port || !logging || !logging.info || !logging.warn || !message) {
20
+ if (!hasSocketAddress(socketAddress) || !logging_1.default || !logging_1.default.info || !logging_1.default.warn || message === undefined) {
6
21
  return Promise.resolve();
7
22
  }
8
-
9
- const net = require('net');
10
- const client = new net.Socket();
11
-
23
+ const client = new node_net_1.default.Socket();
12
24
  return new Promise((resolve) => {
13
- const connect = (options = {}) => {
25
+ const connect = (options) => {
14
26
  let wasResolved = false;
15
-
16
27
  const waitTimeout = setTimeout(() => {
17
- logging.info('Bootstrap socket timed out.');
18
-
28
+ logging_1.default.info('Bootstrap socket timed out.');
19
29
  if (!client.destroyed) {
20
30
  client.destroy();
21
31
  }
22
-
23
32
  if (wasResolved) {
24
33
  return;
25
34
  }
26
-
27
35
  wasResolved = true;
28
36
  resolve();
29
37
  }, 1000 * 5);
30
-
31
38
  client.connect(socketAddress.port, socketAddress.host, () => {
32
39
  if (waitTimeout) {
33
40
  clearTimeout(waitTimeout);
34
41
  }
35
-
36
42
  client.write(JSON.stringify(message));
37
-
38
43
  if (wasResolved) {
39
44
  return;
40
45
  }
41
-
42
46
  wasResolved = true;
43
47
  resolve();
44
48
  });
45
-
46
49
  client.on('close', () => {
47
- logging.info('Bootstrap client was closed.');
48
-
50
+ logging_1.default.info('Bootstrap client was closed.');
49
51
  if (waitTimeout) {
50
52
  clearTimeout(waitTimeout);
51
53
  }
52
54
  });
53
-
54
55
  client.on('error', (err) => {
55
- logging.warn(`Can't connect to the bootstrap socket (${socketAddress.host} ${socketAddress.port}) ${err.code}.`);
56
-
56
+ logging_1.default.warn(`Can't connect to the bootstrap socket (${socketAddress.host} ${socketAddress.port}) ${getErrorCode(err)}.`);
57
57
  client.removeAllListeners();
58
-
59
58
  if (waitTimeout) {
60
59
  clearTimeout(waitTimeout);
61
60
  }
62
-
63
61
  if (options.tries < 3) {
64
- logging.warn(`Tries: ${options.tries}`);
65
-
62
+ logging_1.default.warn(`Tries: ${options.tries}`);
66
63
  // retry
67
- logging.warn('Retrying...');
68
-
69
- options.tries = options.tries + 1;
64
+ logging_1.default.warn('Retrying...');
70
65
  const retryTimeout = setTimeout(() => {
71
66
  clearTimeout(retryTimeout);
72
- connect(options);
67
+ connect({ tries: options.tries + 1 });
73
68
  }, 150);
74
- } else {
69
+ }
70
+ else {
75
71
  if (wasResolved) {
76
72
  return;
77
73
  }
78
-
79
74
  wasResolved = true;
80
75
  resolve();
81
76
  }
82
77
  });
83
78
  };
84
-
85
- connect({tries: 0});
79
+ connect({ tries: 0 });
86
80
  });
87
81
  };
82
+ exports.connectAndSend = connectAndSend;
@@ -0,0 +1,114 @@
1
+ import net from 'node:net';
2
+ import logging from '@tryghost/logging';
3
+ import type {JsonValue} from 'type-fest';
4
+
5
+ type SocketAddress = Readonly<{
6
+ host: string;
7
+ port: number;
8
+ }>;
9
+
10
+ type ConnectOptions = Readonly<{
11
+ tries: number;
12
+ }>;
13
+
14
+ const getErrorCode = (err: unknown): undefined | string => (
15
+ err && typeof err === 'object' && 'code' in err && typeof err.code === 'string'
16
+ ? err.code
17
+ : undefined
18
+ );
19
+
20
+ const isValidPort = (port: unknown): port is number => (
21
+ typeof port === 'number' &&
22
+ Number.isInteger(port) &&
23
+ port >= 1 &&
24
+ port <= 65535
25
+ );
26
+
27
+ const hasSocketAddress = (socketAddress?: Partial<SocketAddress>): socketAddress is SocketAddress => (
28
+ typeof socketAddress?.host === 'string' && Boolean(socketAddress.host) &&
29
+ isValidPort(socketAddress.port)
30
+ );
31
+
32
+ export const connectAndSend = (socketAddress?: Partial<SocketAddress>, message?: JsonValue): Promise<void> => {
33
+ // Very basic guard against bad calls
34
+ if (!hasSocketAddress(socketAddress) || !logging || !logging.info || !logging.warn || message === undefined) {
35
+ return Promise.resolve();
36
+ }
37
+
38
+ const client = new net.Socket();
39
+
40
+ return new Promise((resolve: () => void) => {
41
+ const connect = (options: ConnectOptions) => {
42
+ let wasResolved = false;
43
+
44
+ const waitTimeout = setTimeout(() => {
45
+ logging.info('Bootstrap socket timed out.');
46
+
47
+ if (!client.destroyed) {
48
+ client.destroy();
49
+ }
50
+
51
+ if (wasResolved) {
52
+ return;
53
+ }
54
+
55
+ wasResolved = true;
56
+ resolve();
57
+ }, 1000 * 5);
58
+
59
+ client.connect(socketAddress.port, socketAddress.host, () => {
60
+ if (waitTimeout) {
61
+ clearTimeout(waitTimeout);
62
+ }
63
+
64
+ client.write(JSON.stringify(message));
65
+
66
+ if (wasResolved) {
67
+ return;
68
+ }
69
+
70
+ wasResolved = true;
71
+ resolve();
72
+ });
73
+
74
+ client.on('close', () => {
75
+ logging.info('Bootstrap client was closed.');
76
+
77
+ if (waitTimeout) {
78
+ clearTimeout(waitTimeout);
79
+ }
80
+ });
81
+
82
+ client.on('error', (err: Error) => {
83
+ logging.warn(`Can't connect to the bootstrap socket (${socketAddress.host} ${socketAddress.port}) ${getErrorCode(err)}.`);
84
+
85
+ client.removeAllListeners();
86
+
87
+ if (waitTimeout) {
88
+ clearTimeout(waitTimeout);
89
+ }
90
+
91
+ if (options.tries < 3) {
92
+ logging.warn(`Tries: ${options.tries}`);
93
+
94
+ // retry
95
+ logging.warn('Retrying...');
96
+
97
+ const retryTimeout = setTimeout(() => {
98
+ clearTimeout(retryTimeout);
99
+ connect({tries: options.tries + 1});
100
+ }, 150);
101
+ } else {
102
+ if (wasResolved) {
103
+ return;
104
+ }
105
+
106
+ wasResolved = true;
107
+ resolve();
108
+ }
109
+ });
110
+ };
111
+
112
+ connect({tries: 0});
113
+ });
114
+ };
@@ -1,21 +1,9 @@
1
- /**
2
- * Normalise a Bookshelf model or plain object to its JSON representation.
3
- *
4
- * Bookshelf models expose their data via `.toJSON()` and store it on a private
5
- * `attributes` map; spreading them with `{...model}` skips the prototype-defined
6
- * getters (including `id`) and so silently loses the data. This helper lets
7
- * callers accept either shape uniformly:
8
- *
9
- * const data = toPlain(post);
10
- * urlService.facade.getUrlForResource({...data, type: 'posts'}, ...)
11
- *
12
- * @template T
13
- * @param {T | {toJSON(): T}} modelOrObj
14
- * @returns {T}
15
- */
16
- module.exports = function toPlain(modelOrObj) {
17
- if (modelOrObj && typeof modelOrObj.toJSON === 'function') {
18
- return modelOrObj.toJSON();
19
- }
20
- return modelOrObj;
21
- };
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toPlain = void 0;
4
+ const isJsonSerializable = (modelOrObj) => !!(modelOrObj
5
+ && typeof modelOrObj === 'object'
6
+ && 'toJSON' in modelOrObj
7
+ && typeof modelOrObj.toJSON === 'function');
8
+ const toPlain = (modelOrObj) => (isJsonSerializable(modelOrObj) ? modelOrObj.toJSON() : modelOrObj);
9
+ exports.toPlain = toPlain;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Normalise a Bookshelf model or plain object to its JSON representation.
3
+ *
4
+ * Bookshelf models expose their data via `.toJSON()` and store it on a private
5
+ * `attributes` map; spreading them with `{...model}` skips the prototype-defined
6
+ * getters (including `id`) and so silently loses the data. This helper lets
7
+ * callers accept either shape uniformly:
8
+ *
9
+ * const data = toPlain(post);
10
+ * urlService.facade.getUrlForResource({...data, type: 'posts'}, ...)
11
+ */
12
+ type JsonSerializable<T> = {
13
+ toJSON(): T;
14
+ };
15
+
16
+ const isJsonSerializable = <T>(modelOrObj: T | JsonSerializable<T>): modelOrObj is JsonSerializable<T> => !!(
17
+ modelOrObj
18
+ && typeof modelOrObj === 'object'
19
+ && 'toJSON' in modelOrObj
20
+ && typeof modelOrObj.toJSON === 'function'
21
+ );
22
+
23
+ export const toPlain = <T>(modelOrObj: T | JsonSerializable<T>): T => (
24
+ isJsonSerializable(modelOrObj) ? modelOrObj.toJSON() : modelOrObj
25
+ );