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,182 @@
1
+ function formatNumber(number) {
2
+ return number.toLocaleString();
3
+ }
4
+
5
+ const iff = (cond, yes, no) => (cond ? yes : no);
6
+ module.exports = ({result, siteUrl, membersUrl, emailRecipient}) => `
7
+ <!doctype html>
8
+ <html>
9
+ <head>
10
+ <meta name="viewport" content="width=device-width">
11
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
12
+ <title>Your member import is complete</title>
13
+ <style>
14
+ /* -------------------------------------
15
+ RESPONSIVE AND MOBILE FRIENDLY STYLES
16
+ ------------------------------------- */
17
+ @media only screen and (max-width: 620px) {
18
+ table[class=body] h1 {
19
+ font-size: 28px !important;
20
+ margin-bottom: 10px !important;
21
+ }
22
+ table[class=body] p,
23
+ table[class=body] ul,
24
+ table[class=body] ol,
25
+ table[class=body] td,
26
+ table[class=body] span,
27
+ table[class=body] a {
28
+ font-size: 16px !important;
29
+ }
30
+ table[class=body] .title {
31
+ font-size: 22px !important;
32
+ }
33
+ table[class=body] .wrapper,
34
+ table[class=body] .article {
35
+ padding: 10px !important;
36
+ }
37
+ table[class=body] .content {
38
+ padding: 0 !important;
39
+ }
40
+ table[class=body] .container {
41
+ padding: 0 !important;
42
+ width: 100% !important;
43
+ }
44
+ table[class=body] .main {
45
+ border-left-width: 0 !important;
46
+ border-radius: 0 !important;
47
+ border-right-width: 0 !important;
48
+ }
49
+ table[class=body] .btn table {
50
+ width: 100% !important;
51
+ }
52
+ table[class=body] .btn a {
53
+ width: 100% !important;
54
+ }
55
+ table[class=body] .img-responsive {
56
+ height: auto !important;
57
+ max-width: 100% !important;
58
+ width: auto !important;
59
+ }
60
+ table[class=body] p[class=small],
61
+ table[class=body] a[class=small] {
62
+ font-size: 12x !important;
63
+ }
64
+ }
65
+ /* -------------------------------------
66
+ PRESERVE THESE STYLES IN THE HEAD
67
+ ------------------------------------- */
68
+ @media all {
69
+ .ExternalClass {
70
+ width: 100%;
71
+ }
72
+ .ExternalClass,
73
+ .ExternalClass p,
74
+ .ExternalClass span,
75
+ .ExternalClass font,
76
+ .ExternalClass td,
77
+ .ExternalClass div {
78
+ line-height: 100%;
79
+ }
80
+ .recipient-link a {
81
+ color: inherit !important;
82
+ font-family: inherit !important;
83
+ font-size: inherit !important;
84
+ font-weight: inherit !important;
85
+ line-height: inherit !important;
86
+ text-decoration: none !important;
87
+ }
88
+ #MessageViewBody a {
89
+ color: inherit;
90
+ text-decoration: none;
91
+ font-size: inherit;
92
+ font-family: inherit;
93
+ font-weight: inherit;
94
+ line-height: inherit;
95
+ }
96
+ }
97
+ hr {
98
+ border-width: 0;
99
+ height: 0;
100
+ margin-top: 34px;
101
+ margin-bottom: 34px;
102
+ border-bottom-width: 1px;
103
+ border-bottom-color: #EEF5F8;
104
+ }
105
+ a {
106
+ color: #3A464C;
107
+ }
108
+ </style>
109
+ </head>
110
+ <body class="" style="background-color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.5em; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;">
111
+ <table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
112
+ <tr>
113
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">&nbsp;</td>
114
+ <td class="container" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 540px; padding: 10px; width: 540px;">
115
+ <div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 600px; padding: 30px 20px;">
116
+
117
+ <!-- START CENTERED CONTAINER -->
118
+ <span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">Your member import is complete</span>
119
+ <table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 8px;">
120
+
121
+ <!-- START MAIN CONTENT AREA -->
122
+ <tr>
123
+ <td class="wrapper" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; box-sizing: border-box;">
124
+ <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
125
+ <tr>
126
+ <td align="center" style="padding-top: 20px; padding-bottom: 12px;"><img src="https://static.ghost.org/v4.0.0/images/ghost-orb-4.png" width="60" height="60" style="width: 60px; height: 60px;" /></td>
127
+ </tr>
128
+ <tr>
129
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top;">
130
+ <p class="title" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 21px; color: #3A464C; font-weight: normal; line-height: 25px; margin-bottom: 30px; margin-top: 50px; font-weight: 600; color: #15212A;">${iff(result.imported > 0, `Your member import is complete`, `Your member import was unsuccessful`)}</p>
131
+ </td>
132
+ </tr>
133
+ ${iff(result.imported === 0 && result.errors.length === 0, `
134
+ <tr>
135
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 16px;">
136
+ <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 0px;">No members were added.</p>
137
+ </td>
138
+ </tr>
139
+ `, ``)}
140
+ ${iff(result.imported > 0, `
141
+ <tr>
142
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 16px;">
143
+ <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 0px;">A total of <strong style="font-weight: 600;">${formatNumber(result.imported)}</strong> ${iff(result.imported === 1, 'person', 'people')} were successfully added or updated in your list of members, and now have access to your site.</p>
144
+ </td>
145
+ </tr>`, ``)}
146
+ ${iff(result.errors.length > 0, `
147
+ <tr>
148
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 16px;">
149
+ <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 0px;">
150
+ ${iff(result.imported === 0, `No members were added.`, `<strong style="font-weight: 600;">${formatNumber(result.errors.length)}</strong> ${iff(result.errors.length === 1, `member was`, `members were`)} skipped due to errors.`)} There's a validated CSV file attached to this email with the list of errors so that you can fix them and re-upload the CSV to complete the import.</p>
151
+ </td>
152
+ </tr>`, '')}
153
+ <tr>
154
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 12px; padding-top: 16px;">
155
+ <a href="${membersUrl.href}" target="_blank" style="display: inline-block; color: #ffffff; background-color: #15212A; border: solid 1px #15212A; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: #15212A;">${iff(result.imported > 0, `View members`, `Try again`)}</a>
156
+ </td>
157
+ </tr>
158
+ </table>
159
+ </td>
160
+ </tr>
161
+ <tr>
162
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; vertical-align: top; padding-top: 80px; padding-bottom: 10px;">
163
+ <div class="footer">
164
+ <p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; color: #738A94; font-weight: normal; margin: 0; line-height: 18px; margin-bottom: 0px; font-size: 11px;">This email was sent from <a href="${siteUrl.href}" style="color: #738A94;">${siteUrl.host}</a> to <a href="mailto:${emailRecipient}" style="color: #738A94;">${emailRecipient}</a></p>
165
+ </div>
166
+ </td>
167
+ </tr>
168
+
169
+ <!-- END MAIN CONTENT AREA -->
170
+ </table>
171
+
172
+
173
+ <!-- END CENTERED CONTAINER -->
174
+ </div>
175
+ </td>
176
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">&nbsp;</td>
177
+ </tr>
178
+ </table>
179
+ </body>
180
+ </html>
181
+ `;
182
+
@@ -0,0 +1,30 @@
1
+ const MembersCSVImporter = require('./MembersCSVImporter');
2
+ const MembersCSVImporterStripeUtils = require('./MembersCSVImporterStripeUtils');
3
+
4
+ /**
5
+ * @typedef {import('./MembersCSVImporter').MembersCSVImporterOptions} MembersCSVImporterOptions
6
+ */
7
+
8
+ /**
9
+ * @typedef {Object} MakeImporterDeps
10
+ * @property {Object} stripeAPIService - Instance of StripeAPIService
11
+ * @property {Object} productRepository - Instance of ProductRepository
12
+ */
13
+
14
+ /**
15
+ * Make an instance of MembersCSVImporter
16
+ *
17
+ * @param {MakeImporterDeps & MembersCSVImporterOptions} deps
18
+ * @returns {MembersCSVImporter}
19
+ */
20
+ module.exports = function makeImporter(deps) {
21
+ const stripeUtils = new MembersCSVImporterStripeUtils({
22
+ stripeAPIService: deps.stripeAPIService,
23
+ productRepository: deps.productRepository
24
+ });
25
+
26
+ return new MembersCSVImporter({
27
+ ...deps,
28
+ stripeUtils
29
+ });
30
+ };
@@ -0,0 +1,333 @@
1
+ const {parse: parseUrl} = require('url');
2
+ const createCookies = require('cookies');
3
+ const debug = require('@tryghost/debug')('members-ssr');
4
+
5
+ const {
6
+ BadRequestError,
7
+ IncorrectUsageError
8
+ } = require('@tryghost/errors');
9
+
10
+ /**
11
+ * @typedef {import('http').IncomingMessage} Request
12
+ * @typedef {import('http').ServerResponse} Response
13
+ * @typedef {import('cookies').ICookies} Cookies
14
+ * @typedef {import('cookies').Option} CookiesOptions
15
+ * @typedef {import('cookies').SetOption} SetCookieOptions
16
+ * @typedef {string} JWT
17
+ */
18
+
19
+ /**
20
+ * @typedef {object} Member
21
+ * @prop {string} id
22
+ * @prop {string} transient_id
23
+ * @prop {string} email
24
+ */
25
+
26
+ const SIX_MONTHS_MS = 1000 * 60 * 60 * 24 * 184;
27
+
28
+ class MembersSSR {
29
+ /**
30
+ * @typedef {object} MembersSSROptions
31
+ *
32
+ * @prop {string|string[]} cookieKeys - A secret or array of secrets used to sign cookies
33
+ * @prop {() => object} getMembersApi - A function which returns an instance of members-api
34
+ * @prop {boolean} [cookieSecure = true] - Whether the cookie should have Secure flag
35
+ * @prop {string} [cookieName] - The name of the members-ssr cookie
36
+ * @prop {number} [cookieMaxAge] - The max age in ms of the members-ssr cookie
37
+ * @prop {string} [cookiePath] - The Path flag for the cookie
38
+ * @prop {boolean} [dangerousRemovalOfSignedCookie] - Flag for removing signed cookie
39
+ */
40
+
41
+ /**
42
+ * Create an instance of MembersSSR
43
+ *
44
+ * @param {MembersSSROptions} options - The options for the members ssr class
45
+ */
46
+ constructor(options) {
47
+ const {
48
+ cookieSecure = true,
49
+ cookieName = 'members-ssr',
50
+ cookieMaxAge = SIX_MONTHS_MS,
51
+ cookiePath = '/',
52
+ cookieKeys,
53
+ getMembersApi,
54
+ dangerousRemovalOfSignedCookie
55
+ } = options;
56
+
57
+ if (!getMembersApi) {
58
+ throw new IncorrectUsageError({message: 'Missing option getMembersApi'});
59
+ }
60
+
61
+ this._getMembersApi = getMembersApi;
62
+
63
+ if (!cookieKeys) {
64
+ throw new IncorrectUsageError({message: 'Missing option cookieKeys'});
65
+ }
66
+
67
+ this.sessionCookieName = cookieName;
68
+
69
+ /**
70
+ * @type SetCookieOptions
71
+ */
72
+ this.sessionCookieOptions = {
73
+ signed: true,
74
+ httpOnly: true,
75
+ sameSite: 'lax',
76
+ maxAge: cookieMaxAge,
77
+ path: cookiePath
78
+ };
79
+
80
+ if (dangerousRemovalOfSignedCookie === true) {
81
+ this.sessionCookieOptions.signed = false;
82
+ }
83
+
84
+ /**
85
+ * @type CookiesOptions
86
+ */
87
+ this.cookiesOptions = {
88
+ keys: Array.isArray(cookieKeys) ? cookieKeys : [cookieKeys],
89
+ secure: cookieSecure
90
+ };
91
+ }
92
+
93
+ /**
94
+ * @method _getCookies
95
+ *
96
+ * @param {Request} req
97
+ * @param {Response} res
98
+ *
99
+ * @returns {Cookies} An instance of the cookies object for current request/response
100
+ */
101
+ _getCookies(req, res) {
102
+ return createCookies(req, res, this.cookiesOptions);
103
+ }
104
+
105
+ /**
106
+ * @method _removeSessionCookie
107
+ *
108
+ * @param {Request} req
109
+ * @param {Response} res
110
+ */
111
+ _removeSessionCookie(req, res) {
112
+ const cookies = this._getCookies(req, res);
113
+ cookies.set(this.sessionCookieName, null, this.sessionCookieOptions);
114
+ // If members caching cookies are set, remove them
115
+ if (cookies.get('ghost-access') || cookies.get('ghost-access-hmac')) {
116
+ cookies.set('ghost-access', null, {...this.sessionCookieOptions, signed: false});
117
+ cookies.set('ghost-access-hmac', null, {...this.sessionCookieOptions, signed: false});
118
+ }
119
+ }
120
+
121
+ /**
122
+ * @method _setSessionCookie
123
+ *
124
+ * @param {Request} req
125
+ * @param {Response} res
126
+ * @param {string} value
127
+ */
128
+ _setSessionCookie(req, res, value) {
129
+ if (!value) {
130
+ return this._removeSessionCookie(req, res);
131
+ }
132
+ const cookies = this._getCookies(req, res);
133
+ cookies.set(this.sessionCookieName, value, this.sessionCookieOptions);
134
+ }
135
+
136
+ /**
137
+ * @method _getSessionCookies
138
+ *
139
+ * @param {Request} req
140
+ * @param {Response} res
141
+ *
142
+ * @returns {string} The cookie value
143
+ */
144
+ _getSessionCookies(req, res) {
145
+ const cookies = this._getCookies(req, res);
146
+ const value = cookies.get(this.sessionCookieName, {signed: true});
147
+ if (!value) {
148
+ throw new BadRequestError({
149
+ message: `Cookie ${this.sessionCookieName} not found`
150
+ });
151
+ }
152
+ return value;
153
+ }
154
+
155
+ /**
156
+ * @method _getMemberDataFromToken
157
+ *
158
+ * @param {JWT} token
159
+ *
160
+ * @returns {Promise<Member>} member
161
+ */
162
+ async _getMemberDataFromToken(token) {
163
+ const api = await this._getMembersApi();
164
+ return api.getMemberDataFromMagicLinkToken(token);
165
+ }
166
+
167
+ /**
168
+ * @method _getMemberIdentityData
169
+ *
170
+ * @param {string} email
171
+ *
172
+ * @returns {Promise<Member>} member
173
+ */
174
+ async _getMemberIdentityData(email) {
175
+ const api = await this._getMembersApi();
176
+ return api.getMemberIdentityData(email);
177
+ }
178
+
179
+ /**
180
+ * @method _getMemberIdentityData
181
+ *
182
+ * @param {string} transientId
183
+ *
184
+ * @returns {Promise<Member>} member
185
+ */
186
+ async _getMemberIdentityDataFromTransientId(transientId) {
187
+ const api = await this._getMembersApi();
188
+ return api.getMemberIdentityDataFromTransientId(transientId);
189
+ }
190
+
191
+ /**
192
+ * @method _getMemberIdentityToken
193
+ *
194
+ * @param {string} email
195
+ *
196
+ * @returns {Promise<JWT>} member
197
+ */
198
+ async _getMemberIdentityToken(transientId) {
199
+ const api = await this._getMembersApi();
200
+ return api.getMemberIdentityToken(transientId);
201
+ }
202
+
203
+ /**
204
+ * @method _setMemberGeolocationFromIp
205
+ * @param {string} email
206
+ * @param {string} ip
207
+ *
208
+ * @returns {Promise<Member>} member
209
+ */
210
+ async _setMemberGeolocationFromIp(email, ip) {
211
+ const api = await this._getMembersApi();
212
+ return api.setMemberGeolocationFromIp(email, ip);
213
+ }
214
+
215
+ /**
216
+ * @method exchangeTokenForSession
217
+ * @param {Request} req
218
+ * @param {Response} res
219
+ *
220
+ * @returns {Promise<Member>} The member the session was created for
221
+ */
222
+ async exchangeTokenForSession(req, res) {
223
+ if (!req.url) {
224
+ return Promise.reject(new BadRequestError({
225
+ message: 'Expected token param containing JWT'
226
+ }));
227
+ }
228
+
229
+ const {query} = parseUrl(req.url, true);
230
+ if (!query || !query.token) {
231
+ return Promise.reject(new BadRequestError({
232
+ message: 'Expected token param containing JWT'
233
+ }));
234
+ }
235
+
236
+ const token = Array.isArray(query.token) ? query.token[0] : query.token;
237
+ const member = await this._getMemberDataFromToken(token);
238
+
239
+ if (!member) {
240
+ // The member doesn't exist any longer (could be a sign in token for a member that was deleted)
241
+ return Promise.reject(new BadRequestError({
242
+ message: 'Invalid token'
243
+ }));
244
+ }
245
+
246
+ // perform and store geoip lookup for members when they log in
247
+ if (!member.geolocation) {
248
+ try {
249
+ await this._setMemberGeolocationFromIp(member.email, req.ip);
250
+ } catch (err) {
251
+ // no-op, we don't want to stop anything working due to
252
+ // geolocation lookup failing
253
+ debug(`Geolocation lookup failed: ${err.message}`);
254
+ }
255
+ }
256
+
257
+ this._setSessionCookie(req, res, member.transient_id);
258
+
259
+ return member;
260
+ }
261
+
262
+ async _cycleTransientId(memberId) {
263
+ const api = await this._getMembersApi();
264
+ return api.cycleTransientId(memberId);
265
+ }
266
+
267
+ /**
268
+ * @method deleteSession
269
+ * @param {Request} req
270
+ * @param {Response} res
271
+ *
272
+ * @returns {Promise<void>}
273
+ */
274
+ async deleteSession(req, res) {
275
+ if (req.body && typeof req.body === 'object' && req.body.all) {
276
+ // Update transient_id to invalidate all sessions
277
+ const member = await this.getMemberDataFromSession(req, res);
278
+ if (member) {
279
+ await this._cycleTransientId(member.id);
280
+ }
281
+ }
282
+ this._removeSessionCookie(req, res);
283
+ }
284
+
285
+ /**
286
+ * @method getMemberDataFromSession
287
+ *
288
+ * @param {Request} req
289
+ * @param {Response} res
290
+ *
291
+ * @returns {Promise<Member>}
292
+ */
293
+ async getMemberDataFromSession(req, res) {
294
+ const transientId = this._getSessionCookies(req, res);
295
+ const member = await this._getMemberIdentityDataFromTransientId(transientId);
296
+ return member;
297
+ }
298
+
299
+ /**
300
+ * @method getIdentityTokenForMemberFromSession
301
+ *
302
+ * @param {Request} req
303
+ * @param {Response} res
304
+ *
305
+ * @returns {Promise<JWT>} identity token
306
+ */
307
+ async getIdentityTokenForMemberFromSession(req, res) {
308
+ const transientId = this._getSessionCookies(req, res);
309
+ const token = await this._getMemberIdentityToken(transientId);
310
+ if (!token) {
311
+ await this.deleteSession(req, res);
312
+ throw new BadRequestError({
313
+ message: 'Invalid session, could not get identity token'
314
+ });
315
+ }
316
+ return token;
317
+ }
318
+ }
319
+
320
+ /**
321
+ * Factory function for creating instance of MembersSSR
322
+ *
323
+ * @param {MembersSSROptions} options
324
+ * @returns {MembersSSR}
325
+ */
326
+ module.exports = function create(options) {
327
+ if (!options) {
328
+ throw new IncorrectUsageError({
329
+ message: 'Must pass options'
330
+ });
331
+ }
332
+ return new MembersSSR(options);
333
+ };
@@ -1,10 +1,10 @@
1
1
  const _ = require('lodash');
2
2
  const errors = require('@tryghost/errors');
3
3
  const tpl = require('@tryghost/tpl');
4
- const MembersSSR = require('@tryghost/members-ssr');
4
+ const MembersSSR = require('./members-ssr');
5
5
  const db = require('../../data/db');
6
6
  const MembersConfigProvider = require('./MembersConfigProvider');
7
- const makeMembersCSVImporter = require('@tryghost/members-importer');
7
+ const makeMembersCSVImporter = require('./importer');
8
8
  const MembersStats = require('./stats/MembersStats');
9
9
  const memberJobs = require('./jobs');
10
10
  const logging = require('@tryghost/logging');
@@ -1,7 +1,7 @@
1
1
  const {MemberPageViewEvent, MemberCommentEvent, MemberLinkClickEvent} = require('@tryghost/member-events');
2
2
  const moment = require('moment-timezone');
3
3
  const {IncorrectUsageError} = require('@tryghost/errors');
4
- const {EmailOpenedEvent} = require('@tryghost/email-events');
4
+ const {EmailOpenedEvent} = require('@tryghost/email-service');
5
5
  const logging = require('@tryghost/logging');
6
6
  const LastSeenAtCache = require('./LastSeenAtCache');
7
7
 
@@ -1,6 +1,6 @@
1
- const DynamicRedirectManager = require('@tryghost/express-dynamic-redirects');
2
1
  const OffersModule = require('@tryghost/members-offers');
3
2
 
3
+ const DynamicRedirectManager = require('../lib/DynamicRedirectManager');
4
4
  const config = require('../../../shared/config');
5
5
  const urlUtils = require('../../../shared/url-utils');
6
6
  const models = require('../../models');
@@ -20,6 +20,19 @@ class PostStats {
20
20
  return result?.[0]?.published_at ? new Date(result?.[0]?.published_at) : null;
21
21
  }
22
22
 
23
+ /**
24
+ * Returns the first published post date
25
+ */
26
+ async getFirstPublishedPostDate() {
27
+ const result = await this.#db.knex.select('published_at')
28
+ .from('posts')
29
+ .whereIn('status', ['sent', 'published'])
30
+ .orderBy('published_at', 'asc')
31
+ .limit(1);
32
+
33
+ return result?.[0]?.published_at ? new Date(result?.[0]?.published_at) : null;
34
+ }
35
+
23
36
  /**
24
37
  * Fetches count of all published posts
25
38
  */
@@ -4,37 +4,37 @@ const logging = require('@tryghost/logging');
4
4
 
5
5
  class RecommendationServiceWrapper {
6
6
  /**
7
- * @type {import('@tryghost/recommendations').RecommendationRepository}
7
+ * @type {import('./service').RecommendationRepository}
8
8
  */
9
9
  repository;
10
10
 
11
11
  /**
12
- * @type {import('@tryghost/recommendations').BookshelfClickEventRepository}
12
+ * @type {import('./service').BookshelfClickEventRepository}
13
13
  */
14
14
  clickEventRepository;
15
15
 
16
16
  /**
17
- * @type {import('@tryghost/recommendations').BookshelfSubscribeEventRepository}
17
+ * @type {import('./service').BookshelfSubscribeEventRepository}
18
18
  */
19
19
  subscribeEventRepository;
20
20
 
21
21
  /**
22
- * @type {import('@tryghost/recommendations').RecommendationController}
22
+ * @type {import('./service').RecommendationController}
23
23
  */
24
24
  controller;
25
25
 
26
26
  /**
27
- * @type {import('@tryghost/recommendations').RecommendationService}
27
+ * @type {import('./service').RecommendationService}
28
28
  */
29
29
  service;
30
30
 
31
31
  /**
32
- * @type {import('@tryghost/recommendations').IncomingRecommendationController}
32
+ * @type {import('./service').IncomingRecommendationController}
33
33
  */
34
34
  incomingRecommendationController;
35
35
 
36
36
  /**
37
- * @type {import('@tryghost/recommendations').IncomingRecommendationService}
37
+ * @type {import('./service').IncomingRecommendationService}
38
38
  */
39
39
  incomingRecommendationService;
40
40
 
@@ -65,7 +65,7 @@ class RecommendationServiceWrapper {
65
65
  IncomingRecommendationService,
66
66
  IncomingRecommendationEmailRenderer,
67
67
  RecommendationMetadataService
68
- } = require('@tryghost/recommendations');
68
+ } = require('./service');
69
69
 
70
70
  const mentions = require('../mentions');
71
71