ghost 5.115.0 → 5.116.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 (341) hide show
  1. package/components/{tryghost-api-framework-5.115.0.tgz → tryghost-api-framework-5.116.0.tgz} +0 -0
  2. package/components/tryghost-constants-5.116.0.tgz +0 -0
  3. package/components/tryghost-custom-fonts-5.116.0.tgz +0 -0
  4. package/components/{tryghost-custom-theme-settings-service-5.115.0.tgz → tryghost-custom-theme-settings-service-5.116.0.tgz} +0 -0
  5. package/components/tryghost-domain-events-5.116.0.tgz +0 -0
  6. package/components/{tryghost-donations-5.115.0.tgz → tryghost-donations-5.116.0.tgz} +0 -0
  7. package/components/tryghost-email-addresses-5.116.0.tgz +0 -0
  8. package/components/tryghost-email-service-5.116.0.tgz +0 -0
  9. package/components/tryghost-email-suppression-list-5.116.0.tgz +0 -0
  10. package/components/tryghost-html-to-plaintext-5.116.0.tgz +0 -0
  11. package/components/tryghost-i18n-5.116.0.tgz +0 -0
  12. package/components/tryghost-job-manager-5.116.0.tgz +0 -0
  13. package/components/tryghost-link-replacer-5.116.0.tgz +0 -0
  14. package/components/tryghost-magic-link-5.116.0.tgz +0 -0
  15. package/components/tryghost-member-attribution-5.116.0.tgz +0 -0
  16. package/components/tryghost-member-events-5.116.0.tgz +0 -0
  17. package/components/tryghost-members-api-5.116.0.tgz +0 -0
  18. package/components/tryghost-members-csv-5.116.0.tgz +0 -0
  19. package/components/{tryghost-members-offers-5.115.0.tgz → tryghost-members-offers-5.116.0.tgz} +0 -0
  20. package/components/{tryghost-milestones-5.115.0.tgz → tryghost-milestones-5.116.0.tgz} +0 -0
  21. package/components/{tryghost-mw-error-handler-5.115.0.tgz → tryghost-mw-error-handler-5.116.0.tgz} +0 -0
  22. package/components/tryghost-mw-vhost-5.116.0.tgz +0 -0
  23. package/components/{tryghost-post-events-5.115.0.tgz → tryghost-post-events-5.116.0.tgz} +0 -0
  24. package/components/{tryghost-post-revisions-5.115.0.tgz → tryghost-post-revisions-5.116.0.tgz} +0 -0
  25. package/components/tryghost-posts-service-5.116.0.tgz +0 -0
  26. package/components/{tryghost-prometheus-metrics-5.115.0.tgz → tryghost-prometheus-metrics-5.116.0.tgz} +0 -0
  27. package/components/tryghost-security-5.116.0.tgz +0 -0
  28. package/components/{tryghost-tiers-5.115.0.tgz → tryghost-tiers-5.116.0.tgz} +0 -0
  29. package/components/tryghost-webmentions-5.116.0.tgz +0 -0
  30. package/content/themes/casper/LICENSE +1 -1
  31. package/content/themes/casper/README.md +1 -1
  32. package/content/themes/source/LICENSE +1 -1
  33. package/content/themes/source/README.md +1 -1
  34. package/content/themes/source/assets/built/screen.css +1 -1
  35. package/content/themes/source/assets/built/screen.css.map +1 -1
  36. package/content/themes/source/assets/css/screen.css +11 -6
  37. package/content/themes/source/partials/feature-image.hbs +2 -2
  38. package/core/boot.js +3 -43
  39. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +30494 -29403
  40. package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +1 -1
  41. package/core/built/admin/assets/admin-x-demo/{index-0040480a.mjs → index-a9601514.mjs} +5 -4
  42. package/core/built/admin/assets/admin-x-demo/{modals-fb35c86c.mjs → modals-c1789d04.mjs} +67 -65
  43. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-806ef39c.mjs → CodeEditorView-e9c9deb8.mjs} +2 -2
  44. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
  45. package/core/built/admin/assets/admin-x-settings/{index-376f847c.mjs → index-84580c3a.mjs} +2 -2
  46. package/core/built/admin/assets/admin-x-settings/{index-8fa19303.mjs → index-f744cab7.mjs} +3147 -3123
  47. package/core/built/admin/assets/admin-x-settings/{modals-36775d71.mjs → modals-d9ca60c5.mjs} +1198 -1192
  48. package/core/built/admin/assets/chunk.524.8371443ef8f60db429d0.js +35 -0
  49. package/core/built/admin/assets/chunk.582.f90151775f2e53dd21d9.js +37 -0
  50. package/core/built/admin/assets/{chunk.874.461cb3cf5b6b36915f8c.js → chunk.713.e9027c0cc3c56110f5da.js} +125 -98
  51. package/core/built/admin/assets/{ghost-938b3d9c29e3564a53a22f8c8f82d351.js → ghost-03b64c086f3c60cabc85fe7a7e2b640a.js} +272 -251
  52. package/core/built/admin/assets/ghost-ba58e9822f7384461e926c7e23f04a75.css +1 -0
  53. package/core/built/admin/assets/ghost-dark-f1f29683b14ffa11615b3bba8b6ab92c.css +1 -0
  54. package/core/built/admin/assets/koenig-lexical/index.css +1 -1
  55. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +20563 -20891
  56. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +139 -139
  57. package/core/built/admin/assets/posts/posts.js +5732 -5667
  58. package/core/built/admin/assets/stats/stats.js +75373 -0
  59. package/core/built/admin/assets/{vendor-68a4aa424a179a90f5bbc2b750def576.js → vendor-72026232b36d97babc6320917c16c321.js} +36 -34
  60. package/core/built/admin/index.html +6 -6
  61. package/core/cli/generate-data.js +1 -1
  62. package/core/frontend/helpers/ghost_head.js +8 -1
  63. package/core/frontend/public/ghost-stats.js +55 -2
  64. package/core/frontend/services/assets-minification/AdminAuthAssets.js +2 -1
  65. package/core/frontend/services/assets-minification/CardAssets.js +1 -1
  66. package/core/frontend/services/assets-minification/CommentCountsAssets.js +1 -1
  67. package/core/frontend/services/assets-minification/MemberAttributionAssets.js +1 -1
  68. package/core/frontend/services/assets-minification/Minifier.js +191 -0
  69. package/core/frontend/services/routing/controllers/previews.js +2 -1
  70. package/core/frontend/src/cards/css/cta.css +1 -1
  71. package/core/server/adapters/cache/Redis.js +1 -1
  72. package/core/server/adapters/lib/redis/AdapterCacheRedis.js +287 -0
  73. package/core/server/adapters/lib/redis/redis-store-factory.js +22 -0
  74. package/core/server/api/endpoints/posts.js +9 -3
  75. package/core/server/api/endpoints/previews.js +35 -1
  76. package/core/server/api/endpoints/slugs.js +6 -2
  77. package/core/server/api/endpoints/utils/serializers/output/utils/post-gating.js +6 -9
  78. package/core/server/api/endpoints/utils/validators/input/settings.js +1 -1
  79. package/core/server/data/db/connection.js +2 -0
  80. package/core/server/data/db/index.js +1 -0
  81. package/core/server/data/importer/handlers/ImporterContentFileHandler.js +90 -0
  82. package/core/server/data/importer/import-manager.js +3 -3
  83. package/core/server/data/importer/importers/importer-revue.js +128 -0
  84. package/core/server/data/importer/importers/json-to-html.js +107 -0
  85. package/core/server/data/migrations/utils/tables.js +2 -4
  86. package/core/server/data/seeders/DataGenerator.js +288 -0
  87. package/core/server/data/seeders/importers/BenefitsImporter.js +28 -0
  88. package/core/server/data/seeders/importers/CommentsImporter.js +73 -0
  89. package/core/server/data/seeders/importers/EmailBatchesImporter.js +38 -0
  90. package/core/server/data/seeders/importers/EmailRecipientFailuresImporter.js +67 -0
  91. package/core/server/data/seeders/importers/EmailRecipientsImporter.js +212 -0
  92. package/core/server/data/seeders/importers/EmailsImporter.js +99 -0
  93. package/core/server/data/seeders/importers/LabelsImporter.js +41 -0
  94. package/core/server/data/seeders/importers/MembersClickEventsImporter.js +69 -0
  95. package/core/server/data/seeders/importers/MembersCreatedEventsImporter.js +103 -0
  96. package/core/server/data/seeders/importers/MembersFeedbackImporter.js +45 -0
  97. package/core/server/data/seeders/importers/MembersImporter.js +111 -0
  98. package/core/server/data/seeders/importers/MembersLabelsImporter.js +39 -0
  99. package/core/server/data/seeders/importers/MembersLoginEventsImporter.js +69 -0
  100. package/core/server/data/seeders/importers/MembersNewslettersImporter.js +38 -0
  101. package/core/server/data/seeders/importers/MembersPaidSubscriptionEventsImporter.js +99 -0
  102. package/core/server/data/seeders/importers/MembersProductsImporter.js +42 -0
  103. package/core/server/data/seeders/importers/MembersStatusEventsImporter.js +58 -0
  104. package/core/server/data/seeders/importers/MembersStripeCustomersImporter.js +60 -0
  105. package/core/server/data/seeders/importers/MembersStripeCustomersSubscriptionsImporter.js +259 -0
  106. package/core/server/data/seeders/importers/MembersSubscribeEventsImporter.js +69 -0
  107. package/core/server/data/seeders/importers/MembersSubscriptionCreatedEventsImporter.js +95 -0
  108. package/core/server/data/seeders/importers/NewslettersImporter.js +40 -0
  109. package/core/server/data/seeders/importers/OffersImporter.js +70 -0
  110. package/core/server/data/seeders/importers/PostsAuthorsImporter.js +32 -0
  111. package/core/server/data/seeders/importers/PostsImporter.js +102 -0
  112. package/core/server/data/seeders/importers/PostsProductsImporter.js +35 -0
  113. package/core/server/data/seeders/importers/PostsTagsImporter.js +46 -0
  114. package/core/server/data/seeders/importers/ProductsBenefitsImporter.js +54 -0
  115. package/core/server/data/seeders/importers/ProductsImporter.js +90 -0
  116. package/core/server/data/seeders/importers/RecommendationClickEventsImporter.js +32 -0
  117. package/core/server/data/seeders/importers/RecommendationSubscribeEventsImporter.js +32 -0
  118. package/core/server/data/seeders/importers/RecommendationsImporter.js +34 -0
  119. package/core/server/data/seeders/importers/RedirectsImporter.js +49 -0
  120. package/core/server/data/seeders/importers/RolesUsersImporter.js +42 -0
  121. package/core/server/data/seeders/importers/StripePricesImporter.js +69 -0
  122. package/core/server/data/seeders/importers/StripeProductsImporter.js +34 -0
  123. package/core/server/data/seeders/importers/TableImporter.js +187 -0
  124. package/core/server/data/seeders/importers/TagsImporter.js +41 -0
  125. package/core/server/data/seeders/importers/UsersImporter.js +31 -0
  126. package/core/server/data/seeders/importers/WebMentionsImporter.js +42 -0
  127. package/core/server/data/seeders/importers/index.js +41 -0
  128. package/core/server/data/seeders/utils/JsonImporter.js +39 -0
  129. package/core/server/data/seeders/utils/blog-info.js +3 -0
  130. package/core/server/data/seeders/utils/database-date.js +7 -0
  131. package/core/server/data/seeders/utils/event-generator.js +48 -0
  132. package/core/server/data/seeders/utils/random.js +13 -0
  133. package/core/server/data/seeders/utils/topological-sort.js +33 -0
  134. package/core/server/lib/bootstrap-socket.js +87 -0
  135. package/core/server/lib/package-json/index.js +1 -0
  136. package/core/server/lib/package-json/package-json.js +160 -0
  137. package/core/server/lib/package-json/parse.js +57 -0
  138. package/core/server/models/base/plugins/actions.js +44 -31
  139. package/core/server/models/base/plugins/generate-slug.js +6 -0
  140. package/core/server/notify.js +1 -1
  141. package/core/server/services/activitypub/ActivityPubService.ts +1 -1
  142. package/core/server/services/adapter-manager/AdapterManager.js +161 -0
  143. package/core/server/services/adapter-manager/index.js +1 -1
  144. package/core/server/services/announcement-bar-service/AnnouncementBarSettings.js +54 -0
  145. package/core/server/services/announcement-bar-service/AnnouncementVisibilityValues.js +11 -0
  146. package/core/server/services/announcement-bar-service/index.js +1 -1
  147. package/core/server/services/api-version-compatibility/APIVersionCompatibilityService.js +99 -0
  148. package/core/server/services/api-version-compatibility/VersionNotificationsDataService.js +80 -0
  149. package/core/server/services/api-version-compatibility/extract-api-key.js +57 -0
  150. package/core/server/services/api-version-compatibility/index.js +2 -2
  151. package/core/server/services/api-version-compatibility/mw-api-version-mismatch.js +31 -0
  152. package/core/server/services/audience-feedback/AudienceFeedbackController.js +85 -0
  153. package/core/server/services/audience-feedback/AudienceFeedbackService.js +34 -0
  154. package/core/server/services/audience-feedback/Feedback.js +35 -0
  155. package/core/server/services/audience-feedback/index.js +4 -2
  156. package/core/server/services/auth/session/emails/signin.js +168 -0
  157. package/core/server/services/auth/session/index.js +2 -2
  158. package/core/server/services/auth/session/session-from-token.js +69 -0
  159. package/core/server/services/auth/session/session-service.js +374 -0
  160. package/core/server/services/custom-redirects/index.js +1 -1
  161. package/core/server/services/email-analytics/EmailAnalyticsProviderMailgun.js +62 -0
  162. package/core/server/services/email-analytics/EmailAnalyticsService.js +552 -0
  163. package/core/server/services/email-analytics/EmailAnalyticsServiceWrapper.js +3 -3
  164. package/core/server/services/email-analytics/EventProcessingResult.js +66 -0
  165. package/core/server/services/email-service/EmailServiceWrapper.js +4 -4
  166. package/core/server/services/email-suppression-list/MailgunEmailSuppressionList.js +1 -1
  167. package/core/server/services/email-suppression-list/service.js +1 -1
  168. package/core/server/services/explore-ping/ExplorePingService.js +106 -0
  169. package/core/server/services/explore-ping/index.js +31 -0
  170. package/core/server/services/identity-tokens/IdentityTokenService.js +30 -0
  171. package/core/server/services/identity-tokens/IdentityTokenService.ts +28 -0
  172. package/core/server/services/identity-tokens/IdentityTokenServiceWrapper.js +1 -1
  173. package/core/server/services/invitations/accept.js +5 -2
  174. package/core/server/services/lib/DynamicRedirectManager.js +156 -0
  175. package/core/server/services/lib/EmailContentGenerator.js +54 -0
  176. package/core/server/services/lib/InMemoryRepository.js +62 -0
  177. package/core/server/services/lib/InMemoryRepository.ts +80 -0
  178. package/core/server/services/lib/MailgunClient.js +364 -0
  179. package/core/server/services/link-redirection/LinkRedirect.js +26 -0
  180. package/core/server/services/link-redirection/LinkRedirectRepository.js +7 -7
  181. package/core/server/services/link-redirection/LinkRedirectsService.js +123 -0
  182. package/core/server/services/link-redirection/README.md +151 -0
  183. package/core/server/services/link-redirection/RedirectEvent.js +24 -0
  184. package/core/server/services/link-redirection/index.js +1 -1
  185. package/core/server/services/link-tracking/LinkClickTrackingService.js +1 -1
  186. package/core/server/services/mail/index.js +1 -1
  187. package/core/server/services/mail-events/BookshelfMailEventRepository.js +2 -2
  188. package/core/server/services/mail-events/InMemoryMailEventRepository.js +10 -0
  189. package/core/server/services/mail-events/InMemoryMailEventRepository.ts +8 -0
  190. package/core/server/services/mail-events/MailEvent.js +20 -0
  191. package/core/server/services/mail-events/MailEvent.ts +10 -0
  192. package/core/server/services/mail-events/MailEventRepository.js +2 -0
  193. package/core/server/services/mail-events/MailEventRepository.ts +5 -0
  194. package/core/server/services/mail-events/MailEventService.js +124 -0
  195. package/core/server/services/mail-events/MailEventService.ts +169 -0
  196. package/core/server/services/mail-events/index.js +1 -1
  197. package/core/server/services/mail-events/libraries.d.ts +2 -0
  198. package/core/server/services/members/CaptchaService.js +80 -0
  199. package/core/server/services/members/api.js +1 -1
  200. package/core/server/services/members/importer/MembersCSVImporter.js +464 -0
  201. package/core/server/services/members/importer/MembersCSVImporterStripeUtils.js +194 -0
  202. package/core/server/services/members/importer/email-template.js +182 -0
  203. package/core/server/services/members/importer/index.js +30 -0
  204. package/core/server/services/members/members-ssr.js +333 -0
  205. package/core/server/services/members/service.js +2 -2
  206. package/core/server/services/members-events/LastSeenAtUpdater.js +1 -1
  207. package/core/server/services/offers/service.js +1 -1
  208. package/core/server/services/posts/stats/PostStats.js +13 -0
  209. package/core/server/services/recommendations/RecommendationServiceWrapper.js +8 -8
  210. package/core/server/services/recommendations/service/BookshelfClickEventRepository.js +48 -0
  211. package/core/server/services/recommendations/service/BookshelfClickEventRepository.ts +49 -0
  212. package/core/server/services/recommendations/service/BookshelfRecommendationRepository.js +98 -0
  213. package/core/server/services/recommendations/service/BookshelfRecommendationRepository.ts +117 -0
  214. package/core/server/services/recommendations/service/BookshelfRepository.js +134 -0
  215. package/core/server/services/recommendations/service/BookshelfRepository.ts +196 -0
  216. package/core/server/services/recommendations/service/BookshelfSubscribeEventRepository.js +48 -0
  217. package/core/server/services/recommendations/service/BookshelfSubscribeEventRepository.ts +49 -0
  218. package/core/server/services/recommendations/service/ClickEvent.js +33 -0
  219. package/core/server/services/recommendations/service/ClickEvent.ts +32 -0
  220. package/core/server/services/recommendations/service/InMemoryRecommendationRepository.js +19 -0
  221. package/core/server/services/recommendations/service/InMemoryRecommendationRepository.ts +20 -0
  222. package/core/server/services/recommendations/service/IncomingRecommendationController.js +34 -0
  223. package/core/server/services/recommendations/service/IncomingRecommendationController.ts +51 -0
  224. package/core/server/services/recommendations/service/IncomingRecommendationEmailRenderer.js +25 -0
  225. package/core/server/services/recommendations/service/IncomingRecommendationEmailRenderer.ts +37 -0
  226. package/core/server/services/recommendations/service/IncomingRecommendationService.js +93 -0
  227. package/core/server/services/recommendations/service/IncomingRecommendationService.ts +160 -0
  228. package/core/server/services/recommendations/service/Recommendation.js +140 -0
  229. package/core/server/services/recommendations/service/Recommendation.ts +201 -0
  230. package/core/server/services/recommendations/service/RecommendationController.js +208 -0
  231. package/core/server/services/recommendations/service/RecommendationController.ts +258 -0
  232. package/core/server/services/recommendations/service/RecommendationMetadataService.js +86 -0
  233. package/core/server/services/recommendations/service/RecommendationMetadataService.ts +128 -0
  234. package/core/server/services/recommendations/service/RecommendationRepository.js +2 -0
  235. package/core/server/services/recommendations/service/RecommendationRepository.ts +13 -0
  236. package/core/server/services/recommendations/service/RecommendationService.js +228 -0
  237. package/core/server/services/recommendations/service/RecommendationService.ts +281 -0
  238. package/core/server/services/recommendations/service/SubscribeEvent.js +33 -0
  239. package/core/server/services/recommendations/service/SubscribeEvent.ts +32 -0
  240. package/core/server/services/recommendations/service/UnsafeData.js +183 -0
  241. package/core/server/services/recommendations/service/UnsafeData.ts +217 -0
  242. package/core/server/services/recommendations/service/WellknownService.js +36 -0
  243. package/core/server/services/recommendations/service/WellknownService.ts +47 -0
  244. package/core/server/services/recommendations/service/index.js +31 -0
  245. package/core/server/services/recommendations/service/index.ts +15 -0
  246. package/core/server/services/recommendations/service/libraries.d.ts +5 -0
  247. package/core/server/services/route-settings/SettingsPathManager.js +47 -0
  248. package/core/server/services/route-settings/index.js +1 -1
  249. package/core/server/services/slack-notifications/SlackNotifications.js +211 -0
  250. package/core/server/services/slack-notifications/SlackNotificationsService.js +90 -0
  251. package/core/server/services/slack-notifications/service.js +4 -6
  252. package/core/server/services/stripe/README.md +63 -0
  253. package/core/server/services/stripe/StripeAPI.js +931 -0
  254. package/core/server/services/stripe/StripeMigrations.js +613 -0
  255. package/core/server/services/stripe/StripeService.js +175 -0
  256. package/core/server/services/stripe/WebhookController.js +100 -0
  257. package/core/server/services/stripe/WebhookManager.js +175 -0
  258. package/core/server/services/stripe/events/StripeLiveDisabledEvent.js +23 -0
  259. package/core/server/services/stripe/events/StripeLiveEnabledEvent.js +23 -0
  260. package/core/server/services/stripe/events/index.js +4 -0
  261. package/core/server/services/stripe/service.js +1 -1
  262. package/core/server/services/stripe/services/webhook/CheckoutSessionEventService.js +255 -0
  263. package/core/server/services/stripe/services/webhook/InvoiceEventService.js +70 -0
  264. package/core/server/services/stripe/services/webhook/SubscriptionEventService.js +54 -0
  265. package/core/server/services/themes/loader.js +1 -1
  266. package/core/server/services/themes/to-json.js +1 -1
  267. package/core/server/web/api/endpoints/admin/app.js +1 -21
  268. package/core/server/web/api/endpoints/admin/routes.js +1 -0
  269. package/core/server/web/api/middleware/version-match.js +41 -0
  270. package/core/server/web/shared/middleware/cache-control.js +51 -0
  271. package/core/server/web/shared/middleware/index.js +1 -1
  272. package/core/server/web/well-known.js +1 -1
  273. package/core/shared/labs.js +5 -3
  274. package/core/shared/settings-cache/CacheManager.js +64 -6
  275. package/package.json +98 -146
  276. package/tsconfig.tsbuildinfo +1 -1
  277. package/yarn.lock +1478 -1634
  278. package/components/tryghost-adapter-cache-redis-5.115.0.tgz +0 -0
  279. package/components/tryghost-adapter-manager-5.115.0.tgz +0 -0
  280. package/components/tryghost-announcement-bar-settings-5.115.0.tgz +0 -0
  281. package/components/tryghost-api-version-compatibility-service-5.115.0.tgz +0 -0
  282. package/components/tryghost-audience-feedback-5.115.0.tgz +0 -0
  283. package/components/tryghost-bookshelf-repository-5.115.0.tgz +0 -0
  284. package/components/tryghost-bootstrap-socket-5.115.0.tgz +0 -0
  285. package/components/tryghost-captcha-service-5.115.0.tgz +0 -0
  286. package/components/tryghost-constants-5.115.0.tgz +0 -0
  287. package/components/tryghost-custom-fonts-5.115.0.tgz +0 -0
  288. package/components/tryghost-data-generator-5.115.0.tgz +0 -0
  289. package/components/tryghost-domain-events-5.115.0.tgz +0 -0
  290. package/components/tryghost-email-addresses-5.115.0.tgz +0 -0
  291. package/components/tryghost-email-analytics-provider-mailgun-5.115.0.tgz +0 -0
  292. package/components/tryghost-email-analytics-service-5.115.0.tgz +0 -0
  293. package/components/tryghost-email-content-generator-5.115.0.tgz +0 -0
  294. package/components/tryghost-email-events-5.115.0.tgz +0 -0
  295. package/components/tryghost-email-service-5.115.0.tgz +0 -0
  296. package/components/tryghost-email-suppression-list-5.115.0.tgz +0 -0
  297. package/components/tryghost-express-dynamic-redirects-5.115.0.tgz +0 -0
  298. package/components/tryghost-extract-api-key-5.115.0.tgz +0 -0
  299. package/components/tryghost-ghost-5.115.0.tgz +0 -0
  300. package/components/tryghost-html-to-plaintext-5.115.0.tgz +0 -0
  301. package/components/tryghost-i18n-5.115.0.tgz +0 -0
  302. package/components/tryghost-identity-token-service-5.115.0.tgz +0 -0
  303. package/components/tryghost-importer-handler-content-files-5.115.0.tgz +0 -0
  304. package/components/tryghost-importer-revue-5.115.0.tgz +0 -0
  305. package/components/tryghost-in-memory-repository-5.115.0.tgz +0 -0
  306. package/components/tryghost-job-manager-5.115.0.tgz +0 -0
  307. package/components/tryghost-link-redirects-5.115.0.tgz +0 -0
  308. package/components/tryghost-link-replacer-5.115.0.tgz +0 -0
  309. package/components/tryghost-magic-link-5.115.0.tgz +0 -0
  310. package/components/tryghost-mail-events-5.115.0.tgz +0 -0
  311. package/components/tryghost-mailgun-client-5.115.0.tgz +0 -0
  312. package/components/tryghost-member-attribution-5.115.0.tgz +0 -0
  313. package/components/tryghost-member-events-5.115.0.tgz +0 -0
  314. package/components/tryghost-members-api-5.115.0.tgz +0 -0
  315. package/components/tryghost-members-csv-5.115.0.tgz +0 -0
  316. package/components/tryghost-members-importer-5.115.0.tgz +0 -0
  317. package/components/tryghost-members-payments-5.115.0.tgz +0 -0
  318. package/components/tryghost-members-ssr-5.115.0.tgz +0 -0
  319. package/components/tryghost-members-stripe-service-5.115.0.tgz +0 -0
  320. package/components/tryghost-minifier-5.115.0.tgz +0 -0
  321. package/components/tryghost-mw-api-version-mismatch-5.115.0.tgz +0 -0
  322. package/components/tryghost-mw-cache-control-5.115.0.tgz +0 -0
  323. package/components/tryghost-mw-session-from-token-5.115.0.tgz +0 -0
  324. package/components/tryghost-mw-update-user-last-seen-5.115.0.tgz +0 -0
  325. package/components/tryghost-mw-version-match-5.115.0.tgz +0 -0
  326. package/components/tryghost-mw-vhost-5.115.0.tgz +0 -0
  327. package/components/tryghost-package-json-5.115.0.tgz +0 -0
  328. package/components/tryghost-posts-service-5.115.0.tgz +0 -0
  329. package/components/tryghost-recommendations-5.115.0.tgz +0 -0
  330. package/components/tryghost-referrers-5.115.0.tgz +0 -0
  331. package/components/tryghost-security-5.115.0.tgz +0 -0
  332. package/components/tryghost-session-service-5.115.0.tgz +0 -0
  333. package/components/tryghost-settings-path-manager-5.115.0.tgz +0 -0
  334. package/components/tryghost-slack-notifications-5.115.0.tgz +0 -0
  335. package/components/tryghost-version-notifications-data-service-5.115.0.tgz +0 -0
  336. package/components/tryghost-webmentions-5.115.0.tgz +0 -0
  337. package/core/built/admin/assets/chunk.524.31419fdf6fb3859ecc1e.js +0 -35
  338. package/core/built/admin/assets/chunk.582.08c816d5e4ab766486a7.js +0 -37
  339. package/core/built/admin/assets/ghost-c2a7c4a1b76550c4219adb2ed4124ce0.css +0 -1
  340. package/core/built/admin/assets/ghost-dark-f91e4a479c6d38d94d5d1b14727871dc.css +0 -1
  341. /package/core/built/admin/assets/{chunk.874.461cb3cf5b6b36915f8c.js.LICENSE.txt → chunk.713.e9027c0cc3c56110f5da.js.LICENSE.txt} +0 -0
@@ -0,0 +1,228 @@
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.RecommendationService = void 0;
7
+ const errors_1 = __importDefault(require("@tryghost/errors"));
8
+ const logging_1 = __importDefault(require("@tryghost/logging"));
9
+ const tpl_1 = __importDefault(require("@tryghost/tpl"));
10
+ const ClickEvent_1 = require("./ClickEvent");
11
+ const Recommendation_1 = require("./Recommendation");
12
+ const SubscribeEvent_1 = require("./SubscribeEvent");
13
+ const messages = {
14
+ notFound: 'Recommendation with id {id} not found'
15
+ };
16
+ class RecommendationService {
17
+ repository;
18
+ clickEventRepository;
19
+ subscribeEventRepository;
20
+ wellknownService;
21
+ mentionSendingService;
22
+ recommendationEnablerService;
23
+ recommendationMetadataService;
24
+ constructor(deps) {
25
+ this.repository = deps.repository;
26
+ this.wellknownService = deps.wellknownService;
27
+ this.mentionSendingService = deps.mentionSendingService;
28
+ this.recommendationEnablerService = deps.recommendationEnablerService;
29
+ this.clickEventRepository = deps.clickEventRepository;
30
+ this.subscribeEventRepository = deps.subscribeEventRepository;
31
+ this.recommendationMetadataService = deps.recommendationMetadataService;
32
+ }
33
+ async init() {
34
+ const recommendations = await this.#listRecommendations();
35
+ await this.updateWellknown(recommendations);
36
+ // Do a slow update of all the recommendation metadata (keeping logo up to date, one-click-subscribe, etc.)
37
+ // We better move this to a job in the future
38
+ if (!process.env.NODE_ENV?.startsWith('test')) {
39
+ setTimeout(async () => {
40
+ try {
41
+ await this.updateAllRecommendationsMetadata();
42
+ }
43
+ catch (e) {
44
+ logging_1.default.error('[Recommendations] Failed to update all recommendations metadata on boot', e);
45
+ }
46
+ }, 2 * 60 * 1000 + Math.random() * 5 * 60 * 1000);
47
+ }
48
+ }
49
+ async updateAllRecommendationsMetadata() {
50
+ const recommendations = await this.#listRecommendations();
51
+ logging_1.default.info('[Recommendations] Updating recommendations metadata');
52
+ for (const recommendation of recommendations) {
53
+ try {
54
+ await this._updateRecommendationMetadata(recommendation);
55
+ await this.repository.save(recommendation);
56
+ }
57
+ catch (e) {
58
+ logging_1.default.error('[Recommendations] Failed to save updated metadata for recommendation ' + recommendation.url.toString(), e);
59
+ }
60
+ }
61
+ }
62
+ async updateWellknown(recommendations) {
63
+ await this.wellknownService.set(recommendations);
64
+ }
65
+ async updateRecommendationsEnabledSetting(recommendations) {
66
+ const expectedSetting = (recommendations.length > 0).toString();
67
+ const currentSetting = this.recommendationEnablerService.getSetting();
68
+ if (currentSetting && currentSetting === expectedSetting) {
69
+ return;
70
+ }
71
+ await this.recommendationEnablerService.setSetting(expectedSetting);
72
+ }
73
+ sendMentionToRecommendation(recommendation) {
74
+ this.mentionSendingService.sendAll({
75
+ url: this.wellknownService.getURL(),
76
+ links: [
77
+ recommendation.url
78
+ ]
79
+ }).catch((err) => {
80
+ logging_1.default.error('Failed to send mention to recommendation', err);
81
+ });
82
+ }
83
+ async readRecommendation(id) {
84
+ const recommendation = await this.repository.getById(id);
85
+ if (!recommendation) {
86
+ throw new errors_1.default.NotFoundError({
87
+ message: (0, tpl_1.default)(messages.notFound, { id })
88
+ });
89
+ }
90
+ return recommendation.plain;
91
+ }
92
+ async addRecommendation(addRecommendation) {
93
+ const recommendation = Recommendation_1.Recommendation.create(addRecommendation);
94
+ // If a recommendation with this URL already exists, throw an error
95
+ const existing = await this.repository.getByUrl(recommendation.url);
96
+ if (existing) {
97
+ throw new errors_1.default.ValidationError({
98
+ message: 'A recommendation with this URL already exists.'
99
+ });
100
+ }
101
+ await this.repository.save(recommendation);
102
+ const recommendations = await this.#listRecommendations();
103
+ await this.updateWellknown(recommendations);
104
+ await this.updateRecommendationsEnabledSetting(recommendations);
105
+ // Only send an update for the mentioned URL
106
+ this.sendMentionToRecommendation(recommendation);
107
+ return recommendation.plain;
108
+ }
109
+ async checkRecommendation(url) {
110
+ // If a recommendation with this URL already exists, return it, but with updated metadata
111
+ const existing = await this.repository.getByUrl(url);
112
+ if (existing) {
113
+ this._updateRecommendationMetadata(existing);
114
+ await this.repository.save(existing);
115
+ return existing.plain;
116
+ }
117
+ let metadata;
118
+ try {
119
+ metadata = await this.recommendationMetadataService.fetch(url);
120
+ }
121
+ catch (e) {
122
+ logging_1.default.error('[Recommendations] Failed to fetch metadata for url ' + url, e);
123
+ return {
124
+ url: url,
125
+ title: undefined,
126
+ excerpt: undefined,
127
+ featuredImage: undefined,
128
+ favicon: undefined,
129
+ oneClickSubscribe: false
130
+ };
131
+ }
132
+ return {
133
+ url: url,
134
+ title: metadata.title ?? undefined,
135
+ excerpt: metadata.excerpt ?? undefined,
136
+ featuredImage: metadata.featuredImage ?? undefined,
137
+ favicon: metadata.favicon ?? undefined,
138
+ oneClickSubscribe: !!metadata.oneClickSubscribe
139
+ };
140
+ }
141
+ async _updateRecommendationMetadata(recommendation) {
142
+ // Fetch data
143
+ try {
144
+ const metadata = await this.recommendationMetadataService.fetch(recommendation.url);
145
+ // Set null values to undefined so we don't trigger an update
146
+ recommendation.edit({
147
+ // Don't set title if it's already set on the recommendation
148
+ title: recommendation.title ? undefined : (metadata.title ?? undefined),
149
+ excerpt: metadata.excerpt ?? undefined,
150
+ featuredImage: metadata.featuredImage ?? undefined,
151
+ favicon: metadata.favicon ?? undefined,
152
+ oneClickSubscribe: !!metadata.oneClickSubscribe
153
+ });
154
+ }
155
+ catch (e) {
156
+ logging_1.default.error('[Recommendations] Failed to update metadata for recommendation ' + recommendation.url.toString(), e);
157
+ }
158
+ }
159
+ async editRecommendation(id, recommendationEdit) {
160
+ // Check if it exists
161
+ const existing = await this.repository.getById(id);
162
+ if (!existing) {
163
+ throw new errors_1.default.NotFoundError({
164
+ message: (0, tpl_1.default)(messages.notFound, { id })
165
+ });
166
+ }
167
+ existing.edit(recommendationEdit);
168
+ await this._updateRecommendationMetadata(existing);
169
+ await this.repository.save(existing);
170
+ const recommendations = await this.#listRecommendations();
171
+ await this.updateWellknown(recommendations);
172
+ this.sendMentionToRecommendation(existing);
173
+ return existing.plain;
174
+ }
175
+ async deleteRecommendation(id) {
176
+ const existing = await this.repository.getById(id);
177
+ if (!existing) {
178
+ throw new errors_1.default.NotFoundError({
179
+ message: (0, tpl_1.default)(messages.notFound, { id })
180
+ });
181
+ }
182
+ existing.delete();
183
+ await this.repository.save(existing);
184
+ const recommendations = await this.#listRecommendations();
185
+ await this.updateWellknown(recommendations);
186
+ await this.updateRecommendationsEnabledSetting(recommendations);
187
+ // Send a mention (because it was deleted, according to the webmentions spec)
188
+ this.sendMentionToRecommendation(existing);
189
+ }
190
+ /**
191
+ * Sames as listRecommendations, but returns Entities instead of plain objects (Entities are only used internally)
192
+ */
193
+ async #listRecommendations(options = { page: 1, limit: 'all' }) {
194
+ if (options.limit === 'all') {
195
+ return await this.repository.getAll({
196
+ ...options
197
+ });
198
+ }
199
+ return await this.repository.getPage({
200
+ ...options,
201
+ page: options.page || 1,
202
+ limit: options.limit || 15
203
+ });
204
+ }
205
+ async listRecommendations(options = { page: 1, limit: 'all', include: [] }) {
206
+ const list = await this.#listRecommendations(options);
207
+ return list.map(e => e.plain);
208
+ }
209
+ async countRecommendations({ filter }) {
210
+ return await this.repository.getCount({ filter });
211
+ }
212
+ async trackClicked({ id, memberId }) {
213
+ const clickEvent = ClickEvent_1.ClickEvent.create({ recommendationId: id, memberId });
214
+ await this.clickEventRepository.save(clickEvent);
215
+ }
216
+ async trackSubscribed({ id, memberId }) {
217
+ const subscribeEvent = SubscribeEvent_1.SubscribeEvent.create({ recommendationId: id, memberId });
218
+ await this.subscribeEventRepository.save(subscribeEvent);
219
+ }
220
+ async readRecommendationByUrl(url) {
221
+ const recommendation = await this.repository.getByUrl(url);
222
+ if (!recommendation) {
223
+ return null;
224
+ }
225
+ return recommendation.plain;
226
+ }
227
+ }
228
+ exports.RecommendationService = RecommendationService;
@@ -0,0 +1,281 @@
1
+ import errors from '@tryghost/errors';
2
+ import {InMemoryRepository} from '../../lib/InMemoryRepository';
3
+ import logging from '@tryghost/logging';
4
+ import tpl from '@tryghost/tpl';
5
+
6
+ import {IncludeOption, OrderOption} from './BookshelfRepository';
7
+ import {ClickEvent} from './ClickEvent';
8
+ import {AddRecommendation, Recommendation, RecommendationPlain} from './Recommendation';
9
+ import {RecommendationRepository} from './RecommendationRepository';
10
+ import {SubscribeEvent} from './SubscribeEvent';
11
+ import {WellknownService} from './WellknownService';
12
+ import {RecommendationMetadataService} from './RecommendationMetadataService';
13
+
14
+ type MentionSendingService = {
15
+ sendAll(options: {url: URL, links: URL[]}): Promise<void>
16
+ }
17
+
18
+ type RecommendationEnablerService = {
19
+ getSetting(): string,
20
+ setSetting(value: string): Promise<void>
21
+ }
22
+
23
+ const messages = {
24
+ notFound: 'Recommendation with id {id} not found'
25
+ };
26
+
27
+ export class RecommendationService {
28
+ repository: RecommendationRepository;
29
+ clickEventRepository: InMemoryRepository<string, ClickEvent>;
30
+ subscribeEventRepository: InMemoryRepository<string, SubscribeEvent>;
31
+
32
+ wellknownService: WellknownService;
33
+ mentionSendingService: MentionSendingService;
34
+ recommendationEnablerService: RecommendationEnablerService;
35
+ recommendationMetadataService: RecommendationMetadataService;
36
+
37
+ constructor(deps: {
38
+ repository: RecommendationRepository,
39
+ clickEventRepository: InMemoryRepository<string, ClickEvent>,
40
+ subscribeEventRepository: InMemoryRepository<string, SubscribeEvent>,
41
+ wellknownService: WellknownService,
42
+ mentionSendingService: MentionSendingService,
43
+ recommendationEnablerService: RecommendationEnablerService,
44
+ recommendationMetadataService: RecommendationMetadataService
45
+ }) {
46
+ this.repository = deps.repository;
47
+ this.wellknownService = deps.wellknownService;
48
+ this.mentionSendingService = deps.mentionSendingService;
49
+ this.recommendationEnablerService = deps.recommendationEnablerService;
50
+ this.clickEventRepository = deps.clickEventRepository;
51
+ this.subscribeEventRepository = deps.subscribeEventRepository;
52
+ this.recommendationMetadataService = deps.recommendationMetadataService;
53
+ }
54
+
55
+ async init() {
56
+ const recommendations = await this.#listRecommendations();
57
+ await this.updateWellknown(recommendations);
58
+
59
+ // Do a slow update of all the recommendation metadata (keeping logo up to date, one-click-subscribe, etc.)
60
+ // We better move this to a job in the future
61
+ if (!process.env.NODE_ENV?.startsWith('test')) {
62
+ setTimeout(async () => {
63
+ try {
64
+ await this.updateAllRecommendationsMetadata();
65
+ } catch (e) {
66
+ logging.error('[Recommendations] Failed to update all recommendations metadata on boot', e);
67
+ }
68
+ }, 2 * 60 * 1000 + Math.random() * 5 * 60 * 1000);
69
+ }
70
+ }
71
+
72
+ async updateAllRecommendationsMetadata() {
73
+ const recommendations = await this.#listRecommendations();
74
+ logging.info('[Recommendations] Updating recommendations metadata');
75
+ for (const recommendation of recommendations) {
76
+ try {
77
+ await this._updateRecommendationMetadata(recommendation);
78
+ await this.repository.save(recommendation);
79
+ } catch (e) {
80
+ logging.error('[Recommendations] Failed to save updated metadata for recommendation ' + recommendation.url.toString(), e);
81
+ }
82
+ }
83
+ }
84
+
85
+ async updateWellknown(recommendations: Recommendation[]) {
86
+ await this.wellknownService.set(recommendations);
87
+ }
88
+
89
+ async updateRecommendationsEnabledSetting(recommendations: Recommendation[]) {
90
+ const expectedSetting = (recommendations.length > 0).toString();
91
+ const currentSetting = this.recommendationEnablerService.getSetting();
92
+
93
+ if (currentSetting && currentSetting === expectedSetting) {
94
+ return;
95
+ }
96
+
97
+ await this.recommendationEnablerService.setSetting(expectedSetting);
98
+ }
99
+
100
+ private sendMentionToRecommendation(recommendation: Recommendation) {
101
+ this.mentionSendingService.sendAll({
102
+ url: this.wellknownService.getURL(),
103
+ links: [
104
+ recommendation.url
105
+ ]
106
+ }).catch((err) => {
107
+ logging.error('Failed to send mention to recommendation', err);
108
+ });
109
+ }
110
+
111
+ async readRecommendation(id: string): Promise<RecommendationPlain> {
112
+ const recommendation = await this.repository.getById(id);
113
+
114
+ if (!recommendation) {
115
+ throw new errors.NotFoundError({
116
+ message: tpl(messages.notFound, {id})
117
+ });
118
+ }
119
+
120
+ return recommendation.plain;
121
+ }
122
+
123
+ async addRecommendation(addRecommendation: AddRecommendation): Promise<RecommendationPlain> {
124
+ const recommendation = Recommendation.create(addRecommendation);
125
+
126
+ // If a recommendation with this URL already exists, throw an error
127
+ const existing = await this.repository.getByUrl(recommendation.url);
128
+ if (existing) {
129
+ throw new errors.ValidationError({
130
+ message: 'A recommendation with this URL already exists.'
131
+ });
132
+ }
133
+
134
+ await this.repository.save(recommendation);
135
+
136
+ const recommendations = await this.#listRecommendations();
137
+ await this.updateWellknown(recommendations);
138
+ await this.updateRecommendationsEnabledSetting(recommendations);
139
+
140
+ // Only send an update for the mentioned URL
141
+ this.sendMentionToRecommendation(recommendation);
142
+ return recommendation.plain;
143
+ }
144
+
145
+ async checkRecommendation(url: URL): Promise<Partial<RecommendationPlain>> {
146
+ // If a recommendation with this URL already exists, return it, but with updated metadata
147
+ const existing = await this.repository.getByUrl(url);
148
+ if (existing) {
149
+ this._updateRecommendationMetadata(existing);
150
+ await this.repository.save(existing);
151
+ return existing.plain;
152
+ }
153
+
154
+ let metadata;
155
+ try {
156
+ metadata = await this.recommendationMetadataService.fetch(url);
157
+ } catch (e) {
158
+ logging.error('[Recommendations] Failed to fetch metadata for url ' + url, e);
159
+
160
+ return {
161
+ url: url,
162
+ title: undefined,
163
+ excerpt: undefined,
164
+ featuredImage: undefined,
165
+ favicon: undefined,
166
+ oneClickSubscribe: false
167
+ };
168
+ }
169
+
170
+ return {
171
+ url: url,
172
+ title: metadata.title ?? undefined,
173
+ excerpt: metadata.excerpt ?? undefined,
174
+ featuredImage: metadata.featuredImage ?? undefined,
175
+ favicon: metadata.favicon ?? undefined,
176
+ oneClickSubscribe: !!metadata.oneClickSubscribe
177
+ };
178
+ }
179
+
180
+ async _updateRecommendationMetadata(recommendation: Recommendation) {
181
+ // Fetch data
182
+ try {
183
+ const metadata = await this.recommendationMetadataService.fetch(recommendation.url);
184
+
185
+ // Set null values to undefined so we don't trigger an update
186
+ recommendation.edit({
187
+ // Don't set title if it's already set on the recommendation
188
+ title: recommendation.title ? undefined : (metadata.title ?? undefined),
189
+ excerpt: metadata.excerpt ?? undefined,
190
+ featuredImage: metadata.featuredImage ?? undefined,
191
+ favicon: metadata.favicon ?? undefined,
192
+ oneClickSubscribe: !!metadata.oneClickSubscribe
193
+ });
194
+ } catch (e) {
195
+ logging.error('[Recommendations] Failed to update metadata for recommendation ' + recommendation.url.toString(), e);
196
+ }
197
+ }
198
+
199
+ async editRecommendation(id: string, recommendationEdit: Partial<Recommendation>): Promise<RecommendationPlain> {
200
+ // Check if it exists
201
+ const existing = await this.repository.getById(id);
202
+ if (!existing) {
203
+ throw new errors.NotFoundError({
204
+ message: tpl(messages.notFound, {id})
205
+ });
206
+ }
207
+
208
+ existing.edit(recommendationEdit);
209
+ await this._updateRecommendationMetadata(existing);
210
+ await this.repository.save(existing);
211
+
212
+ const recommendations = await this.#listRecommendations();
213
+ await this.updateWellknown(recommendations);
214
+
215
+ this.sendMentionToRecommendation(existing);
216
+ return existing.plain;
217
+ }
218
+
219
+ async deleteRecommendation(id: string) {
220
+ const existing = await this.repository.getById(id);
221
+ if (!existing) {
222
+ throw new errors.NotFoundError({
223
+ message: tpl(messages.notFound, {id})
224
+ });
225
+ }
226
+
227
+ existing.delete();
228
+ await this.repository.save(existing);
229
+
230
+ const recommendations = await this.#listRecommendations();
231
+ await this.updateWellknown(recommendations);
232
+ await this.updateRecommendationsEnabledSetting(recommendations);
233
+
234
+ // Send a mention (because it was deleted, according to the webmentions spec)
235
+ this.sendMentionToRecommendation(existing);
236
+ }
237
+
238
+ /**
239
+ * Sames as listRecommendations, but returns Entities instead of plain objects (Entities are only used internally)
240
+ */
241
+ async #listRecommendations(options: { filter?: string; order?: OrderOption<Recommendation>; page?: number; limit?: number|'all', include?: IncludeOption<Recommendation> } = {page: 1, limit: 'all'}): Promise<Recommendation[]> {
242
+ if (options.limit === 'all') {
243
+ return await this.repository.getAll({
244
+ ...options
245
+ });
246
+ }
247
+ return await this.repository.getPage({
248
+ ...options,
249
+ page: options.page || 1,
250
+ limit: options.limit || 15
251
+ });
252
+ }
253
+
254
+ async listRecommendations(options: { filter?: string; order?: OrderOption<Recommendation>; page?: number; limit?: number|'all', include?: IncludeOption<Recommendation> } = {page: 1, limit: 'all', include: []}): Promise<RecommendationPlain[]> {
255
+ const list = await this.#listRecommendations(options);
256
+ return list.map(e => e.plain);
257
+ }
258
+
259
+ async countRecommendations({filter}: { filter?: string }) {
260
+ return await this.repository.getCount({filter});
261
+ }
262
+
263
+ async trackClicked({id, memberId}: { id: string, memberId?: string }) {
264
+ const clickEvent = ClickEvent.create({recommendationId: id, memberId});
265
+ await this.clickEventRepository.save(clickEvent);
266
+ }
267
+
268
+ async trackSubscribed({id, memberId}: { id: string, memberId: string }) {
269
+ const subscribeEvent = SubscribeEvent.create({recommendationId: id, memberId});
270
+ await this.subscribeEventRepository.save(subscribeEvent);
271
+ }
272
+
273
+ async readRecommendationByUrl(url: URL): Promise<RecommendationPlain|null> {
274
+ const recommendation = await this.repository.getByUrl(url);
275
+
276
+ if (!recommendation) {
277
+ return null;
278
+ }
279
+ return recommendation.plain;
280
+ }
281
+ }
@@ -0,0 +1,33 @@
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.SubscribeEvent = void 0;
7
+ const bson_objectid_1 = __importDefault(require("bson-objectid"));
8
+ class SubscribeEvent {
9
+ id;
10
+ recommendationId;
11
+ memberId;
12
+ createdAt;
13
+ get deleted() {
14
+ return false;
15
+ }
16
+ constructor(data) {
17
+ this.id = data.id;
18
+ this.recommendationId = data.recommendationId;
19
+ this.memberId = data.memberId;
20
+ this.createdAt = data.createdAt;
21
+ }
22
+ static create(data) {
23
+ const id = data.id ?? (0, bson_objectid_1.default)().toString();
24
+ const d = {
25
+ id,
26
+ recommendationId: data.recommendationId,
27
+ memberId: data.memberId,
28
+ createdAt: data.createdAt ?? new Date()
29
+ };
30
+ return new SubscribeEvent(d);
31
+ }
32
+ }
33
+ exports.SubscribeEvent = SubscribeEvent;
@@ -0,0 +1,32 @@
1
+ import ObjectId from 'bson-objectid';
2
+
3
+ export class SubscribeEvent {
4
+ id: string;
5
+ recommendationId: string;
6
+ memberId: string|null;
7
+ createdAt: Date;
8
+
9
+ get deleted() {
10
+ return false;
11
+ }
12
+
13
+ private constructor(data: {id: string, recommendationId: string, memberId: string|null, createdAt: Date}) {
14
+ this.id = data.id;
15
+ this.recommendationId = data.recommendationId;
16
+ this.memberId = data.memberId;
17
+ this.createdAt = data.createdAt;
18
+ }
19
+
20
+ static create(data: {id?: string, recommendationId: string, memberId: string, createdAt?: Date}) {
21
+ const id = data.id ?? ObjectId().toString();
22
+
23
+ const d = {
24
+ id,
25
+ recommendationId: data.recommendationId,
26
+ memberId: data.memberId,
27
+ createdAt: data.createdAt ?? new Date()
28
+ };
29
+
30
+ return new SubscribeEvent(d);
31
+ }
32
+ }