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.
- package/components/{tryghost-api-framework-5.115.0.tgz → tryghost-api-framework-5.116.0.tgz} +0 -0
- package/components/tryghost-constants-5.116.0.tgz +0 -0
- package/components/tryghost-custom-fonts-5.116.0.tgz +0 -0
- package/components/{tryghost-custom-theme-settings-service-5.115.0.tgz → tryghost-custom-theme-settings-service-5.116.0.tgz} +0 -0
- package/components/tryghost-domain-events-5.116.0.tgz +0 -0
- package/components/{tryghost-donations-5.115.0.tgz → tryghost-donations-5.116.0.tgz} +0 -0
- package/components/tryghost-email-addresses-5.116.0.tgz +0 -0
- package/components/tryghost-email-service-5.116.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.116.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.116.0.tgz +0 -0
- package/components/tryghost-i18n-5.116.0.tgz +0 -0
- package/components/tryghost-job-manager-5.116.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.116.0.tgz +0 -0
- package/components/tryghost-magic-link-5.116.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.116.0.tgz +0 -0
- package/components/tryghost-member-events-5.116.0.tgz +0 -0
- package/components/tryghost-members-api-5.116.0.tgz +0 -0
- package/components/tryghost-members-csv-5.116.0.tgz +0 -0
- package/components/{tryghost-members-offers-5.115.0.tgz → tryghost-members-offers-5.116.0.tgz} +0 -0
- package/components/{tryghost-milestones-5.115.0.tgz → tryghost-milestones-5.116.0.tgz} +0 -0
- package/components/{tryghost-mw-error-handler-5.115.0.tgz → tryghost-mw-error-handler-5.116.0.tgz} +0 -0
- package/components/tryghost-mw-vhost-5.116.0.tgz +0 -0
- package/components/{tryghost-post-events-5.115.0.tgz → tryghost-post-events-5.116.0.tgz} +0 -0
- package/components/{tryghost-post-revisions-5.115.0.tgz → tryghost-post-revisions-5.116.0.tgz} +0 -0
- package/components/tryghost-posts-service-5.116.0.tgz +0 -0
- package/components/{tryghost-prometheus-metrics-5.115.0.tgz → tryghost-prometheus-metrics-5.116.0.tgz} +0 -0
- package/components/tryghost-security-5.116.0.tgz +0 -0
- package/components/{tryghost-tiers-5.115.0.tgz → tryghost-tiers-5.116.0.tgz} +0 -0
- package/components/tryghost-webmentions-5.116.0.tgz +0 -0
- package/content/themes/casper/LICENSE +1 -1
- package/content/themes/casper/README.md +1 -1
- package/content/themes/source/LICENSE +1 -1
- package/content/themes/source/README.md +1 -1
- package/content/themes/source/assets/built/screen.css +1 -1
- package/content/themes/source/assets/built/screen.css.map +1 -1
- package/content/themes/source/assets/css/screen.css +11 -6
- package/content/themes/source/partials/feature-image.hbs +2 -2
- package/core/boot.js +3 -43
- package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +30494 -29403
- package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +1 -1
- package/core/built/admin/assets/admin-x-demo/{index-0040480a.mjs → index-a9601514.mjs} +5 -4
- package/core/built/admin/assets/admin-x-demo/{modals-fb35c86c.mjs → modals-c1789d04.mjs} +67 -65
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-806ef39c.mjs → CodeEditorView-e9c9deb8.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-376f847c.mjs → index-84580c3a.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-8fa19303.mjs → index-f744cab7.mjs} +3147 -3123
- package/core/built/admin/assets/admin-x-settings/{modals-36775d71.mjs → modals-d9ca60c5.mjs} +1198 -1192
- package/core/built/admin/assets/chunk.524.8371443ef8f60db429d0.js +35 -0
- package/core/built/admin/assets/chunk.582.f90151775f2e53dd21d9.js +37 -0
- package/core/built/admin/assets/{chunk.874.461cb3cf5b6b36915f8c.js → chunk.713.e9027c0cc3c56110f5da.js} +125 -98
- package/core/built/admin/assets/{ghost-938b3d9c29e3564a53a22f8c8f82d351.js → ghost-03b64c086f3c60cabc85fe7a7e2b640a.js} +272 -251
- package/core/built/admin/assets/ghost-ba58e9822f7384461e926c7e23f04a75.css +1 -0
- package/core/built/admin/assets/ghost-dark-f1f29683b14ffa11615b3bba8b6ab92c.css +1 -0
- package/core/built/admin/assets/koenig-lexical/index.css +1 -1
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +20563 -20891
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +139 -139
- package/core/built/admin/assets/posts/posts.js +5732 -5667
- package/core/built/admin/assets/stats/stats.js +75373 -0
- package/core/built/admin/assets/{vendor-68a4aa424a179a90f5bbc2b750def576.js → vendor-72026232b36d97babc6320917c16c321.js} +36 -34
- package/core/built/admin/index.html +6 -6
- package/core/cli/generate-data.js +1 -1
- package/core/frontend/helpers/ghost_head.js +8 -1
- package/core/frontend/public/ghost-stats.js +55 -2
- package/core/frontend/services/assets-minification/AdminAuthAssets.js +2 -1
- package/core/frontend/services/assets-minification/CardAssets.js +1 -1
- package/core/frontend/services/assets-minification/CommentCountsAssets.js +1 -1
- package/core/frontend/services/assets-minification/MemberAttributionAssets.js +1 -1
- package/core/frontend/services/assets-minification/Minifier.js +191 -0
- package/core/frontend/services/routing/controllers/previews.js +2 -1
- package/core/frontend/src/cards/css/cta.css +1 -1
- package/core/server/adapters/cache/Redis.js +1 -1
- package/core/server/adapters/lib/redis/AdapterCacheRedis.js +287 -0
- package/core/server/adapters/lib/redis/redis-store-factory.js +22 -0
- package/core/server/api/endpoints/posts.js +9 -3
- package/core/server/api/endpoints/previews.js +35 -1
- package/core/server/api/endpoints/slugs.js +6 -2
- package/core/server/api/endpoints/utils/serializers/output/utils/post-gating.js +6 -9
- package/core/server/api/endpoints/utils/validators/input/settings.js +1 -1
- package/core/server/data/db/connection.js +2 -0
- package/core/server/data/db/index.js +1 -0
- package/core/server/data/importer/handlers/ImporterContentFileHandler.js +90 -0
- package/core/server/data/importer/import-manager.js +3 -3
- package/core/server/data/importer/importers/importer-revue.js +128 -0
- package/core/server/data/importer/importers/json-to-html.js +107 -0
- package/core/server/data/migrations/utils/tables.js +2 -4
- package/core/server/data/seeders/DataGenerator.js +288 -0
- package/core/server/data/seeders/importers/BenefitsImporter.js +28 -0
- package/core/server/data/seeders/importers/CommentsImporter.js +73 -0
- package/core/server/data/seeders/importers/EmailBatchesImporter.js +38 -0
- package/core/server/data/seeders/importers/EmailRecipientFailuresImporter.js +67 -0
- package/core/server/data/seeders/importers/EmailRecipientsImporter.js +212 -0
- package/core/server/data/seeders/importers/EmailsImporter.js +99 -0
- package/core/server/data/seeders/importers/LabelsImporter.js +41 -0
- package/core/server/data/seeders/importers/MembersClickEventsImporter.js +69 -0
- package/core/server/data/seeders/importers/MembersCreatedEventsImporter.js +103 -0
- package/core/server/data/seeders/importers/MembersFeedbackImporter.js +45 -0
- package/core/server/data/seeders/importers/MembersImporter.js +111 -0
- package/core/server/data/seeders/importers/MembersLabelsImporter.js +39 -0
- package/core/server/data/seeders/importers/MembersLoginEventsImporter.js +69 -0
- package/core/server/data/seeders/importers/MembersNewslettersImporter.js +38 -0
- package/core/server/data/seeders/importers/MembersPaidSubscriptionEventsImporter.js +99 -0
- package/core/server/data/seeders/importers/MembersProductsImporter.js +42 -0
- package/core/server/data/seeders/importers/MembersStatusEventsImporter.js +58 -0
- package/core/server/data/seeders/importers/MembersStripeCustomersImporter.js +60 -0
- package/core/server/data/seeders/importers/MembersStripeCustomersSubscriptionsImporter.js +259 -0
- package/core/server/data/seeders/importers/MembersSubscribeEventsImporter.js +69 -0
- package/core/server/data/seeders/importers/MembersSubscriptionCreatedEventsImporter.js +95 -0
- package/core/server/data/seeders/importers/NewslettersImporter.js +40 -0
- package/core/server/data/seeders/importers/OffersImporter.js +70 -0
- package/core/server/data/seeders/importers/PostsAuthorsImporter.js +32 -0
- package/core/server/data/seeders/importers/PostsImporter.js +102 -0
- package/core/server/data/seeders/importers/PostsProductsImporter.js +35 -0
- package/core/server/data/seeders/importers/PostsTagsImporter.js +46 -0
- package/core/server/data/seeders/importers/ProductsBenefitsImporter.js +54 -0
- package/core/server/data/seeders/importers/ProductsImporter.js +90 -0
- package/core/server/data/seeders/importers/RecommendationClickEventsImporter.js +32 -0
- package/core/server/data/seeders/importers/RecommendationSubscribeEventsImporter.js +32 -0
- package/core/server/data/seeders/importers/RecommendationsImporter.js +34 -0
- package/core/server/data/seeders/importers/RedirectsImporter.js +49 -0
- package/core/server/data/seeders/importers/RolesUsersImporter.js +42 -0
- package/core/server/data/seeders/importers/StripePricesImporter.js +69 -0
- package/core/server/data/seeders/importers/StripeProductsImporter.js +34 -0
- package/core/server/data/seeders/importers/TableImporter.js +187 -0
- package/core/server/data/seeders/importers/TagsImporter.js +41 -0
- package/core/server/data/seeders/importers/UsersImporter.js +31 -0
- package/core/server/data/seeders/importers/WebMentionsImporter.js +42 -0
- package/core/server/data/seeders/importers/index.js +41 -0
- package/core/server/data/seeders/utils/JsonImporter.js +39 -0
- package/core/server/data/seeders/utils/blog-info.js +3 -0
- package/core/server/data/seeders/utils/database-date.js +7 -0
- package/core/server/data/seeders/utils/event-generator.js +48 -0
- package/core/server/data/seeders/utils/random.js +13 -0
- package/core/server/data/seeders/utils/topological-sort.js +33 -0
- package/core/server/lib/bootstrap-socket.js +87 -0
- package/core/server/lib/package-json/index.js +1 -0
- package/core/server/lib/package-json/package-json.js +160 -0
- package/core/server/lib/package-json/parse.js +57 -0
- package/core/server/models/base/plugins/actions.js +44 -31
- package/core/server/models/base/plugins/generate-slug.js +6 -0
- package/core/server/notify.js +1 -1
- package/core/server/services/activitypub/ActivityPubService.ts +1 -1
- package/core/server/services/adapter-manager/AdapterManager.js +161 -0
- package/core/server/services/adapter-manager/index.js +1 -1
- package/core/server/services/announcement-bar-service/AnnouncementBarSettings.js +54 -0
- package/core/server/services/announcement-bar-service/AnnouncementVisibilityValues.js +11 -0
- package/core/server/services/announcement-bar-service/index.js +1 -1
- package/core/server/services/api-version-compatibility/APIVersionCompatibilityService.js +99 -0
- package/core/server/services/api-version-compatibility/VersionNotificationsDataService.js +80 -0
- package/core/server/services/api-version-compatibility/extract-api-key.js +57 -0
- package/core/server/services/api-version-compatibility/index.js +2 -2
- package/core/server/services/api-version-compatibility/mw-api-version-mismatch.js +31 -0
- package/core/server/services/audience-feedback/AudienceFeedbackController.js +85 -0
- package/core/server/services/audience-feedback/AudienceFeedbackService.js +34 -0
- package/core/server/services/audience-feedback/Feedback.js +35 -0
- package/core/server/services/audience-feedback/index.js +4 -2
- package/core/server/services/auth/session/emails/signin.js +168 -0
- package/core/server/services/auth/session/index.js +2 -2
- package/core/server/services/auth/session/session-from-token.js +69 -0
- package/core/server/services/auth/session/session-service.js +374 -0
- package/core/server/services/custom-redirects/index.js +1 -1
- package/core/server/services/email-analytics/EmailAnalyticsProviderMailgun.js +62 -0
- package/core/server/services/email-analytics/EmailAnalyticsService.js +552 -0
- package/core/server/services/email-analytics/EmailAnalyticsServiceWrapper.js +3 -3
- package/core/server/services/email-analytics/EventProcessingResult.js +66 -0
- package/core/server/services/email-service/EmailServiceWrapper.js +4 -4
- package/core/server/services/email-suppression-list/MailgunEmailSuppressionList.js +1 -1
- package/core/server/services/email-suppression-list/service.js +1 -1
- package/core/server/services/explore-ping/ExplorePingService.js +106 -0
- package/core/server/services/explore-ping/index.js +31 -0
- package/core/server/services/identity-tokens/IdentityTokenService.js +30 -0
- package/core/server/services/identity-tokens/IdentityTokenService.ts +28 -0
- package/core/server/services/identity-tokens/IdentityTokenServiceWrapper.js +1 -1
- package/core/server/services/invitations/accept.js +5 -2
- package/core/server/services/lib/DynamicRedirectManager.js +156 -0
- package/core/server/services/lib/EmailContentGenerator.js +54 -0
- package/core/server/services/lib/InMemoryRepository.js +62 -0
- package/core/server/services/lib/InMemoryRepository.ts +80 -0
- package/core/server/services/lib/MailgunClient.js +364 -0
- package/core/server/services/link-redirection/LinkRedirect.js +26 -0
- package/core/server/services/link-redirection/LinkRedirectRepository.js +7 -7
- package/core/server/services/link-redirection/LinkRedirectsService.js +123 -0
- package/core/server/services/link-redirection/README.md +151 -0
- package/core/server/services/link-redirection/RedirectEvent.js +24 -0
- package/core/server/services/link-redirection/index.js +1 -1
- package/core/server/services/link-tracking/LinkClickTrackingService.js +1 -1
- package/core/server/services/mail/index.js +1 -1
- package/core/server/services/mail-events/BookshelfMailEventRepository.js +2 -2
- package/core/server/services/mail-events/InMemoryMailEventRepository.js +10 -0
- package/core/server/services/mail-events/InMemoryMailEventRepository.ts +8 -0
- package/core/server/services/mail-events/MailEvent.js +20 -0
- package/core/server/services/mail-events/MailEvent.ts +10 -0
- package/core/server/services/mail-events/MailEventRepository.js +2 -0
- package/core/server/services/mail-events/MailEventRepository.ts +5 -0
- package/core/server/services/mail-events/MailEventService.js +124 -0
- package/core/server/services/mail-events/MailEventService.ts +169 -0
- package/core/server/services/mail-events/index.js +1 -1
- package/core/server/services/mail-events/libraries.d.ts +2 -0
- package/core/server/services/members/CaptchaService.js +80 -0
- package/core/server/services/members/api.js +1 -1
- package/core/server/services/members/importer/MembersCSVImporter.js +464 -0
- package/core/server/services/members/importer/MembersCSVImporterStripeUtils.js +194 -0
- package/core/server/services/members/importer/email-template.js +182 -0
- package/core/server/services/members/importer/index.js +30 -0
- package/core/server/services/members/members-ssr.js +333 -0
- package/core/server/services/members/service.js +2 -2
- package/core/server/services/members-events/LastSeenAtUpdater.js +1 -1
- package/core/server/services/offers/service.js +1 -1
- package/core/server/services/posts/stats/PostStats.js +13 -0
- package/core/server/services/recommendations/RecommendationServiceWrapper.js +8 -8
- package/core/server/services/recommendations/service/BookshelfClickEventRepository.js +48 -0
- package/core/server/services/recommendations/service/BookshelfClickEventRepository.ts +49 -0
- package/core/server/services/recommendations/service/BookshelfRecommendationRepository.js +98 -0
- package/core/server/services/recommendations/service/BookshelfRecommendationRepository.ts +117 -0
- package/core/server/services/recommendations/service/BookshelfRepository.js +134 -0
- package/core/server/services/recommendations/service/BookshelfRepository.ts +196 -0
- package/core/server/services/recommendations/service/BookshelfSubscribeEventRepository.js +48 -0
- package/core/server/services/recommendations/service/BookshelfSubscribeEventRepository.ts +49 -0
- package/core/server/services/recommendations/service/ClickEvent.js +33 -0
- package/core/server/services/recommendations/service/ClickEvent.ts +32 -0
- package/core/server/services/recommendations/service/InMemoryRecommendationRepository.js +19 -0
- package/core/server/services/recommendations/service/InMemoryRecommendationRepository.ts +20 -0
- package/core/server/services/recommendations/service/IncomingRecommendationController.js +34 -0
- package/core/server/services/recommendations/service/IncomingRecommendationController.ts +51 -0
- package/core/server/services/recommendations/service/IncomingRecommendationEmailRenderer.js +25 -0
- package/core/server/services/recommendations/service/IncomingRecommendationEmailRenderer.ts +37 -0
- package/core/server/services/recommendations/service/IncomingRecommendationService.js +93 -0
- package/core/server/services/recommendations/service/IncomingRecommendationService.ts +160 -0
- package/core/server/services/recommendations/service/Recommendation.js +140 -0
- package/core/server/services/recommendations/service/Recommendation.ts +201 -0
- package/core/server/services/recommendations/service/RecommendationController.js +208 -0
- package/core/server/services/recommendations/service/RecommendationController.ts +258 -0
- package/core/server/services/recommendations/service/RecommendationMetadataService.js +86 -0
- package/core/server/services/recommendations/service/RecommendationMetadataService.ts +128 -0
- package/core/server/services/recommendations/service/RecommendationRepository.js +2 -0
- package/core/server/services/recommendations/service/RecommendationRepository.ts +13 -0
- package/core/server/services/recommendations/service/RecommendationService.js +228 -0
- package/core/server/services/recommendations/service/RecommendationService.ts +281 -0
- package/core/server/services/recommendations/service/SubscribeEvent.js +33 -0
- package/core/server/services/recommendations/service/SubscribeEvent.ts +32 -0
- package/core/server/services/recommendations/service/UnsafeData.js +183 -0
- package/core/server/services/recommendations/service/UnsafeData.ts +217 -0
- package/core/server/services/recommendations/service/WellknownService.js +36 -0
- package/core/server/services/recommendations/service/WellknownService.ts +47 -0
- package/core/server/services/recommendations/service/index.js +31 -0
- package/core/server/services/recommendations/service/index.ts +15 -0
- package/core/server/services/recommendations/service/libraries.d.ts +5 -0
- package/core/server/services/route-settings/SettingsPathManager.js +47 -0
- package/core/server/services/route-settings/index.js +1 -1
- package/core/server/services/slack-notifications/SlackNotifications.js +211 -0
- package/core/server/services/slack-notifications/SlackNotificationsService.js +90 -0
- package/core/server/services/slack-notifications/service.js +4 -6
- package/core/server/services/stripe/README.md +63 -0
- package/core/server/services/stripe/StripeAPI.js +931 -0
- package/core/server/services/stripe/StripeMigrations.js +613 -0
- package/core/server/services/stripe/StripeService.js +175 -0
- package/core/server/services/stripe/WebhookController.js +100 -0
- package/core/server/services/stripe/WebhookManager.js +175 -0
- package/core/server/services/stripe/events/StripeLiveDisabledEvent.js +23 -0
- package/core/server/services/stripe/events/StripeLiveEnabledEvent.js +23 -0
- package/core/server/services/stripe/events/index.js +4 -0
- package/core/server/services/stripe/service.js +1 -1
- package/core/server/services/stripe/services/webhook/CheckoutSessionEventService.js +255 -0
- package/core/server/services/stripe/services/webhook/InvoiceEventService.js +70 -0
- package/core/server/services/stripe/services/webhook/SubscriptionEventService.js +54 -0
- package/core/server/services/themes/loader.js +1 -1
- package/core/server/services/themes/to-json.js +1 -1
- package/core/server/web/api/endpoints/admin/app.js +1 -21
- package/core/server/web/api/endpoints/admin/routes.js +1 -0
- package/core/server/web/api/middleware/version-match.js +41 -0
- package/core/server/web/shared/middleware/cache-control.js +51 -0
- package/core/server/web/shared/middleware/index.js +1 -1
- package/core/server/web/well-known.js +1 -1
- package/core/shared/labs.js +5 -3
- package/core/shared/settings-cache/CacheManager.js +64 -6
- package/package.json +98 -146
- package/tsconfig.tsbuildinfo +1 -1
- package/yarn.lock +1478 -1634
- package/components/tryghost-adapter-cache-redis-5.115.0.tgz +0 -0
- package/components/tryghost-adapter-manager-5.115.0.tgz +0 -0
- package/components/tryghost-announcement-bar-settings-5.115.0.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.115.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.115.0.tgz +0 -0
- package/components/tryghost-bookshelf-repository-5.115.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.115.0.tgz +0 -0
- package/components/tryghost-captcha-service-5.115.0.tgz +0 -0
- package/components/tryghost-constants-5.115.0.tgz +0 -0
- package/components/tryghost-custom-fonts-5.115.0.tgz +0 -0
- package/components/tryghost-data-generator-5.115.0.tgz +0 -0
- package/components/tryghost-domain-events-5.115.0.tgz +0 -0
- package/components/tryghost-email-addresses-5.115.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.115.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.115.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.115.0.tgz +0 -0
- package/components/tryghost-email-events-5.115.0.tgz +0 -0
- package/components/tryghost-email-service-5.115.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.115.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.115.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.115.0.tgz +0 -0
- package/components/tryghost-ghost-5.115.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.115.0.tgz +0 -0
- package/components/tryghost-i18n-5.115.0.tgz +0 -0
- package/components/tryghost-identity-token-service-5.115.0.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.115.0.tgz +0 -0
- package/components/tryghost-importer-revue-5.115.0.tgz +0 -0
- package/components/tryghost-in-memory-repository-5.115.0.tgz +0 -0
- package/components/tryghost-job-manager-5.115.0.tgz +0 -0
- package/components/tryghost-link-redirects-5.115.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.115.0.tgz +0 -0
- package/components/tryghost-magic-link-5.115.0.tgz +0 -0
- package/components/tryghost-mail-events-5.115.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.115.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.115.0.tgz +0 -0
- package/components/tryghost-member-events-5.115.0.tgz +0 -0
- package/components/tryghost-members-api-5.115.0.tgz +0 -0
- package/components/tryghost-members-csv-5.115.0.tgz +0 -0
- package/components/tryghost-members-importer-5.115.0.tgz +0 -0
- package/components/tryghost-members-payments-5.115.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.115.0.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.115.0.tgz +0 -0
- package/components/tryghost-minifier-5.115.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.115.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.115.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.115.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.115.0.tgz +0 -0
- package/components/tryghost-mw-version-match-5.115.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.115.0.tgz +0 -0
- package/components/tryghost-package-json-5.115.0.tgz +0 -0
- package/components/tryghost-posts-service-5.115.0.tgz +0 -0
- package/components/tryghost-recommendations-5.115.0.tgz +0 -0
- package/components/tryghost-referrers-5.115.0.tgz +0 -0
- package/components/tryghost-security-5.115.0.tgz +0 -0
- package/components/tryghost-session-service-5.115.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.115.0.tgz +0 -0
- package/components/tryghost-slack-notifications-5.115.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.115.0.tgz +0 -0
- package/components/tryghost-webmentions-5.115.0.tgz +0 -0
- package/core/built/admin/assets/chunk.524.31419fdf6fb3859ecc1e.js +0 -35
- package/core/built/admin/assets/chunk.582.08c816d5e4ab766486a7.js +0 -37
- package/core/built/admin/assets/ghost-c2a7c4a1b76550c4219adb2ed4124ce0.css +0 -1
- package/core/built/admin/assets/ghost-dark-f91e4a479c6d38d94d5d1b14727871dc.css +0 -1
- /package/core/built/admin/assets/{chunk.874.461cb3cf5b6b36915f8c.js.LICENSE.txt → chunk.713.e9027c0cc3c56110f5da.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,931 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
const {VersionMismatchError} = require('@tryghost/errors');
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
const debug = require('@tryghost/debug')('stripe');
|
|
5
|
+
const Stripe = require('stripe').Stripe;
|
|
6
|
+
|
|
7
|
+
/* Stripe has the following rate limits:
|
|
8
|
+
* - For most APIs, 100 read requests per second in live mode, 25 read requests per second in test mode
|
|
9
|
+
* - For search, 20 requests per second in both live and test modes
|
|
10
|
+
*
|
|
11
|
+
* For the testing environment, we increase these limits to 10,000 req/s to keep tests fast
|
|
12
|
+
*/
|
|
13
|
+
const EXPECTED_API_EFFICIENCY = 0.95;
|
|
14
|
+
const EXPECTED_SEARCH_API_EFFICIENCY = 0.15;
|
|
15
|
+
|
|
16
|
+
// If we're running in a testing environment, we don't want to rate limit the Stripe API like we do in production
|
|
17
|
+
const isTesting = process.env.NODE_ENV?.includes('testing');
|
|
18
|
+
const TEST_MODE_RATE_LIMIT = isTesting ? 10_000 : 25;
|
|
19
|
+
const LIVE_MODE_RATE_LIMIT = isTesting ? 10_000 : 100;
|
|
20
|
+
const SEARCH_MODE_RATE_LIMIT = isTesting ? 10_000 : 100;
|
|
21
|
+
|
|
22
|
+
const STRIPE_API_VERSION = '2020-08-27';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {import('stripe').Stripe.Customer} ICustomer
|
|
26
|
+
* @typedef {import('stripe').Stripe.DeletedCustomer} IDeletedCustomer
|
|
27
|
+
* @typedef {import('stripe').Stripe.Product} IProduct
|
|
28
|
+
* @typedef {import('stripe').Stripe.Plan} IPlan
|
|
29
|
+
* @typedef {import('stripe').Stripe.Price} IPrice
|
|
30
|
+
* @typedef {import('stripe').Stripe.WebhookEndpoint} IWebhookEndpoint
|
|
31
|
+
* @typedef {import('stripe').Stripe.Coupon} ICoupon
|
|
32
|
+
* @typedef {import('stripe').Stripe.CouponCreateParams} ICouponCreateParams
|
|
33
|
+
* @typedef {import('stripe').Stripe.ProductCreateParams} IProductCreateParams
|
|
34
|
+
* @typedef {import('stripe').Stripe.CustomerRetrieveParams} ICustomerRetrieveParams
|
|
35
|
+
* @typedef {import('stripe').Stripe.Checkout.Session} ICheckoutSession
|
|
36
|
+
* @typedef {import('stripe').Stripe.Checkout.SessionCreateParams} ICheckoutSessionCreateParams
|
|
37
|
+
* @typedef {import('stripe').Stripe.SubscriptionRetrieveParams} ISubscriptionRetrieveParams
|
|
38
|
+
* @typedef {import('stripe').Stripe.Subscription} ISubscription
|
|
39
|
+
* @typedef {import('stripe').Stripe.Checkout.SessionCreateParams.PaymentMethodType} IPaymentMethodType
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @typedef {object} IStripeAPIConfig
|
|
44
|
+
* @prop {string} secretKey
|
|
45
|
+
* @prop {string} publicKey
|
|
46
|
+
* @prop {boolean} enablePromoCodes
|
|
47
|
+
* @prop {boolean} enableAutomaticTax
|
|
48
|
+
* @prop {string} checkoutSessionSuccessUrl
|
|
49
|
+
* @prop {string} checkoutSessionCancelUrl
|
|
50
|
+
* @prop {string} checkoutSetupSessionSuccessUrl
|
|
51
|
+
* @prop {string} checkoutSetupSessionCancelUrl
|
|
52
|
+
* @prop {boolean} testEnv - indicates if the module is run in test environment (note, NOT the test mode)
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
module.exports = class StripeAPI {
|
|
56
|
+
/**
|
|
57
|
+
* StripeAPI
|
|
58
|
+
* @param {object} deps
|
|
59
|
+
* @param {object} deps.labs
|
|
60
|
+
*/
|
|
61
|
+
constructor(deps) {
|
|
62
|
+
/** @type {Stripe} */
|
|
63
|
+
this._stripe = null;
|
|
64
|
+
this._configured = false;
|
|
65
|
+
this.labs = deps.labs;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @returns {IPaymentMethodType[]|undefined}
|
|
70
|
+
*/
|
|
71
|
+
get PAYMENT_METHOD_TYPES() {
|
|
72
|
+
if (this.labs.isSet('additionalPaymentMethods')) {
|
|
73
|
+
return undefined;
|
|
74
|
+
} else {
|
|
75
|
+
return ['card'];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Returns true if the Stripe API is configured.
|
|
81
|
+
* @returns {boolean}
|
|
82
|
+
*/
|
|
83
|
+
get configured() {
|
|
84
|
+
return this._configured;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Returns true if this package is running in a test environment (i.e. browser tests).
|
|
89
|
+
*
|
|
90
|
+
* Note: This is not the same as the Stripe API's test mode.
|
|
91
|
+
* @returns {boolean}
|
|
92
|
+
*/
|
|
93
|
+
get testEnv() {
|
|
94
|
+
return this._config.testEnv;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns the Stripe API mode (test or live).
|
|
99
|
+
*
|
|
100
|
+
* @returns {string}
|
|
101
|
+
*/
|
|
102
|
+
get mode() {
|
|
103
|
+
return this._testMode ? 'test' : 'live';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Configure the Stripe API.
|
|
108
|
+
* - Instantiates the Stripe API client
|
|
109
|
+
* - Sets the Stripe API mode
|
|
110
|
+
* - Configures rate limiting buckets
|
|
111
|
+
*
|
|
112
|
+
* @param {IStripeAPIConfig} config
|
|
113
|
+
*
|
|
114
|
+
* @returns {void}
|
|
115
|
+
*/
|
|
116
|
+
configure(config) {
|
|
117
|
+
if (!config) {
|
|
118
|
+
this._stripe = null;
|
|
119
|
+
this._configured = false;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Lazyloaded to protect sites without Stripe configured
|
|
124
|
+
const LeakyBucket = require('leaky-bucket');
|
|
125
|
+
|
|
126
|
+
this._stripe = new Stripe(config.secretKey, {
|
|
127
|
+
apiVersion: STRIPE_API_VERSION
|
|
128
|
+
});
|
|
129
|
+
this._config = config;
|
|
130
|
+
this._testMode = config.secretKey && config.secretKey.startsWith('sk_test_');
|
|
131
|
+
if (this._testMode) {
|
|
132
|
+
this._rateLimitBucket = new LeakyBucket(EXPECTED_API_EFFICIENCY * TEST_MODE_RATE_LIMIT, 1);
|
|
133
|
+
} else {
|
|
134
|
+
this._rateLimitBucket = new LeakyBucket(EXPECTED_API_EFFICIENCY * LIVE_MODE_RATE_LIMIT, 1);
|
|
135
|
+
}
|
|
136
|
+
this._searchRateLimitBucket = new LeakyBucket(EXPECTED_SEARCH_API_EFFICIENCY * SEARCH_MODE_RATE_LIMIT, 1);
|
|
137
|
+
this._configured = true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Create a new Stripe Coupon.
|
|
142
|
+
*
|
|
143
|
+
* @param {ICouponCreateParams} options
|
|
144
|
+
*
|
|
145
|
+
* @returns {Promise<ICoupon>}
|
|
146
|
+
*/
|
|
147
|
+
async createCoupon(options) {
|
|
148
|
+
await this._rateLimitBucket.throttle();
|
|
149
|
+
const coupon = await this._stripe.coupons.create(options);
|
|
150
|
+
|
|
151
|
+
return coupon;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Retrieve the Stripe Product object by ID.
|
|
156
|
+
* @param {string} id
|
|
157
|
+
*
|
|
158
|
+
* @returns {Promise<IProduct>}
|
|
159
|
+
*/
|
|
160
|
+
async getProduct(id) {
|
|
161
|
+
await this._rateLimitBucket.throttle();
|
|
162
|
+
const product = await this._stripe.products.retrieve(id);
|
|
163
|
+
|
|
164
|
+
return product;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Create a new Stripe Product.
|
|
169
|
+
* @param {IProductCreateParams} options
|
|
170
|
+
*
|
|
171
|
+
* @returns {Promise<IProduct>}
|
|
172
|
+
*/
|
|
173
|
+
async createProduct(options) {
|
|
174
|
+
await this._rateLimitBucket.throttle();
|
|
175
|
+
const product = await this._stripe.products.create(options);
|
|
176
|
+
|
|
177
|
+
return product;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Create a new Stripe Price.
|
|
182
|
+
*
|
|
183
|
+
* @param {object} options
|
|
184
|
+
* @param {string} options.product
|
|
185
|
+
* @param {boolean} options.active
|
|
186
|
+
* @param {string} options.nickname
|
|
187
|
+
* @param {string} options.currency
|
|
188
|
+
* @param {number} [options.amount]
|
|
189
|
+
* @param {{enabled: boolean;maximum?: number;minimum?: number;preset?: number;}} [options.custom_unit_amount]
|
|
190
|
+
* @param {'recurring'|'one-time'} options.type
|
|
191
|
+
* @param {Stripe.Price.Recurring.Interval|null} [options.interval]
|
|
192
|
+
*
|
|
193
|
+
* @returns {Promise<IPrice>}
|
|
194
|
+
*/
|
|
195
|
+
async createPrice(options) {
|
|
196
|
+
await this._rateLimitBucket.throttle();
|
|
197
|
+
const price = await this._stripe.prices.create({
|
|
198
|
+
currency: options.currency,
|
|
199
|
+
product: options.product,
|
|
200
|
+
unit_amount: options.amount,
|
|
201
|
+
active: options.active,
|
|
202
|
+
nickname: options.nickname,
|
|
203
|
+
// @ts-ignore
|
|
204
|
+
custom_unit_amount: options.custom_unit_amount, // missing in .d.ts definitions in the Stripe node version we use, but should be supported in Stripe API at this version (:
|
|
205
|
+
recurring: options.type === 'recurring' && options.interval ? {
|
|
206
|
+
interval: options.interval
|
|
207
|
+
} : undefined
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
return price;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Update the Stripe Price object by ID.
|
|
215
|
+
*
|
|
216
|
+
* @param {string} id
|
|
217
|
+
* @param {object} options
|
|
218
|
+
* @param {boolean} [options.active]
|
|
219
|
+
* @param {string} [options.nickname]
|
|
220
|
+
*
|
|
221
|
+
* @returns {Promise<IPrice>}
|
|
222
|
+
*/
|
|
223
|
+
async updatePrice(id, options) {
|
|
224
|
+
await this._rateLimitBucket.throttle();
|
|
225
|
+
const price = await this._stripe.prices.update(id, {
|
|
226
|
+
active: options.active,
|
|
227
|
+
nickname: options.nickname
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
return price;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Update the Stripe Product object by ID.
|
|
235
|
+
*
|
|
236
|
+
* @param {string} id
|
|
237
|
+
* @param {object} options
|
|
238
|
+
* @param {string} options.name
|
|
239
|
+
*
|
|
240
|
+
* @returns {Promise<IProduct>}
|
|
241
|
+
*/
|
|
242
|
+
async updateProduct(id, options) {
|
|
243
|
+
await this._rateLimitBucket.throttle();
|
|
244
|
+
const product = await this._stripe.products.update(id, {
|
|
245
|
+
name: options.name
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
return product;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Retrieve the Stripe Customer object by ID.
|
|
253
|
+
*
|
|
254
|
+
* @param {string} id
|
|
255
|
+
* @param {ICustomerRetrieveParams} options
|
|
256
|
+
*
|
|
257
|
+
* @returns {Promise<ICustomer|IDeletedCustomer>}
|
|
258
|
+
* @throws {Error}
|
|
259
|
+
*/
|
|
260
|
+
async getCustomer(id, options = {}) {
|
|
261
|
+
debug(`getCustomer(${id}, ${JSON.stringify(options)})`);
|
|
262
|
+
try {
|
|
263
|
+
await this._rateLimitBucket.throttle();
|
|
264
|
+
if (options.expand) {
|
|
265
|
+
options.expand.push('subscriptions');
|
|
266
|
+
} else {
|
|
267
|
+
options.expand = ['subscriptions'];
|
|
268
|
+
}
|
|
269
|
+
const customer = await this._stripe.customers.retrieve(id, options);
|
|
270
|
+
debug(`getCustomer(${id}, ${JSON.stringify(options)}) -> Success`);
|
|
271
|
+
return customer;
|
|
272
|
+
} catch (err) {
|
|
273
|
+
debug(`getCustomer(${id}, ${JSON.stringify(options)}) -> ${err.type}`);
|
|
274
|
+
throw err;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Finds or creates a Stripe Customer for a Member.
|
|
280
|
+
*
|
|
281
|
+
* @deprecated
|
|
282
|
+
* @param {any} member
|
|
283
|
+
*
|
|
284
|
+
* @returns {Promise<ICustomer>}
|
|
285
|
+
*/
|
|
286
|
+
async getCustomerForMemberCheckoutSession(member) {
|
|
287
|
+
await member.related('stripeCustomers').fetch();
|
|
288
|
+
const customers = member.related('stripeCustomers');
|
|
289
|
+
for (const data of customers.models) {
|
|
290
|
+
try {
|
|
291
|
+
const customer = await this.getCustomer(data.get('customer_id'));
|
|
292
|
+
if (!customer.deleted) {
|
|
293
|
+
return /** @type {ICustomer} */(customer);
|
|
294
|
+
}
|
|
295
|
+
} catch (err) {
|
|
296
|
+
debug(`Ignoring Error getting customer for member ${err.message}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
debug(`Creating customer for member ${member.get('email')}`);
|
|
301
|
+
const customer = await this.createCustomer({
|
|
302
|
+
email: member.get('email')
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
return customer;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Finds a Stripe Customer ID based on the provided email address. Returns null if no customer is found.
|
|
310
|
+
* @param {string} email
|
|
311
|
+
* @see https://stripe.com/docs/api/customers/search
|
|
312
|
+
*
|
|
313
|
+
* @returns {Promise<string|null>} Stripe Customer ID, if found
|
|
314
|
+
*/
|
|
315
|
+
async getCustomerIdByEmail(email) {
|
|
316
|
+
await this._searchRateLimitBucket.throttle();
|
|
317
|
+
try {
|
|
318
|
+
const result = await this._stripe.customers.search({
|
|
319
|
+
query: `email:"${email}"`,
|
|
320
|
+
limit: 10,
|
|
321
|
+
expand: ['data.subscriptions']
|
|
322
|
+
});
|
|
323
|
+
const customers = result.data;
|
|
324
|
+
|
|
325
|
+
// No customer found, return null
|
|
326
|
+
if (customers.length === 0) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Return the only customer found
|
|
331
|
+
if (customers.length === 1) {
|
|
332
|
+
return customers[0].id;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Multiple customers found, return the one with the most recent subscription
|
|
336
|
+
if (customers.length > 1) {
|
|
337
|
+
let latestCustomer = customers[0];
|
|
338
|
+
let latestSubscriptionTime = 0;
|
|
339
|
+
|
|
340
|
+
for (let customer of customers) {
|
|
341
|
+
// skip customers with no subscriptions
|
|
342
|
+
if (!customer.subscriptions || !customer.subscriptions.data || customer.subscriptions.data.length === 0) {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// find the customer with the most recent subscription
|
|
347
|
+
for (let subscription of customer.subscriptions.data) {
|
|
348
|
+
if (subscription.current_period_end && subscription.current_period_end > latestSubscriptionTime) {
|
|
349
|
+
latestSubscriptionTime = subscription.current_period_end;
|
|
350
|
+
latestCustomer = customer;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return latestCustomer.id;
|
|
356
|
+
}
|
|
357
|
+
} catch (err) {
|
|
358
|
+
debug(`getCustomerByEmail(${email}) -> ${err.type}:${err.message}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Create a new Stripe Customer.
|
|
364
|
+
*
|
|
365
|
+
* @param {import('stripe').Stripe.CustomerCreateParams} options
|
|
366
|
+
*
|
|
367
|
+
* @returns {Promise<ICustomer>}
|
|
368
|
+
*/
|
|
369
|
+
async createCustomer(options = {}) {
|
|
370
|
+
debug(`createCustomer(${JSON.stringify(options)})`);
|
|
371
|
+
try {
|
|
372
|
+
await this._rateLimitBucket.throttle();
|
|
373
|
+
const customer = await this._stripe.customers.create(options);
|
|
374
|
+
debug(`createCustomer(${JSON.stringify(options)}) -> Success`);
|
|
375
|
+
return customer;
|
|
376
|
+
} catch (err) {
|
|
377
|
+
debug(`createCustomer(${JSON.stringify(options)}) -> ${err.type}`);
|
|
378
|
+
throw err;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Update the email address for a Stripe Customer.
|
|
384
|
+
*
|
|
385
|
+
* @param {string} id
|
|
386
|
+
* @param {string} email
|
|
387
|
+
*
|
|
388
|
+
* @returns {Promise<ICustomer>}
|
|
389
|
+
*/
|
|
390
|
+
async updateCustomerEmail(id, email) {
|
|
391
|
+
debug(`updateCustomerEmail(${id}, ${email})`);
|
|
392
|
+
try {
|
|
393
|
+
await this._rateLimitBucket.throttle();
|
|
394
|
+
const customer = await this._stripe.customers.update(id, {email});
|
|
395
|
+
debug(`updateCustomerEmail(${id}, ${email}) -> Success`);
|
|
396
|
+
return customer;
|
|
397
|
+
} catch (err) {
|
|
398
|
+
debug(`updateCustomerEmail(${id}, ${email}) -> ${err.type}`);
|
|
399
|
+
throw err;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Create a new Stripe Webhook Endpoint.
|
|
405
|
+
*
|
|
406
|
+
* @param {string} url
|
|
407
|
+
* @param {import('stripe').Stripe.WebhookEndpointUpdateParams.EnabledEvent[]} events
|
|
408
|
+
*
|
|
409
|
+
* @returns {Promise<IWebhookEndpoint>}
|
|
410
|
+
*/
|
|
411
|
+
async createWebhookEndpoint(url, events) {
|
|
412
|
+
debug(`createWebhook(${url})`);
|
|
413
|
+
try {
|
|
414
|
+
await this._rateLimitBucket.throttle();
|
|
415
|
+
const webhook = await this._stripe.webhookEndpoints.create({
|
|
416
|
+
url,
|
|
417
|
+
enabled_events: events,
|
|
418
|
+
api_version: STRIPE_API_VERSION
|
|
419
|
+
});
|
|
420
|
+
debug(`createWebhook(${url}) -> Success`);
|
|
421
|
+
return webhook;
|
|
422
|
+
} catch (err) {
|
|
423
|
+
debug(`createWebhook(${url}) -> ${err.type}`);
|
|
424
|
+
throw err;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Delete a Stripe Webhook Endpoint by ID.
|
|
430
|
+
*
|
|
431
|
+
* @param {string} id
|
|
432
|
+
*
|
|
433
|
+
* @returns {Promise<void>}
|
|
434
|
+
*/
|
|
435
|
+
async deleteWebhookEndpoint(id) {
|
|
436
|
+
debug(`deleteWebhook(${id})`);
|
|
437
|
+
try {
|
|
438
|
+
await this._rateLimitBucket.throttle();
|
|
439
|
+
await this._stripe.webhookEndpoints.del(id);
|
|
440
|
+
debug(`deleteWebhook(${id}) -> Success`);
|
|
441
|
+
return;
|
|
442
|
+
} catch (err) {
|
|
443
|
+
debug(`deleteWebhook(${id}) -> ${err.type}`);
|
|
444
|
+
throw err;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Update a Stripe Webhook Endpoint by ID and URL.
|
|
450
|
+
*
|
|
451
|
+
* @param {string} id
|
|
452
|
+
* @param {string} url
|
|
453
|
+
* @param {import('stripe').Stripe.WebhookEndpointUpdateParams.EnabledEvent[]} events
|
|
454
|
+
*
|
|
455
|
+
* @returns {Promise<IWebhookEndpoint>}
|
|
456
|
+
*/
|
|
457
|
+
async updateWebhookEndpoint(id, url, events) {
|
|
458
|
+
debug(`updateWebhook(${id}, ${url})`);
|
|
459
|
+
try {
|
|
460
|
+
await this._rateLimitBucket.throttle();
|
|
461
|
+
const webhook = await this._stripe.webhookEndpoints.update(id, {
|
|
462
|
+
url,
|
|
463
|
+
enabled_events: events
|
|
464
|
+
});
|
|
465
|
+
if (webhook.api_version !== STRIPE_API_VERSION) {
|
|
466
|
+
throw new VersionMismatchError({message: 'Webhook has incorrect api_version'});
|
|
467
|
+
}
|
|
468
|
+
debug(`updateWebhook(${id}, ${url}) -> Success`);
|
|
469
|
+
return webhook;
|
|
470
|
+
} catch (err) {
|
|
471
|
+
debug(`updateWebhook(${id}, ${url}) -> ${err.type}`);
|
|
472
|
+
throw err;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Parse a Stripe Webhook event.
|
|
478
|
+
*
|
|
479
|
+
* @param {string} body
|
|
480
|
+
* @param {string} signature
|
|
481
|
+
* @param {string} secret
|
|
482
|
+
*
|
|
483
|
+
* @returns {import('stripe').Stripe.Event}
|
|
484
|
+
*/
|
|
485
|
+
parseWebhook(body, signature, secret) {
|
|
486
|
+
debug(`parseWebhook(${body}, ${signature}, ${secret})`);
|
|
487
|
+
try {
|
|
488
|
+
const event = this._stripe.webhooks.constructEvent(body, signature, secret);
|
|
489
|
+
debug(`parseWebhook(${body}, ${signature}, ${secret}) -> Success ${event.type}`);
|
|
490
|
+
return event;
|
|
491
|
+
} catch (err) {
|
|
492
|
+
debug(`parseWebhook(${body}, ${signature}, ${secret}) -> ${err.type}`);
|
|
493
|
+
throw err;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Create a new Stripe Checkout Session for a new subscription.
|
|
499
|
+
*
|
|
500
|
+
* @param {string} priceId
|
|
501
|
+
* @param {ICustomer} customer
|
|
502
|
+
*
|
|
503
|
+
* @param {object} options
|
|
504
|
+
* @param {Object.<String, any>} options.metadata
|
|
505
|
+
* @param {string} options.successUrl
|
|
506
|
+
* @param {string} options.cancelUrl
|
|
507
|
+
* @param {string} options.customerEmail
|
|
508
|
+
* @param {number} options.trialDays
|
|
509
|
+
* @param {string} [options.coupon]
|
|
510
|
+
*
|
|
511
|
+
* @returns {Promise<ICheckoutSession>}
|
|
512
|
+
*/
|
|
513
|
+
async createCheckoutSession(priceId, customer, options) {
|
|
514
|
+
const metadata = options.metadata || undefined; // https://docs.stripe.com/api/metadata some limits to how much can be passed
|
|
515
|
+
const customerId = customer ? customer.id : undefined;
|
|
516
|
+
const customerEmail = customer ? customer.email : options.customerEmail;
|
|
517
|
+
|
|
518
|
+
await this._rateLimitBucket.throttle();
|
|
519
|
+
let discounts;
|
|
520
|
+
if (options.coupon) {
|
|
521
|
+
discounts = [{coupon: options.coupon}];
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const subscriptionData = {
|
|
525
|
+
trial_from_plan: true,
|
|
526
|
+
items: [{
|
|
527
|
+
plan: priceId
|
|
528
|
+
}],
|
|
529
|
+
metadata: {
|
|
530
|
+
attribution_id: metadata?.attribution_id,
|
|
531
|
+
attribution_url: metadata?.attribution_url,
|
|
532
|
+
attribution_type: metadata?.attribution_type,
|
|
533
|
+
referrer_source: metadata?.referrer_source,
|
|
534
|
+
referrer_medium: metadata?.referrer_medium,
|
|
535
|
+
referrer_url: metadata?.referrer_url
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* `trial_from_plan` is deprecated.
|
|
541
|
+
* Replaces it in favor of custom trial period days stored in Ghost
|
|
542
|
+
*/
|
|
543
|
+
if (typeof options.trialDays === 'number' && options.trialDays > 0) {
|
|
544
|
+
delete subscriptionData.trial_from_plan;
|
|
545
|
+
subscriptionData.trial_period_days = options.trialDays;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
let stripeSessionOptions = {
|
|
549
|
+
payment_method_types: this.PAYMENT_METHOD_TYPES,
|
|
550
|
+
success_url: options.successUrl || this._config.checkoutSessionSuccessUrl,
|
|
551
|
+
cancel_url: options.cancelUrl || this._config.checkoutSessionCancelUrl,
|
|
552
|
+
// @ts-ignore - we need to update to latest stripe library to correctly use newer features
|
|
553
|
+
allow_promotion_codes: discounts ? undefined : this._config.enablePromoCodes,
|
|
554
|
+
automatic_tax: {
|
|
555
|
+
enabled: this._config.enableAutomaticTax
|
|
556
|
+
},
|
|
557
|
+
metadata,
|
|
558
|
+
discounts,
|
|
559
|
+
/*
|
|
560
|
+
line_items: [{
|
|
561
|
+
price: priceId
|
|
562
|
+
}]
|
|
563
|
+
*/
|
|
564
|
+
// This is deprecated and using the old way of doing things with Plans.
|
|
565
|
+
// It should be replaced with the line_items entry above when possible,
|
|
566
|
+
// however, this would lose the "trial from plan" feature which has also
|
|
567
|
+
// been deprecated by Stripe
|
|
568
|
+
subscription_data: subscriptionData
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
/* We are only allowed to specify one of these; email will be pulled from
|
|
572
|
+
customer object on Stripe side if that object already exists. */
|
|
573
|
+
if (customerId) {
|
|
574
|
+
stripeSessionOptions.customer = customerId;
|
|
575
|
+
} else {
|
|
576
|
+
stripeSessionOptions.customer_email = customerEmail;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (customerId && this._config.enableAutomaticTax) {
|
|
580
|
+
stripeSessionOptions.customer_update = {address: 'auto'};
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// @ts-ignore
|
|
584
|
+
const session = await this._stripe.checkout.sessions.create(stripeSessionOptions);
|
|
585
|
+
|
|
586
|
+
return session;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Create a new Stripe Checkout Session for a donation.
|
|
591
|
+
*
|
|
592
|
+
* @param {object} options
|
|
593
|
+
* @param {string} options.priceId
|
|
594
|
+
* @param {string} options.successUrl
|
|
595
|
+
* @param {string} options.cancelUrl
|
|
596
|
+
* @param {Object.<String, any>} options.metadata
|
|
597
|
+
* @param {ICustomer} [options.customer]
|
|
598
|
+
* @param {string} [options.customerEmail]
|
|
599
|
+
* @param {string} [options.personalNote]
|
|
600
|
+
*
|
|
601
|
+
* @returns {Promise<ICheckoutSession>}
|
|
602
|
+
*/
|
|
603
|
+
async createDonationCheckoutSession({priceId, successUrl, cancelUrl, metadata, customer, customerEmail, personalNote}) {
|
|
604
|
+
await this._rateLimitBucket.throttle();
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* @type {Stripe.Checkout.SessionCreateParams}
|
|
608
|
+
*/
|
|
609
|
+
|
|
610
|
+
// TODO - add it higher up the stack to the metadata object.
|
|
611
|
+
// add ghost_donation key to metadata object
|
|
612
|
+
metadata = {
|
|
613
|
+
ghost_donation: true,
|
|
614
|
+
...metadata
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
const stripeSessionOptions = {
|
|
618
|
+
mode: 'payment',
|
|
619
|
+
success_url: successUrl || this._config.checkoutSessionSuccessUrl,
|
|
620
|
+
cancel_url: cancelUrl || this._config.checkoutSessionCancelUrl,
|
|
621
|
+
automatic_tax: {
|
|
622
|
+
enabled: this._config.enableAutomaticTax
|
|
623
|
+
},
|
|
624
|
+
metadata,
|
|
625
|
+
customer: customer ? customer.id : undefined,
|
|
626
|
+
customer_email: !customer && customerEmail ? customerEmail : undefined,
|
|
627
|
+
submit_type: 'pay',
|
|
628
|
+
invoice_creation: {
|
|
629
|
+
enabled: true,
|
|
630
|
+
invoice_data: {
|
|
631
|
+
// Make sure we pass the data through to the invoice
|
|
632
|
+
metadata: {
|
|
633
|
+
ghost_donation: true,
|
|
634
|
+
...metadata
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
},
|
|
638
|
+
line_items: [{
|
|
639
|
+
price: priceId,
|
|
640
|
+
quantity: 1
|
|
641
|
+
}],
|
|
642
|
+
custom_fields: [
|
|
643
|
+
{
|
|
644
|
+
key: 'donation_message',
|
|
645
|
+
label: {
|
|
646
|
+
type: 'custom',
|
|
647
|
+
custom: personalNote || 'Add a personal note'
|
|
648
|
+
},
|
|
649
|
+
type: 'text',
|
|
650
|
+
optional: true
|
|
651
|
+
}
|
|
652
|
+
]
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
if (customer && this._config.enableAutomaticTax) {
|
|
656
|
+
stripeSessionOptions.customer_update = {address: 'auto'};
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// @ts-ignore
|
|
660
|
+
const session = await this._stripe.checkout.sessions.create(stripeSessionOptions);
|
|
661
|
+
return session;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Create a new Stripe Checkout Setup Session.
|
|
666
|
+
*
|
|
667
|
+
* @param {ICustomer} customer
|
|
668
|
+
* @param {object} options
|
|
669
|
+
* @param {string} options.successUrl
|
|
670
|
+
* @param {string} options.cancelUrl
|
|
671
|
+
* @param {string} options.currency - 3-letter ISO code in lowercase, e.g. `usd`
|
|
672
|
+
* @returns {Promise<ICheckoutSession>}
|
|
673
|
+
*/
|
|
674
|
+
async createCheckoutSetupSession(customer, options) {
|
|
675
|
+
await this._rateLimitBucket.throttle();
|
|
676
|
+
const session = await this._stripe.checkout.sessions.create({
|
|
677
|
+
mode: 'setup',
|
|
678
|
+
payment_method_types: this.PAYMENT_METHOD_TYPES,
|
|
679
|
+
success_url: options.successUrl || this._config.checkoutSetupSessionSuccessUrl,
|
|
680
|
+
cancel_url: options.cancelUrl || this._config.checkoutSetupSessionCancelUrl,
|
|
681
|
+
customer_email: customer.email,
|
|
682
|
+
setup_intent_data: {
|
|
683
|
+
metadata: {
|
|
684
|
+
customer_id: customer.id
|
|
685
|
+
}
|
|
686
|
+
},
|
|
687
|
+
|
|
688
|
+
// Note: this is required for dynamic payment methods
|
|
689
|
+
// https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-currency
|
|
690
|
+
// @ts-ignore
|
|
691
|
+
currency: this.labs.isSet('additionalPaymentMethods') ? options.currency : undefined
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
return session;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Get the Stripe public key.
|
|
699
|
+
*
|
|
700
|
+
* @returns {string}
|
|
701
|
+
*/
|
|
702
|
+
getPublicKey() {
|
|
703
|
+
return this._config.publicKey;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Retrieve the Stripe Price object by ID.
|
|
708
|
+
*
|
|
709
|
+
* @param {string} id
|
|
710
|
+
* @param {object} options
|
|
711
|
+
*
|
|
712
|
+
* @returns {Promise<IPrice>}
|
|
713
|
+
*/
|
|
714
|
+
async getPrice(id, options = {}) {
|
|
715
|
+
debug(`getPrice(${id}, ${JSON.stringify(options)})`);
|
|
716
|
+
|
|
717
|
+
return await this._stripe.prices.retrieve(id, options);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Retrieve the Stripe Subscription object by ID.
|
|
722
|
+
*
|
|
723
|
+
* @param {string} id
|
|
724
|
+
* @param {ISubscriptionRetrieveParams} options
|
|
725
|
+
*
|
|
726
|
+
* @returns {Promise<ISubscription>}
|
|
727
|
+
*/
|
|
728
|
+
async getSubscription(id, options = {}) {
|
|
729
|
+
debug(`getSubscription(${id}, ${JSON.stringify(options)})`);
|
|
730
|
+
try {
|
|
731
|
+
await this._rateLimitBucket.throttle();
|
|
732
|
+
const subscription = await this._stripe.subscriptions.retrieve(id, options);
|
|
733
|
+
debug(`getSubscription(${id}, ${JSON.stringify(options)}) -> Success`);
|
|
734
|
+
return subscription;
|
|
735
|
+
} catch (err) {
|
|
736
|
+
debug(`getSubscription(${id}, ${JSON.stringify(options)}) -> ${err.type}`);
|
|
737
|
+
throw err;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Cancel the Stripe Subscription by ID.
|
|
743
|
+
*
|
|
744
|
+
* @param {string} id
|
|
745
|
+
*
|
|
746
|
+
* @returns {Promise<ISubscription>}
|
|
747
|
+
*/
|
|
748
|
+
async cancelSubscription(id) {
|
|
749
|
+
debug(`cancelSubscription(${id})`);
|
|
750
|
+
try {
|
|
751
|
+
await this._rateLimitBucket.throttle();
|
|
752
|
+
const subscription = await this._stripe.subscriptions.del(id);
|
|
753
|
+
debug(`cancelSubscription(${id}) -> Success`);
|
|
754
|
+
return subscription;
|
|
755
|
+
} catch (err) {
|
|
756
|
+
debug(`cancelSubscription(${id}) -> ${err.type}`);
|
|
757
|
+
throw err;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Cancel the Stripe Subscription at the end of the current period by ID.
|
|
763
|
+
*
|
|
764
|
+
* @param {string} id - The ID of the Subscription to modify
|
|
765
|
+
* @param {string} [reason=''] - The user defined cancellation reason
|
|
766
|
+
*
|
|
767
|
+
* @returns {Promise<ISubscription>}
|
|
768
|
+
*/
|
|
769
|
+
async cancelSubscriptionAtPeriodEnd(id, reason = '') {
|
|
770
|
+
await this._rateLimitBucket.throttle();
|
|
771
|
+
const subscription = await this._stripe.subscriptions.update(id, {
|
|
772
|
+
cancel_at_period_end: true,
|
|
773
|
+
metadata: {
|
|
774
|
+
cancellation_reason: reason
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
return subscription;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Continue the Stripe Subscription at the end of the current period by ID.
|
|
782
|
+
*
|
|
783
|
+
* @param {string} id - The ID of the Subscription to modify
|
|
784
|
+
*
|
|
785
|
+
* @returns {Promise<ISubscription>}
|
|
786
|
+
*/
|
|
787
|
+
async continueSubscriptionAtPeriodEnd(id) {
|
|
788
|
+
await this._rateLimitBucket.throttle();
|
|
789
|
+
const subscription = await this._stripe.subscriptions.update(id, {
|
|
790
|
+
cancel_at_period_end: false,
|
|
791
|
+
metadata: {
|
|
792
|
+
cancellation_reason: null
|
|
793
|
+
}
|
|
794
|
+
});
|
|
795
|
+
return subscription;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Remove the coupon from the Stripe Subscription by ID.
|
|
800
|
+
*
|
|
801
|
+
* @param {string} id - The ID of the subscription to remove coupon from
|
|
802
|
+
*
|
|
803
|
+
* @returns {Promise<ISubscription>}
|
|
804
|
+
*/
|
|
805
|
+
async removeCouponFromSubscription(id) {
|
|
806
|
+
await this._rateLimitBucket.throttle();
|
|
807
|
+
const subscription = await this._stripe.subscriptions.update(id, {
|
|
808
|
+
coupon: ''
|
|
809
|
+
});
|
|
810
|
+
return subscription;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* Update the price of the Stripe SubscriptionItem by Subscription ID,
|
|
815
|
+
* SubscriptionItem ID, and Price ID.
|
|
816
|
+
*
|
|
817
|
+
* @param {string} subscriptionId - The ID of the Subscription to modify
|
|
818
|
+
* @param {string} id - The ID of the SubscriptionItem
|
|
819
|
+
* @param {string} price - The ID of the new Price
|
|
820
|
+
* @param {object} [options={}] - Additional data to set on the subscription object
|
|
821
|
+
* @param {('always_invoice'|'create_prorations'|'none')} [options.prorationBehavior='always_invoice'] - The proration behavior to use. See [Stripe docs](https://docs.stripe.com/api/subscriptions/update#update_subscription-proration_behavior) for more info
|
|
822
|
+
* @param {string} [options.cancellationReason=null] - The user defined cancellation reason
|
|
823
|
+
*
|
|
824
|
+
* @returns {Promise<ISubscription>}
|
|
825
|
+
*/
|
|
826
|
+
async updateSubscriptionItemPrice(subscriptionId, id, price, options = {}) {
|
|
827
|
+
await this._rateLimitBucket.throttle();
|
|
828
|
+
const subscription = await this._stripe.subscriptions.update(subscriptionId, {
|
|
829
|
+
proration_behavior: options.prorationBehavior || 'always_invoice',
|
|
830
|
+
items: [{
|
|
831
|
+
id,
|
|
832
|
+
price
|
|
833
|
+
}],
|
|
834
|
+
cancel_at_period_end: false,
|
|
835
|
+
metadata: {
|
|
836
|
+
cancellation_reason: options.cancellationReason ?? null
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
return subscription;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Create a new Stripe Subscription for a Customer by ID and Price ID.
|
|
844
|
+
*
|
|
845
|
+
* @param {string} customer - The ID of the Customer to create the subscription for
|
|
846
|
+
* @param {string} price - The ID of the new Price
|
|
847
|
+
*
|
|
848
|
+
* @returns {Promise<ISubscription>}
|
|
849
|
+
*/
|
|
850
|
+
async createSubscription(customer, price) {
|
|
851
|
+
await this._rateLimitBucket.throttle();
|
|
852
|
+
const subscription = await this._stripe.subscriptions.create({
|
|
853
|
+
customer,
|
|
854
|
+
items: [{price}]
|
|
855
|
+
});
|
|
856
|
+
return subscription;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* Retrieve the Stripe SetupIntent object by ID.
|
|
861
|
+
*
|
|
862
|
+
* @param {string} id
|
|
863
|
+
* @param {import('stripe').Stripe.SetupIntentRetrieveParams} options
|
|
864
|
+
*
|
|
865
|
+
* @returns {Promise<import('stripe').Stripe.SetupIntent>}
|
|
866
|
+
*/
|
|
867
|
+
async getSetupIntent(id, options = {}) {
|
|
868
|
+
await this._rateLimitBucket.throttle();
|
|
869
|
+
return await this._stripe.setupIntents.retrieve(id, options);
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* Attach a PaymentMethod to a Customer
|
|
874
|
+
*
|
|
875
|
+
* @param {string} customer
|
|
876
|
+
* @param {string} paymentMethod
|
|
877
|
+
*
|
|
878
|
+
* @returns {Promise<void>}
|
|
879
|
+
*/
|
|
880
|
+
async attachPaymentMethodToCustomer(customer, paymentMethod) {
|
|
881
|
+
await this._rateLimitBucket.throttle();
|
|
882
|
+
await this._stripe.paymentMethods.attach(paymentMethod, {customer});
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Retrieve the Stripe PaymentMethod object by ID.
|
|
888
|
+
*
|
|
889
|
+
* @param {string} id
|
|
890
|
+
*
|
|
891
|
+
* @returns {Promise<import('stripe').Stripe.PaymentMethod|null>}
|
|
892
|
+
*/
|
|
893
|
+
async getCardPaymentMethod(id) {
|
|
894
|
+
await this._rateLimitBucket.throttle();
|
|
895
|
+
const paymentMethod = await this._stripe.paymentMethods.retrieve(id);
|
|
896
|
+
if (paymentMethod.type !== 'card') {
|
|
897
|
+
return null;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
return paymentMethod;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Update the default PaymentMethod for a Subscription.
|
|
905
|
+
*
|
|
906
|
+
* @param {string} subscription
|
|
907
|
+
* @param {string} paymentMethod
|
|
908
|
+
*
|
|
909
|
+
* @returns {Promise<ISubscription>}
|
|
910
|
+
*/
|
|
911
|
+
async updateSubscriptionDefaultPaymentMethod(subscription, paymentMethod) {
|
|
912
|
+
await this._rateLimitBucket.throttle();
|
|
913
|
+
return await this._stripe.subscriptions.update(subscription, {
|
|
914
|
+
default_payment_method: paymentMethod
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Cancel the trial for a Stripe Subscription by ID.
|
|
920
|
+
*
|
|
921
|
+
* @param {string} id - The ID of the subscription to cancel the trial for
|
|
922
|
+
*
|
|
923
|
+
* @returns {Promise<ISubscription>}
|
|
924
|
+
*/
|
|
925
|
+
async cancelSubscriptionTrial(id) {
|
|
926
|
+
await this._rateLimitBucket.throttle();
|
|
927
|
+
return this._stripe.subscriptions.update(id, {
|
|
928
|
+
trial_end: 'now'
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
};
|