@donation-alerts/api
Version:
Interact with Donation Alerts API.
176 lines (175 loc) • 7.81 kB
JavaScript
;
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);