UNPKG

@donation-alerts/api

Version:
176 lines (175 loc) 7.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ApiClient = void 0; const tslib_1 = require("tslib"); const rate_limiter_1 = require("@d-fischer/rate-limiter"); const api_call_1 = require("@donation-alerts/api-call"); const common_1 = require("@donation-alerts/common"); const logger_1 = require("@stimulcross/logger"); const shared_utils_1 = require("@stimulcross/shared-utils"); const typescript_memoize_1 = require("typescript-memoize"); const donation_alerts_centrifugo_api_1 = require("./api/centrifugo/donation-alerts-centrifugo-api"); const donation_alerts_custom_alerts_api_1 = require("./api/customAlerts/donation-alerts-custom-alerts-api"); const donation_alerts_donations_api_1 = require("./api/donations/donation-alerts-donations-api"); const donation_alerts_merchandise_api_1 = require("./api/merchandise/donation-alerts-merchandise-api"); const donation_alerts_users_api_1 = require("./api/users/donation-alerts-users-api"); /** * The client for interacting with the Donation Alerts API. */ let ApiClient = class ApiClient { /** * Creates a new instance of the API client. * * @param config The configuration options for the API client. * @throws Error if the `authProvider` is not supplied in the configuration. */ constructor(config) { if (!config.authProvider) { throw new Error('No auth provider given. Please supply the `authProvider` option.'); } this._config = config; this._limitReachedBehavior = config.rateLimiterOptions?.limitReachedBehavior ?? 'enqueue'; if (config.rateLimiterOptions?.limitToOneRequestPerSecond ?? true) { this._rateLimiter = new rate_limiter_1.TimedPassthruRateLimiter(new rate_limiter_1.TimeBasedRateLimiter({ timeFrame: 1000, bucketSize: 1, doRequest: async (req) => await (0, api_call_1.callDonationAlertsApiRaw)(req.options, req.accessToken, req.fetchOptions), logger: { minLevel: 'ERROR' }, }), { bucketSize: 60, timeFrame: 60000 }); } else { this._rateLimiter = new rate_limiter_1.TimeBasedRateLimiter({ bucketSize: 60, timeFrame: 60000, doRequest: async (req) => await (0, api_call_1.callDonationAlertsApiRaw)(req.options, req.accessToken, req.fetchOptions), logger: { minLevel: 'ERROR' }, }); } this._logger = (0, logger_1.createLogger)({ context: 'da:api', ...config.logger }); } /** * Users API namespace. * * This namespace allows you to fetch user details, such as information about the authenticated user. */ get users() { return new donation_alerts_users_api_1.DonationAlertsUsersApi(this); } /** * Donations API namespace. * * This namespace provides methods for retrieving donation data. */ get donations() { return new donation_alerts_donations_api_1.DonationAlertsDonationsApi(this); } /** * Custom Alerts API namespace. * * This namespace provides methods for sending custom alerts. */ get customAlerts() { return new donation_alerts_custom_alerts_api_1.DonationAlertsCustomAlertsApi(this); } /** * * Centrifugo API namespace. * * This namespace provides methods for subscribing to Centrifugo channels. */ get centrifugo() { return new donation_alerts_centrifugo_api_1.DonationAlertsCentrifugoApi(this); } /** * Merchandise API namespace. * * This namespace allows managing merchandise-related data. */ get merchandise() { return new donation_alerts_merchandise_api_1.DonationAlertsMerchandiseApi(this); } /** * Sends a request to the Donation Alerts API. * * @param user The ID of the user making the request. * @param options Options for the API call, including method, URL, and other details. * @param rateLimiterOptions Options for fine-tuning rate-limiting behavior. * * @throws {@link HttpError} If the response status code is outside the 200-299 range. * @throws {@link UnregisteredUserError} If the specified user is not registered in the authentication provider. * @throws {@link MissingScopeError} If the access token lacks the required scope to complete the request. */ async callApi(user, options, rateLimiterOptions = {}) { const userId = (0, common_1.extractUserId)(user); const { authProvider } = this._config; const shouldAuth = options.auth ?? true; let accessToken = shouldAuth ? await authProvider.getAccessTokenForUser(userId, options.scope ? [options.scope] : undefined) : null; if (!accessToken) { return await (0, api_call_1.callDonationAlertsApi)(options, undefined, this._config.fetchOptions); } let response = await this._callApiInternal(options, accessToken.accessToken, rateLimiterOptions); if (response.status === 401 && authProvider.refreshAccessTokenForUser) { accessToken = await authProvider.refreshAccessTokenForUser(userId); response = await this._callApiInternal(options, accessToken.accessToken, rateLimiterOptions); } await (0, api_call_1.handleDonationAlertsApiResponseError)(response, options); return await (0, api_call_1.transformDonationAlertsResponse)(response); } async _callApiInternal(options, accessToken, rateLimiterOptions = {}) { const { fetchOptions } = this._config; const type = options.type ?? 'api'; const limitReachedBehavior = rateLimiterOptions.limitReachedBehavior ?? this._limitReachedBehavior; this._logger.debug(`Calling ${type}: ${options.method ?? 'GET'} ${options.url}`); if (options.query) { this._logger.trace(`Query: ${JSON.stringify(options.query)}`); } if (options.jsonBody) { this._logger.trace(`Request JSON body: ${JSON.stringify(options.jsonBody)}`); } if (options.formBody) { this._logger.trace(`Request form body: ${JSON.stringify(options.formBody)}`); } const response = type === 'api' ? await this._rateLimiter.request({ options, accessToken, fetchOptions, }, { limitReachedBehavior }) : await (0, api_call_1.callDonationAlertsApiRaw)(options, accessToken, fetchOptions); this._logger.debug(`Called API: ${options.method ?? 'GET'} ${options.url} - result: ${response.status}`); return response; } }; exports.ApiClient = ApiClient; tslib_1.__decorate([ shared_utils_1.nonenumerable ], ApiClient.prototype, "_config", void 0); tslib_1.__decorate([ shared_utils_1.nonenumerable ], ApiClient.prototype, "_logger", void 0); tslib_1.__decorate([ shared_utils_1.nonenumerable ], ApiClient.prototype, "_rateLimiter", void 0); tslib_1.__decorate([ shared_utils_1.nonenumerable ], ApiClient.prototype, "_limitReachedBehavior", void 0); tslib_1.__decorate([ (0, typescript_memoize_1.Memoize)() ], ApiClient.prototype, "users", null); tslib_1.__decorate([ (0, typescript_memoize_1.Memoize)() ], ApiClient.prototype, "donations", null); tslib_1.__decorate([ (0, typescript_memoize_1.Memoize)() ], ApiClient.prototype, "customAlerts", null); tslib_1.__decorate([ (0, typescript_memoize_1.Memoize)() ], ApiClient.prototype, "centrifugo", null); tslib_1.__decorate([ (0, typescript_memoize_1.Memoize)() ], ApiClient.prototype, "merchandise", null); exports.ApiClient = ApiClient = tslib_1.__decorate([ (0, common_1.ReadDocumentation)('api') ], ApiClient);