ghost 5.82.8 → 5.82.9

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 (277) hide show
  1. package/components/tryghost-adapter-cache-memory-ttl-5.82.9.tgz +0 -0
  2. package/components/tryghost-adapter-cache-redis-5.82.9.tgz +0 -0
  3. package/components/tryghost-adapter-manager-5.82.9.tgz +0 -0
  4. package/components/tryghost-announcement-bar-settings-5.82.9.tgz +0 -0
  5. package/components/tryghost-api-framework-5.82.9.tgz +0 -0
  6. package/components/tryghost-api-version-compatibility-service-5.82.9.tgz +0 -0
  7. package/components/tryghost-audience-feedback-5.82.9.tgz +0 -0
  8. package/components/tryghost-bookshelf-repository-5.82.9.tgz +0 -0
  9. package/components/tryghost-bootstrap-socket-5.82.9.tgz +0 -0
  10. package/components/{tryghost-collections-5.82.8.tgz → tryghost-collections-5.82.9.tgz} +0 -0
  11. package/components/tryghost-constants-5.82.9.tgz +0 -0
  12. package/components/{tryghost-custom-theme-settings-service-5.82.8.tgz → tryghost-custom-theme-settings-service-5.82.9.tgz} +0 -0
  13. package/components/tryghost-data-generator-5.82.9.tgz +0 -0
  14. package/components/tryghost-domain-events-5.82.9.tgz +0 -0
  15. package/components/tryghost-donations-5.82.9.tgz +0 -0
  16. package/components/tryghost-dynamic-routing-events-5.82.9.tgz +0 -0
  17. package/components/{tryghost-email-addresses-5.82.8.tgz → tryghost-email-addresses-5.82.9.tgz} +0 -0
  18. package/components/tryghost-email-analytics-provider-mailgun-5.82.9.tgz +0 -0
  19. package/components/tryghost-email-analytics-service-5.82.9.tgz +0 -0
  20. package/components/tryghost-email-content-generator-5.82.9.tgz +0 -0
  21. package/components/tryghost-email-events-5.82.9.tgz +0 -0
  22. package/components/{tryghost-email-service-5.82.8.tgz → tryghost-email-service-5.82.9.tgz} +0 -0
  23. package/components/tryghost-email-suppression-list-5.82.9.tgz +0 -0
  24. package/components/tryghost-express-dynamic-redirects-5.82.9.tgz +0 -0
  25. package/components/tryghost-external-media-inliner-5.82.9.tgz +0 -0
  26. package/components/tryghost-extract-api-key-5.82.9.tgz +0 -0
  27. package/components/tryghost-ghost-5.82.9.tgz +0 -0
  28. package/components/tryghost-html-to-plaintext-5.82.9.tgz +0 -0
  29. package/components/tryghost-i18n-5.82.9.tgz +0 -0
  30. package/components/tryghost-importer-handler-content-files-5.82.9.tgz +0 -0
  31. package/components/tryghost-importer-revue-5.82.9.tgz +0 -0
  32. package/components/tryghost-in-memory-repository-5.82.9.tgz +0 -0
  33. package/components/tryghost-job-manager-5.82.9.tgz +0 -0
  34. package/components/tryghost-link-redirects-5.82.9.tgz +0 -0
  35. package/components/tryghost-link-replacer-5.82.9.tgz +0 -0
  36. package/components/{tryghost-link-tracking-5.82.8.tgz → tryghost-link-tracking-5.82.9.tgz} +0 -0
  37. package/components/tryghost-magic-link-5.82.9.tgz +0 -0
  38. package/components/tryghost-mail-events-5.82.9.tgz +0 -0
  39. package/components/tryghost-mailgun-client-5.82.9.tgz +0 -0
  40. package/components/tryghost-member-attribution-5.82.9.tgz +0 -0
  41. package/components/tryghost-member-events-5.82.9.tgz +0 -0
  42. package/components/{tryghost-members-api-5.82.8.tgz → tryghost-members-api-5.82.9.tgz} +0 -0
  43. package/components/tryghost-members-csv-5.82.9.tgz +0 -0
  44. package/components/tryghost-members-events-service-5.82.9.tgz +0 -0
  45. package/components/tryghost-members-importer-5.82.9.tgz +0 -0
  46. package/components/tryghost-members-offers-5.82.9.tgz +0 -0
  47. package/components/tryghost-members-payments-5.82.9.tgz +0 -0
  48. package/components/tryghost-members-ssr-5.82.9.tgz +0 -0
  49. package/components/{tryghost-members-stripe-service-5.82.8.tgz → tryghost-members-stripe-service-5.82.9.tgz} +0 -0
  50. package/components/tryghost-mentions-email-report-5.82.9.tgz +0 -0
  51. package/components/tryghost-milestones-5.82.9.tgz +0 -0
  52. package/components/{tryghost-minifier-5.82.8.tgz → tryghost-minifier-5.82.9.tgz} +0 -0
  53. package/components/tryghost-model-to-domain-event-interceptor-5.82.9.tgz +0 -0
  54. package/components/tryghost-mw-api-version-mismatch-5.82.9.tgz +0 -0
  55. package/components/tryghost-mw-cache-control-5.82.9.tgz +0 -0
  56. package/components/tryghost-mw-error-handler-5.82.9.tgz +0 -0
  57. package/components/tryghost-mw-session-from-token-5.82.9.tgz +0 -0
  58. package/components/tryghost-mw-update-user-last-seen-5.82.9.tgz +0 -0
  59. package/components/{tryghost-mw-version-match-5.82.8.tgz → tryghost-mw-version-match-5.82.9.tgz} +0 -0
  60. package/components/tryghost-mw-vhost-5.82.9.tgz +0 -0
  61. package/components/tryghost-nql-filter-expansions-5.82.9.tgz +0 -0
  62. package/components/tryghost-oembed-service-5.82.9.tgz +0 -0
  63. package/components/tryghost-package-json-5.82.9.tgz +0 -0
  64. package/components/tryghost-post-events-5.82.9.tgz +0 -0
  65. package/components/tryghost-post-revisions-5.82.9.tgz +0 -0
  66. package/components/tryghost-posts-service-5.82.9.tgz +0 -0
  67. package/components/tryghost-recommendations-5.82.9.tgz +0 -0
  68. package/components/tryghost-referrers-5.82.9.tgz +0 -0
  69. package/components/tryghost-security-5.82.9.tgz +0 -0
  70. package/components/tryghost-session-service-5.82.9.tgz +0 -0
  71. package/components/tryghost-settings-path-manager-5.82.9.tgz +0 -0
  72. package/components/tryghost-slack-notifications-5.82.9.tgz +0 -0
  73. package/components/{tryghost-staff-service-5.82.8.tgz → tryghost-staff-service-5.82.9.tgz} +0 -0
  74. package/components/tryghost-stats-service-5.82.9.tgz +0 -0
  75. package/components/tryghost-tiers-5.82.9.tgz +0 -0
  76. package/components/{tryghost-update-check-service-5.82.8.tgz → tryghost-update-check-service-5.82.9.tgz} +0 -0
  77. package/components/tryghost-verification-trigger-5.82.9.tgz +0 -0
  78. package/components/tryghost-version-notifications-data-service-5.82.9.tgz +0 -0
  79. package/components/tryghost-webmentions-5.82.9.tgz +0 -0
  80. package/core/app.js +1 -1
  81. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +1 -1
  82. package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +1 -1
  83. package/core/built/admin/assets/admin-x-demo/{index-e30bf632.mjs → index-f544d6cb.mjs} +3 -3
  84. package/core/built/admin/assets/admin-x-demo/{modals-44d6f757.mjs → modals-6544d395.mjs} +2 -2
  85. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-c72ff915.mjs → CodeEditorView-a1b9ba69.mjs} +2 -2
  86. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
  87. package/core/built/admin/assets/admin-x-settings/{index-c91e5b06.mjs → index-8d83c7e9.mjs} +2 -2
  88. package/core/built/admin/assets/admin-x-settings/{index-ab6aea43.mjs → index-d54677fb.mjs} +4 -4
  89. package/core/built/admin/assets/admin-x-settings/{modals-839cba44.mjs → modals-73b6c803.mjs} +3125 -3105
  90. package/core/built/admin/assets/{chunk.524.784dc858253af4b339a9.js → chunk.524.cad7f24c33927f31923c.js} +5 -5
  91. package/core/built/admin/assets/{chunk.582.22b04d2b8d1fb7e2256c.js → chunk.582.a3046e5a9e7ea94bda16.js} +4 -4
  92. package/core/built/admin/assets/{chunk.799.5012e659e3d64d043636.js → chunk.799.5bcf6feef26f9fe94f0a.js} +523 -517
  93. package/core/built/admin/assets/{ghost-e16d0c67f0a0262f4cbe0d2745f90f5a.js → ghost-377ce682ddf6e53f0ccb91aeae235f29.js} +70 -58
  94. package/core/built/admin/assets/koenig-lexical/index.css +1 -1
  95. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +2015 -1951
  96. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +46 -46
  97. package/core/built/admin/assets/{vendor-5ef343f0a55366497ef903095548a0d5.js → vendor-96853bcc300bd0b0cda2913c8edb0d14.js} +13 -11
  98. package/core/built/admin/index.html +5 -5
  99. package/core/frontend/meta/og-image.js +1 -1
  100. package/core/frontend/meta/twitter-image.js +1 -1
  101. package/core/frontend/services/routing/ParentRouter.js +3 -3
  102. package/core/frontend/web/middleware/error-handler.js +1 -1
  103. package/core/frontend/web/site.js +4 -2
  104. package/core/server/GhostServer.js +1 -1
  105. package/core/server/api/endpoints/actions.js +4 -1
  106. package/core/server/api/endpoints/announcements.js +4 -1
  107. package/core/server/api/endpoints/authentication.js +4 -1
  108. package/core/server/api/endpoints/authors-public.js +4 -1
  109. package/core/server/api/endpoints/collections-public.js +4 -1
  110. package/core/server/api/endpoints/collections.js +4 -1
  111. package/core/server/api/endpoints/comments-members.js +6 -3
  112. package/core/server/api/endpoints/comments.js +4 -1
  113. package/core/server/api/endpoints/config.js +4 -1
  114. package/core/server/api/endpoints/custom-theme-settings.js +4 -1
  115. package/core/server/api/endpoints/db.js +4 -1
  116. package/core/server/api/endpoints/email-post.js +4 -1
  117. package/core/server/api/endpoints/email-previews.js +4 -1
  118. package/core/server/api/endpoints/emails.js +4 -1
  119. package/core/server/api/endpoints/explore.js +4 -1
  120. package/core/server/api/endpoints/feedback-members.js +4 -1
  121. package/core/server/api/endpoints/files.js +4 -1
  122. package/core/server/api/endpoints/identities.js +4 -1
  123. package/core/server/api/endpoints/images.js +4 -1
  124. package/core/server/api/endpoints/incoming-recommendations.js +4 -1
  125. package/core/server/api/endpoints/integrations.js +4 -1
  126. package/core/server/api/endpoints/invites.js +4 -1
  127. package/core/server/api/endpoints/labels.js +4 -1
  128. package/core/server/api/endpoints/links.js +4 -1
  129. package/core/server/api/endpoints/mail-events.js +4 -1
  130. package/core/server/api/endpoints/mail.js +4 -19
  131. package/core/server/api/endpoints/media.js +4 -1
  132. package/core/server/api/endpoints/member-signin-urls.js +5 -1
  133. package/core/server/api/endpoints/members-stripe-connect.js +4 -1
  134. package/core/server/api/endpoints/members.js +4 -1
  135. package/core/server/api/endpoints/mentions.js +4 -1
  136. package/core/server/api/endpoints/newsletters-public.js +4 -1
  137. package/core/server/api/endpoints/newsletters.js +4 -1
  138. package/core/server/api/endpoints/notifications.js +4 -1
  139. package/core/server/api/endpoints/oembed.js +4 -1
  140. package/core/server/api/endpoints/offers-public.js +4 -1
  141. package/core/server/api/endpoints/offers.js +4 -1
  142. package/core/server/api/endpoints/pages-public.js +4 -1
  143. package/core/server/api/endpoints/pages.js +4 -1
  144. package/core/server/api/endpoints/posts-public.js +11 -1
  145. package/core/server/api/endpoints/posts.js +4 -1
  146. package/core/server/api/endpoints/previews.js +4 -1
  147. package/core/server/api/endpoints/recommendations-public.js +4 -1
  148. package/core/server/api/endpoints/recommendations.js +4 -1
  149. package/core/server/api/endpoints/redirects.js +4 -1
  150. package/core/server/api/endpoints/roles.js +4 -1
  151. package/core/server/api/endpoints/schedules.js +4 -2
  152. package/core/server/api/endpoints/session.js +5 -4
  153. package/core/server/api/endpoints/settings-public.js +4 -1
  154. package/core/server/api/endpoints/settings.js +4 -1
  155. package/core/server/api/endpoints/site.js +3 -2
  156. package/core/server/api/endpoints/slack.js +4 -1
  157. package/core/server/api/endpoints/slugs.js +4 -1
  158. package/core/server/api/endpoints/snippets.js +4 -1
  159. package/core/server/api/endpoints/stats.js +4 -1
  160. package/core/server/api/endpoints/tags-public.js +4 -1
  161. package/core/server/api/endpoints/tags.js +4 -1
  162. package/core/server/api/endpoints/themes.js +4 -1
  163. package/core/server/api/endpoints/tiers-public.js +4 -1
  164. package/core/server/api/endpoints/tiers.js +4 -1
  165. package/core/server/api/endpoints/users.js +4 -1
  166. package/core/server/api/endpoints/utils/index.js +9 -1
  167. package/core/server/api/endpoints/utils/permissions.js +2 -2
  168. package/core/server/api/endpoints/utils/serializers/input/pages.js +31 -3
  169. package/core/server/api/endpoints/utils/serializers/input/posts.js +30 -2
  170. package/core/server/api/endpoints/utils/serializers/input/utils/url.js +2 -2
  171. package/core/server/api/endpoints/utils/serializers/output/mappers/activity-feed-events.js +1 -1
  172. package/core/server/api/endpoints/utils/serializers/output/members.js +5 -10
  173. package/core/server/api/endpoints/utils/serializers/output/settings.js +4 -2
  174. package/core/server/api/endpoints/utils/serializers/output/tiers.js +3 -6
  175. package/core/server/api/endpoints/utils/validators/input/password_reset.js +1 -1
  176. package/core/server/api/endpoints/utils/validators/utils/json-schema.js +1 -2
  177. package/core/server/api/endpoints/webhooks.js +4 -1
  178. package/core/server/data/importer/import-manager.js +8 -0
  179. package/core/server/services/comments/CommentsController.js +1 -1
  180. package/core/server/services/url/UrlService.js +2 -4
  181. package/core/server/web/admin/app.js +5 -1
  182. package/core/server/web/admin/controller.js +6 -7
  183. package/core/server/web/admin/middleware/redirect-admin-urls.js +6 -0
  184. package/core/server/web/announcement/routes.js +3 -0
  185. package/core/server/web/api/app.js +3 -0
  186. package/core/server/web/api/endpoints/admin/app.js +4 -1
  187. package/core/server/web/api/endpoints/admin/middleware.js +14 -1
  188. package/core/server/web/api/endpoints/admin/routes.js +3 -0
  189. package/core/server/web/api/endpoints/content/app.js +3 -0
  190. package/core/server/web/api/endpoints/content/middleware.js +2 -0
  191. package/core/server/web/api/endpoints/content/routes.js +3 -0
  192. package/core/server/web/api/middleware/upload.js +26 -2
  193. package/core/server/web/comments/routes.js +3 -0
  194. package/core/server/web/members/app.js +15 -4
  195. package/core/server/web/parent/app.js +3 -0
  196. package/core/server/web/parent/backend.js +1 -1
  197. package/core/server/web/parent/frontend.js +1 -1
  198. package/core/server/web/parent/middleware/emit-events.js +5 -0
  199. package/core/server/web/parent/middleware/ghost-locals.js +7 -2
  200. package/core/server/web/parent/middleware/log-request.js +4 -0
  201. package/core/server/web/parent/middleware/queue-request.js +6 -1
  202. package/core/server/web/parent/middleware/request-id.js +4 -0
  203. package/core/server/web/webmentions/routes.js +3 -0
  204. package/core/shared/express.js +5 -0
  205. package/core/shared/labs.js +1 -1
  206. package/core/shared/sentry.js +30 -24
  207. package/package.json +152 -152
  208. package/yarn.lock +612 -574
  209. package/components/tryghost-adapter-cache-memory-ttl-5.82.8.tgz +0 -0
  210. package/components/tryghost-adapter-cache-redis-5.82.8.tgz +0 -0
  211. package/components/tryghost-adapter-manager-5.82.8.tgz +0 -0
  212. package/components/tryghost-announcement-bar-settings-5.82.8.tgz +0 -0
  213. package/components/tryghost-api-framework-5.82.8.tgz +0 -0
  214. package/components/tryghost-api-version-compatibility-service-5.82.8.tgz +0 -0
  215. package/components/tryghost-audience-feedback-5.82.8.tgz +0 -0
  216. package/components/tryghost-bookshelf-repository-5.82.8.tgz +0 -0
  217. package/components/tryghost-bootstrap-socket-5.82.8.tgz +0 -0
  218. package/components/tryghost-constants-5.82.8.tgz +0 -0
  219. package/components/tryghost-data-generator-5.82.8.tgz +0 -0
  220. package/components/tryghost-domain-events-5.82.8.tgz +0 -0
  221. package/components/tryghost-donations-5.82.8.tgz +0 -0
  222. package/components/tryghost-dynamic-routing-events-5.82.8.tgz +0 -0
  223. package/components/tryghost-email-analytics-provider-mailgun-5.82.8.tgz +0 -0
  224. package/components/tryghost-email-analytics-service-5.82.8.tgz +0 -0
  225. package/components/tryghost-email-content-generator-5.82.8.tgz +0 -0
  226. package/components/tryghost-email-events-5.82.8.tgz +0 -0
  227. package/components/tryghost-email-suppression-list-5.82.8.tgz +0 -0
  228. package/components/tryghost-express-dynamic-redirects-5.82.8.tgz +0 -0
  229. package/components/tryghost-external-media-inliner-5.82.8.tgz +0 -0
  230. package/components/tryghost-extract-api-key-5.82.8.tgz +0 -0
  231. package/components/tryghost-ghost-5.82.8.tgz +0 -0
  232. package/components/tryghost-html-to-plaintext-5.82.8.tgz +0 -0
  233. package/components/tryghost-i18n-5.82.8.tgz +0 -0
  234. package/components/tryghost-importer-handler-content-files-5.82.8.tgz +0 -0
  235. package/components/tryghost-importer-revue-5.82.8.tgz +0 -0
  236. package/components/tryghost-in-memory-repository-5.82.8.tgz +0 -0
  237. package/components/tryghost-job-manager-5.82.8.tgz +0 -0
  238. package/components/tryghost-link-redirects-5.82.8.tgz +0 -0
  239. package/components/tryghost-link-replacer-5.82.8.tgz +0 -0
  240. package/components/tryghost-magic-link-5.82.8.tgz +0 -0
  241. package/components/tryghost-mail-events-5.82.8.tgz +0 -0
  242. package/components/tryghost-mailgun-client-5.82.8.tgz +0 -0
  243. package/components/tryghost-member-attribution-5.82.8.tgz +0 -0
  244. package/components/tryghost-member-events-5.82.8.tgz +0 -0
  245. package/components/tryghost-members-csv-5.82.8.tgz +0 -0
  246. package/components/tryghost-members-events-service-5.82.8.tgz +0 -0
  247. package/components/tryghost-members-importer-5.82.8.tgz +0 -0
  248. package/components/tryghost-members-offers-5.82.8.tgz +0 -0
  249. package/components/tryghost-members-payments-5.82.8.tgz +0 -0
  250. package/components/tryghost-members-ssr-5.82.8.tgz +0 -0
  251. package/components/tryghost-mentions-email-report-5.82.8.tgz +0 -0
  252. package/components/tryghost-milestones-5.82.8.tgz +0 -0
  253. package/components/tryghost-model-to-domain-event-interceptor-5.82.8.tgz +0 -0
  254. package/components/tryghost-mw-api-version-mismatch-5.82.8.tgz +0 -0
  255. package/components/tryghost-mw-cache-control-5.82.8.tgz +0 -0
  256. package/components/tryghost-mw-error-handler-5.82.8.tgz +0 -0
  257. package/components/tryghost-mw-session-from-token-5.82.8.tgz +0 -0
  258. package/components/tryghost-mw-update-user-last-seen-5.82.8.tgz +0 -0
  259. package/components/tryghost-mw-vhost-5.82.8.tgz +0 -0
  260. package/components/tryghost-nql-filter-expansions-5.82.8.tgz +0 -0
  261. package/components/tryghost-oembed-service-5.82.8.tgz +0 -0
  262. package/components/tryghost-package-json-5.82.8.tgz +0 -0
  263. package/components/tryghost-post-events-5.82.8.tgz +0 -0
  264. package/components/tryghost-post-revisions-5.82.8.tgz +0 -0
  265. package/components/tryghost-posts-service-5.82.8.tgz +0 -0
  266. package/components/tryghost-recommendations-5.82.8.tgz +0 -0
  267. package/components/tryghost-referrers-5.82.8.tgz +0 -0
  268. package/components/tryghost-security-5.82.8.tgz +0 -0
  269. package/components/tryghost-session-service-5.82.8.tgz +0 -0
  270. package/components/tryghost-settings-path-manager-5.82.8.tgz +0 -0
  271. package/components/tryghost-slack-notifications-5.82.8.tgz +0 -0
  272. package/components/tryghost-stats-service-5.82.8.tgz +0 -0
  273. package/components/tryghost-tiers-5.82.8.tgz +0 -0
  274. package/components/tryghost-verification-trigger-5.82.8.tgz +0 -0
  275. package/components/tryghost-version-notifications-data-service-5.82.8.tgz +0 -0
  276. package/components/tryghost-webmentions-5.82.8.tgz +0 -0
  277. /package/core/built/admin/assets/{chunk.799.5012e659e3d64d043636.js.LICENSE.txt → chunk.799.5bcf6feef26f9fe94f0a.js.LICENSE.txt} +0 -0
@@ -1,12 +1,20 @@
1
1
  const _ = require('lodash');
2
2
  const debug = require('@tryghost/debug')('api:endpoints:utils:serializers:input:pages');
3
- const mobiledoc = require('../../../../../lib/mobiledoc');
3
+ const {ValidationError} = require('@tryghost/errors');
4
+ const tpl = require('@tryghost/tpl');
4
5
  const url = require('./utils/url');
5
6
  const slugFilterOrder = require('./utils/slug-filter-order');
6
7
  const localUtils = require('../../index');
8
+ const mobiledoc = require('../../../../../lib/mobiledoc');
7
9
  const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
8
10
  const clean = require('./utils/clean');
9
11
  const lexical = require('../../../../../lib/lexical');
12
+ const sentry = require('../../../../../../shared/sentry');
13
+
14
+ const messages = {
15
+ failedHtmlToMobiledoc: 'Failed to convert HTML to Mobiledoc',
16
+ failedHtmlToLexical: 'Failed to convert HTML to Lexical'
17
+ };
10
18
 
11
19
  function removeSourceFormats(frame) {
12
20
  if (frame.options.formats?.includes('mobiledoc') || frame.options.formats?.includes('lexical')) {
@@ -136,7 +144,17 @@ module.exports = {
136
144
  if (process.env.CI) {
137
145
  console.time('htmlToMobiledocConverter (page)'); // eslint-disable-line no-console
138
146
  }
139
- frame.data.pages[0].mobiledoc = JSON.stringify(mobiledoc.htmlToMobiledocConverter(html));
147
+
148
+ try {
149
+ frame.data.pages[0].mobiledoc = JSON.stringify(mobiledoc.htmlToMobiledocConverter(html));
150
+ } catch (err) {
151
+ sentry.captureException(err);
152
+ throw new ValidationError({
153
+ message: tpl(messages.failedHtmlToMobiledoc),
154
+ err
155
+ });
156
+ }
157
+
140
158
  if (process.env.CI) {
141
159
  console.timeEnd('htmlToMobiledocConverter (page)'); // eslint-disable-line no-console
142
160
  }
@@ -146,7 +164,17 @@ module.exports = {
146
164
  if (process.env.CI) {
147
165
  console.time('htmlToLexicalConverter (page)'); // eslint-disable-line no-console
148
166
  }
149
- frame.data.pages[0].lexical = JSON.stringify(lexical.htmlToLexicalConverter(html));
167
+
168
+ try {
169
+ frame.data.pages[0].lexical = JSON.stringify(lexical.htmlToLexicalConverter(html));
170
+ } catch (err) {
171
+ sentry.captureException(err);
172
+ throw new ValidationError({
173
+ message: tpl(messages.failedHtmlToLexical),
174
+ err
175
+ });
176
+ }
177
+
150
178
  if (process.env.CI) {
151
179
  console.timeEnd('htmlToLexicalConverter (page)'); // eslint-disable-line no-console
152
180
  }
@@ -1,5 +1,7 @@
1
1
  const _ = require('lodash');
2
2
  const debug = require('@tryghost/debug')('api:endpoints:utils:serializers:input:posts');
3
+ const {ValidationError} = require('@tryghost/errors');
4
+ const tpl = require('@tryghost/tpl');
3
5
  const url = require('./utils/url');
4
6
  const slugFilterOrder = require('./utils/slug-filter-order');
5
7
  const localUtils = require('../../index');
@@ -7,6 +9,12 @@ const mobiledoc = require('../../../../../lib/mobiledoc');
7
9
  const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
8
10
  const clean = require('./utils/clean');
9
11
  const lexical = require('../../../../../lib/lexical');
12
+ const sentry = require('../../../../../../shared/sentry');
13
+
14
+ const messages = {
15
+ failedHtmlToMobiledoc: 'Failed to convert HTML to Mobiledoc',
16
+ failedHtmlToLexical: 'Failed to convert HTML to Lexical'
17
+ };
10
18
 
11
19
  function removeSourceFormats(frame) {
12
20
  if (frame.options.formats?.includes('mobiledoc') || frame.options.formats?.includes('lexical')) {
@@ -170,7 +178,17 @@ module.exports = {
170
178
  if (process.env.CI) {
171
179
  console.time('htmlToMobiledocConverter (post)'); // eslint-disable-line no-console
172
180
  }
173
- frame.data.posts[0].mobiledoc = JSON.stringify(mobiledoc.htmlToMobiledocConverter(html));
181
+
182
+ try {
183
+ frame.data.posts[0].mobiledoc = JSON.stringify(mobiledoc.htmlToMobiledocConverter(html));
184
+ } catch (err) {
185
+ sentry.captureException(err);
186
+ throw new ValidationError({
187
+ message: tpl(messages.failedHtmlToMobiledoc),
188
+ err
189
+ });
190
+ }
191
+
174
192
  if (process.env.CI) {
175
193
  console.timeEnd('htmlToMobiledocConverter (post)'); // eslint-disable-line no-console
176
194
  }
@@ -180,7 +198,17 @@ module.exports = {
180
198
  if (process.env.CI) {
181
199
  console.time('htmlToLexicalConverter (post)'); // eslint-disable-line no-console
182
200
  }
183
- frame.data.posts[0].lexical = JSON.stringify(lexical.htmlToLexicalConverter(html));
201
+
202
+ try {
203
+ frame.data.posts[0].lexical = JSON.stringify(lexical.htmlToLexicalConverter(html));
204
+ } catch (err) {
205
+ sentry.captureException(err);
206
+ throw new ValidationError({
207
+ message: tpl(messages.failedHtmlToLexical),
208
+ err
209
+ });
210
+ }
211
+
184
212
  if (process.env.CI) {
185
213
  console.timeEnd('htmlToLexicalConverter (post)'); // eslint-disable-line no-console
186
214
  }
@@ -25,11 +25,11 @@ const forPost = (attrs, options) => {
25
25
  }
26
26
 
27
27
  if (relation === 'author' && attrs.author) {
28
- attrs.author = forUser(attrs.author, options);
28
+ attrs.author = forUser(attrs.author);
29
29
  }
30
30
 
31
31
  if (relation === 'authors' && attrs.authors) {
32
- attrs.authors = attrs.authors.map(author => forUser(author, options));
32
+ attrs.authors = attrs.authors.map(author => forUser(author));
33
33
  }
34
34
  });
35
35
  }
@@ -144,7 +144,7 @@ const activityFeedMapper = (event, frame) => {
144
144
  return clickEventMapper(event, frame);
145
145
  }
146
146
  if (event.type === 'aggregated_click_event') {
147
- return aggregatedClickEventMapper(event, frame);
147
+ return aggregatedClickEventMapper(event);
148
148
  }
149
149
  if (event.type === 'feedback_event') {
150
150
  return feedbackEventMapper(event, frame);
@@ -28,7 +28,7 @@ module.exports = {
28
28
  *
29
29
  * @param {{data: import('bookshelf').Model[], meta: PageMeta}} page
30
30
  * @param {APIConfig} _apiConfig
31
- * @param {Frame} frame
31
+ * @param {import('@tryghost/api-framework').Frame} frame
32
32
  *
33
33
  * @returns {{members: SerializedMember[], meta: PageMeta}}
34
34
  */
@@ -42,7 +42,7 @@ function paginatedMembers(page, _apiConfig, frame) {
42
42
  /**
43
43
  * @param {import('bookshelf').Model} model
44
44
  * @param {APIConfig} _apiConfig
45
- * @param {Frame} frame
45
+ * @param {import('@tryghost/api-framework').Frame} frame
46
46
  *
47
47
  * @returns {{members: SerializedMember[]}}
48
48
  */
@@ -55,7 +55,7 @@ function singleMember(model, _apiConfig, frame) {
55
55
  /**
56
56
  * @param {object} bulkActionResult
57
57
  * @param {APIConfig} _apiConfig
58
- * @param {Frame} frame
58
+ * @param {import('@tryghost/api-framework').Frame} frame
59
59
  *
60
60
  * @returns {{bulk: SerializedBulkAction}}
61
61
  */
@@ -219,9 +219,9 @@ function passthrough(data) {
219
219
  * @template Data
220
220
  * @template Response
221
221
  * @param {string} debugString
222
- * @param {(data: Data, apiConfig: APIConfig, frame: Frame) => Response} serialize - A function to serialize the data into an object suitable for API response
222
+ * @param {(data: Data, apiConfig: APIConfig, frame: import('@tryghost/api-framework').Frame) => Response} serialize
223
223
  *
224
- * @returns {(data: Data, apiConfig: APIConfig, frame: Frame) => void}
224
+ * @returns {(data: Data, apiConfig: APIConfig, frame: import('@tryghost/api-framework').Frame) => void}
225
225
  */
226
226
  function createSerializer(debugString, serialize) {
227
227
  return function serializer(data, apiConfig, frame) {
@@ -355,8 +355,3 @@ function createSerializer(debugString, serialize) {
355
355
  * @prop {string} docName
356
356
  * @prop {string} method
357
357
  */
358
-
359
- /**
360
- * @typedef {Object<string, any>} Frame
361
- * @prop {Object} options
362
- */
@@ -2,6 +2,8 @@ const _ = require('lodash');
2
2
  const utils = require('../../index');
3
3
  const mappers = require('./mappers');
4
4
 
5
+ /** @typedef {import('@tryghost/api-framework').Frame} Frame */
6
+
5
7
  /**
6
8
  * Filters an object based on a given filter object
7
9
  * @private
@@ -25,7 +27,7 @@ function settingsFilter(settings, filter) {
25
27
  *
26
28
  * @param {Object} models
27
29
  * @param {Object} apiConfig
28
- * @param {Object} frame
30
+ * @param {Frame} frame
29
31
  */
30
32
  function serializeSettings(models, apiConfig, frame) {
31
33
  let filteredSettings;
@@ -79,7 +81,7 @@ function passthrough(data) {
79
81
  * @template Data
80
82
  * @param {Data} data
81
83
  * @param {Object} apiConfig
82
- * @param {Object} frame
84
+ * @param {Frame} frame
83
85
  */
84
86
  function serializeData(data, apiConfig, frame) {
85
87
  frame.response = data;
@@ -20,7 +20,7 @@ module.exports = {
20
20
  function paginatedTiers(page, _apiConfig, frame) {
21
21
  return {
22
22
  tiers: page.data.map((model) => {
23
- return serializeTier(model, frame.options, frame);
23
+ return serializeTier(model, frame.options);
24
24
  }),
25
25
  meta: page.meta
26
26
  };
@@ -36,7 +36,7 @@ function paginatedTiers(page, _apiConfig, frame) {
36
36
  function singleTier(model, _apiConfig, frame) {
37
37
  return {
38
38
  tiers: [
39
- serializeTier(model, frame.options, frame)
39
+ serializeTier(model, frame.options)
40
40
  ]
41
41
  };
42
42
  }
@@ -131,7 +131,4 @@ function createSerializer(debugString, serialize) {
131
131
  * @prop {string} method
132
132
  */
133
133
 
134
- /**
135
- * @typedef {Object<string, any>} Frame
136
- * @prop {Object} options
137
- */
134
+ /** @typedef {import('@tryghost/api-framework').Frame} Frame */
@@ -25,7 +25,7 @@ module.exports = {
25
25
  generateResetToken(apiConfig, frame) {
26
26
  debug('generateResetToken');
27
27
 
28
- const email = frame.data.password_reset[0].email;
28
+ const email = frame.data.password_reset?.[0]?.email;
29
29
 
30
30
  if (typeof email !== 'string' || !validator.isEmail(email)) {
31
31
  throw new errors.BadRequestError({
@@ -5,8 +5,7 @@ const jsonSchema = require('@tryghost/admin-api-schema');
5
5
  * @param {Object} apiConfig "frame" api configuration object
6
6
  * @param {string} apiConfig.docName the name of the resource
7
7
  * @param {string} apiConfig.method API's method name
8
- * @param {Object} frame "frame" object with data attached to it
9
- * @param {Object} frame.data request data to validate
8
+ * @param {import('@tryghost/api-framework').Frame} frame "frame" object with data attached to it
10
9
  */
11
10
  const validate = async (apiConfig, frame) => await jsonSchema.validate({
12
11
  data: frame.data,
@@ -15,7 +15,8 @@ const webhooksService = getWebhooksServiceInstance({
15
15
  WebhookModel: models.Webhook
16
16
  });
17
17
 
18
- module.exports = {
18
+ /** @type {import('@tryghost/api-framework').Controller} */
19
+ const controller = {
19
20
  docName: 'webhooks',
20
21
 
21
22
  add: {
@@ -133,3 +134,5 @@ module.exports = {
133
134
  }
134
135
  }
135
136
  };
137
+
138
+ module.exports = controller;
@@ -235,6 +235,14 @@ class ImportManager {
235
235
  help: tpl(messages.invalidZipFileNameEncodingHelp),
236
236
  code: 'INVALID_ZIP_FILE_NAME_ENCODING'
237
237
  });
238
+ } else if (
239
+ err.message.includes('end of central directory record signature not found')
240
+ || err.message.includes('invalid comment length')
241
+ ) { // This comes from Yauzl when the zip is invalid
242
+ throw new errors.UnsupportedMediaTypeError({
243
+ message: tpl(messages.invalidZipFileNameEncoding),
244
+ code: 'INVALID_ZIP_FILE'
245
+ });
238
246
  }
239
247
  throw err;
240
248
  }
@@ -2,7 +2,7 @@ const _ = require('lodash');
2
2
  const errors = require('@tryghost/errors');
3
3
 
4
4
  /**
5
- * @typedef {import('../../api/shared/frame')} Frame
5
+ * @typedef {import('@tryghost/api-framework').Frame} Frame
6
6
  */
7
7
 
8
8
  const {MethodNotAllowedError} = require('@tryghost/errors');
@@ -219,14 +219,12 @@ class UrlService {
219
219
  * They would show localhost:2368/null/.
220
220
  *
221
221
  * @param {String} id
222
- * @param {Object} options
222
+ * @param {Object} [options]
223
223
  * @param {Object} [options.absolute]
224
224
  * @param {Object} [options.withSubdirectory]
225
225
  * @returns {String}
226
226
  */
227
- getUrlByResourceId(id, options) {
228
- options = options || {};
229
-
227
+ getUrlByResourceId(id, options = {}) {
230
228
  const obj = this.urls.getByResourceId(id);
231
229
 
232
230
  if (obj) {
@@ -10,6 +10,10 @@ const errorHandler = require('@tryghost/mw-error-handler');
10
10
  const sentry = require('../../../shared/sentry');
11
11
  const redirectAdminUrls = require('./middleware/redirect-admin-urls');
12
12
 
13
+ /**
14
+ *
15
+ * @returns {import('express').Application}
16
+ */
13
17
  module.exports = function setupAdminApp() {
14
18
  debug('Admin setup start');
15
19
  const adminApp = express('admin');
@@ -34,7 +38,7 @@ module.exports = function setupAdminApp() {
34
38
  // request to the Admin API /users/me/ endpoint to check if the user is logged in.
35
39
  //
36
40
  // Used by comments-ui to add moderation options to front-end comments when logged in.
37
- adminApp.use('/auth-frame', (req, res, next) => {
41
+ adminApp.use('/auth-frame', function authFrameMw(req, res, next) {
38
42
  // only render content when we have an Admin session cookie,
39
43
  // otherwise return a 204 to avoid JS and API requests being made unnecessarily
40
44
  try {
@@ -20,8 +20,8 @@ const messages = {
20
20
  *
21
21
  * Every request to the admin panel will re-trigger the update check service.
22
22
  *
23
- * @param req
24
- * @param res
23
+ * @param {import('express').Request} req
24
+ * @param {import('express').Response} res
25
25
  */
26
26
  module.exports = function adminController(req, res) {
27
27
  debug('index called');
@@ -47,16 +47,15 @@ module.exports = function adminController(req, res) {
47
47
  }
48
48
 
49
49
  res.sendFile(templatePath, {headers});
50
- } catch (error) {
51
- if (error.code === 'ENOENT') {
50
+ } catch (err) {
51
+ if (err.code === 'ENOENT') {
52
52
  throw new errors.IncorrectUsageError({
53
53
  message: tpl(messages.templateError.message, {templatePath}),
54
54
  context: tpl(messages.templateError.context),
55
55
  help: tpl(messages.templateError.help, {link: 'https://ghost.org/docs/install/source/'}),
56
- error: error
56
+ err
57
57
  });
58
- } else {
59
- throw error;
60
58
  }
59
+ throw err;
61
60
  }
62
61
  };
@@ -1,5 +1,11 @@
1
1
  const urlUtils = require('../../../../shared/url-utils');
2
2
 
3
+ /**
4
+ *
5
+ * @param {import('express').Request} req
6
+ * @param {import('express').Response} res
7
+ * @param {import('express').NextFunction} next
8
+ */
3
9
  function redirectAdminUrls(req, res, next) {
4
10
  const subdir = urlUtils.getSubdir();
5
11
  const ghostPathRegex = new RegExp(`^${subdir}/ghost/(.+)`);
@@ -3,6 +3,9 @@ const api = require('../../api').endpoints;
3
3
  const {http} = require('@tryghost/api-framework');
4
4
  const shared = require('../shared');
5
5
 
6
+ /**
7
+ * @returns {import('express').Router}
8
+ */
6
9
  module.exports = function apiRoutes() {
7
10
  const router = express.Router('announcements');
8
11
 
@@ -5,6 +5,9 @@ const sentry = require('../../../shared/sentry');
5
5
  const errorHandler = require('@tryghost/mw-error-handler');
6
6
  const APIVersionCompatibilityService = require('../../services/api-version-compatibility');
7
7
 
8
+ /**
9
+ * @returns {import('express').Application}
10
+ */
8
11
  module.exports = function setupApiApp() {
9
12
  debug('Parent API setup start');
10
13
  const apiApp = express('api');
@@ -12,6 +12,9 @@ const routes = require('./routes');
12
12
  const APIVersionCompatibilityService = require('../../../../services/api-version-compatibility');
13
13
  const GhostNestApp = require('@tryghost/ghost');
14
14
 
15
+ /**
16
+ * @returns {import('express').Application}
17
+ */
15
18
  module.exports = function setupApiApp() {
16
19
  debug('Admin API setup start');
17
20
  const apiApp = express('admin api');
@@ -35,7 +38,7 @@ module.exports = function setupApiApp() {
35
38
  // Routing
36
39
  apiApp.use(routes());
37
40
 
38
- apiApp.use(async (req, res, next) => {
41
+ apiApp.use(async function nestApp(req, res, next) {
39
42
  if (labs.isSet('NestPlayground') || labs.isSet('ActivityPub')) {
40
43
  const originalExpressApp = req.app;
41
44
  const app = await GhostNestApp.getApp();
@@ -8,6 +8,11 @@ const messages = {
8
8
  notImplemented: 'The server does not support the functionality required to fulfill the request.'
9
9
  };
10
10
 
11
+ /**
12
+ * @param {import('express').Request} req
13
+ * @param {import('express').Response} res
14
+ * @param {import('express').NextFunction} next
15
+ */
11
16
  const notImplemented = function notImplemented(req, res, next) {
12
17
  // CASE: user is logged in, allow
13
18
  if (!req.api_key) {
@@ -59,12 +64,16 @@ const notImplemented = function notImplemented(req, res, next) {
59
64
  next(new errors.InternalServerError({
60
65
  errorType: 'NotImplementedError',
61
66
  message: tpl(messages.notImplemented),
62
- statusCode: '501'
67
+ statusCode: 501
63
68
  }));
64
69
  };
65
70
 
71
+ /** @typedef {import('express').RequestHandler} RequestHandler */
72
+
66
73
  /**
67
74
  * Authentication for private endpoints
75
+ *
76
+ * @type {RequestHandler[]}
68
77
  */
69
78
  module.exports.authAdminApi = [
70
79
  auth.authenticate.authenticateAdminApi,
@@ -79,6 +88,8 @@ module.exports.authAdminApi = [
79
88
  /**
80
89
  * Authentication for private endpoints with token in URL
81
90
  * Ex.: For scheduler publish endpoint
91
+ *
92
+ * @type {RequestHandler[]}
82
93
  */
83
94
  module.exports.authAdminApiWithUrl = [
84
95
  auth.authenticate.authenticateAdminApiWithUrl,
@@ -92,6 +103,8 @@ module.exports.authAdminApiWithUrl = [
92
103
 
93
104
  /**
94
105
  * Middleware for public admin endpoints
106
+ *
107
+ * @type {RequestHandler[]}
95
108
  */
96
109
  module.exports.publicAdminApi = [
97
110
  apiMw.cors,
@@ -7,6 +7,9 @@ const mw = require('./middleware');
7
7
  const shared = require('../../../shared');
8
8
  const labs = require('../../../../../shared/labs');
9
9
 
10
+ /**
11
+ * @returns {import('express').Router}
12
+ */
10
13
  module.exports = function apiRoutes() {
11
14
  const router = express.Router('admin api');
12
15
 
@@ -9,6 +9,9 @@ const routes = require('./routes');
9
9
  const errorHandler = require('@tryghost/mw-error-handler');
10
10
  const apiVersionCompatibility = require('../../../../services/api-version-compatibility');
11
11
 
12
+ /**
13
+ * @returns {import('express').Application}
14
+ */
12
15
  module.exports = function setupApiApp() {
13
16
  debug('Content API setup start');
14
17
  const apiApp = express('content api');
@@ -12,6 +12,8 @@ const shared = require('../../../shared');
12
12
 
13
13
  /**
14
14
  * Authentication for public endpoints
15
+ *
16
+ * @type {import('express').RequestHandler[]}
15
17
  */
16
18
  module.exports.authenticatePublic = [
17
19
  shared.middleware.brute.contentApiKey,
@@ -5,6 +5,9 @@ const {http} = require('@tryghost/api-framework');
5
5
  const mw = require('./middleware');
6
6
  const config = require('../../../../../shared/config');
7
7
 
8
+ /**
9
+ * @returns {import('express').Router}
10
+ */
8
11
  module.exports = function apiRoutes() {
9
12
  const router = express.Router('content api');
10
13
 
@@ -24,6 +24,10 @@ const messages = {
24
24
  missingFile: 'Please select a theme.',
25
25
  invalidFile: 'Please select a valid zip file.'
26
26
  },
27
+ members: {
28
+ missingFile: 'Please select a members CSV file.',
29
+ invalidFile: 'Please select a valid CSV file.'
30
+ },
27
31
  images: {
28
32
  missingFile: 'Please select an image.',
29
33
  invalidFile: 'Please select a valid image.'
@@ -58,6 +62,13 @@ const single = name => function singleUploadFunction(req, res, next) {
58
62
 
59
63
  singleUpload(req, res, (err) => {
60
64
  if (err) {
65
+ // Busboy, Multer or Dicer errors are usually caused by invalid file uploads
66
+ if (err instanceof multer.MulterError || err.stack?.includes('dicer') || err.stack?.includes('busboy')) {
67
+ return next(new errors.BadRequestError({
68
+ err
69
+ }));
70
+ }
71
+
61
72
  return next(err);
62
73
  }
63
74
  if (enabledClear) {
@@ -94,6 +105,13 @@ const media = (fileName, thumbName) => function mediaUploadFunction(req, res, ne
94
105
 
95
106
  mediaUpload(req, res, (err) => {
96
107
  if (err) {
108
+ // Busboy, Multer or Dicer errors are usually caused by invalid file uploads
109
+ if (err instanceof multer.MulterError || err.stack?.includes('dicer') || err.stack?.includes('busboy')) {
110
+ return next(new errors.BadRequestError({
111
+ err
112
+ }));
113
+ }
114
+
97
115
  return next(err);
98
116
  }
99
117
 
@@ -138,10 +156,16 @@ const checkFileIsValid = (fileData, types, extensions) => {
138
156
  *
139
157
  * @param {Object} options
140
158
  * @param {String} options.type - type of the file
141
- * @returns {Function}
159
+ * @returns {import('express').RequestHandler}
142
160
  */
143
161
  const validation = function ({type}) {
144
162
  // if we finish the data/importer logic, we forward the request to the specified importer
163
+
164
+ /**
165
+ * @param {import('express').Request} req
166
+ * @param {import('express').Response} res
167
+ * @param {import('express').NextFunction} next
168
+ */
145
169
  return function uploadValidation(req, res, next) {
146
170
  const extensions = (config.get('uploads')[type] && config.get('uploads')[type].extensions) || [];
147
171
  const contentTypes = (config.get('uploads')[type] && config.get('uploads')[type].contentTypes) || [];
@@ -174,7 +198,7 @@ const validation = function ({type}) {
174
198
  *
175
199
  * @param {Object} options
176
200
  * @param {String} options.type - type of the file
177
- * @returns {Function}
201
+ * @returns {import('express').RequestHandler}
178
202
  */
179
203
  const mediaValidation = function ({type}) {
180
204
  return function mediaUploadValidation(req, res, next) {
@@ -7,6 +7,9 @@ const shared = require('../shared');
7
7
  const bodyParser = require('body-parser');
8
8
  const membersService = require('../../../server/services/members');
9
9
 
10
+ /**
11
+ * @returns {import('express').Router}
12
+ */
10
13
  module.exports = function apiRoutes() {
11
14
  const router = express.Router('comment api');
12
15
  router.use(bodyParser.json({limit: '50mb'}));
@@ -16,6 +16,9 @@ const api = require('../../api').endpoints;
16
16
  const commentRouter = require('../comments');
17
17
  const announcementRouter = require('../announcement');
18
18
 
19
+ /**
20
+ * @returns {import('express').Application}
21
+ */
19
22
  module.exports = function setupMembersApp() {
20
23
  debug('Members App setup start');
21
24
  const membersApp = express('members');
@@ -61,11 +64,19 @@ module.exports = function setupMembersApp() {
61
64
  shared.middleware.brute.membersAuthEnumeration,
62
65
  // Prevent brute forcing passwords for the same email address
63
66
  shared.middleware.brute.membersAuth,
64
- (req, res, next) => membersService.api.middleware.sendMagicLink(req, res, next)
67
+ function lazySendMagicLinkMw(req, res, next) {
68
+ return membersService.api.middleware.sendMagicLink(req, res, next);
69
+ }
65
70
  );
66
- membersApp.post('/api/create-stripe-checkout-session', (req, res, next) => membersService.api.middleware.createCheckoutSession(req, res, next));
67
- membersApp.post('/api/create-stripe-update-session', (req, res, next) => membersService.api.middleware.createCheckoutSetupSession(req, res, next));
68
- membersApp.put('/api/subscriptions/:id', (req, res, next) => membersService.api.middleware.updateSubscription(req, res, next));
71
+ membersApp.post('/api/create-stripe-checkout-session', function lazyCreateCheckoutSessionMw(req, res, next) {
72
+ return membersService.api.middleware.createCheckoutSession(req, res, next);
73
+ });
74
+ membersApp.post('/api/create-stripe-update-session', function lazyCreateCheckoutSetupSessionMw(req, res, next) {
75
+ return membersService.api.middleware.createCheckoutSetupSession(req, res, next);
76
+ });
77
+ membersApp.put('/api/subscriptions/:id', function lazyUpdateSubscriptionMw(req, res, next) {
78
+ return membersService.api.middleware.updateSubscription(req, res, next);
79
+ });
69
80
 
70
81
  // Comments
71
82
  membersApp.use('/api/comments', commentRouter());
@@ -4,6 +4,9 @@ const express = require('../../../shared/express');
4
4
  const compress = require('compression');
5
5
  const mw = require('./middleware');
6
6
 
7
+ /**
8
+ * @returns {import('express').Application}
9
+ */
7
10
  module.exports = function setupParentApp() {
8
11
  debug('ParentApp setup start');
9
12
  const parentApp = express('parent');
@@ -4,7 +4,7 @@ const {BASE_API_PATH} = require('../../../shared/url-utils');
4
4
 
5
5
  /**
6
6
  *
7
- * @returns {import('express').RequestHandler}
7
+ * @returns {import('express').Application}
8
8
  */
9
9
  module.exports = () => {
10
10
  debug('BackendApp setup start');