From afe804d271fb78b498a8ff05e072d371319afa3b Mon Sep 17 00:00:00 2001 From: rlajous Date: Wed, 13 Sep 2023 12:00:02 +0200 Subject: [PATCH] PLT-1397 Some documentation and variable refactor --- packages/drops/src/DropsClient.ts | 4 +- packages/poaps/src/PoapsClient.ts | 19 +++--- packages/poaps/src/types/input.ts | 40 +++++++++++- packages/poaps/src/utils/ClaimChecker.ts | 37 +++++++++++ packages/poaps/src/utils/PoapIndexed.ts | 24 +++++++ .../src/core/PoapTokenApi/PoapTokenApi.ts | 62 ++++++++++++++++--- packages/utils/src/index.ts | 2 +- packages/utils/src/queries/utils.ts | 2 +- 8 files changed, 166 insertions(+), 24 deletions(-) diff --git a/packages/drops/src/DropsClient.ts b/packages/drops/src/DropsClient.ts index 8a0b6246..bc8fbd00 100644 --- a/packages/drops/src/DropsClient.ts +++ b/packages/drops/src/DropsClient.ts @@ -10,7 +10,7 @@ import { PaginatedResult, nextCursor, creatPrivateFilter, - creatUndefinedOrder, + createUndefinedOrder, createBetweenFilter, createFilter, createInFilter, @@ -58,7 +58,7 @@ export class DropsClient { const variables = { limit, offset, - orderBy: creatUndefinedOrder(sort_field, sort_dir), + orderBy: createUndefinedOrder(sort_field, sort_dir), where: { ...creatPrivateFilter('private', is_private), ...createFilter('name', name), diff --git a/packages/poaps/src/PoapsClient.ts b/packages/poaps/src/PoapsClient.ts index fc66076b..73045f43 100644 --- a/packages/poaps/src/PoapsClient.ts +++ b/packages/poaps/src/PoapsClient.ts @@ -6,14 +6,14 @@ import { import { POAP } from './domain/Poap'; import { POAPReservation } from './domain/POAPReservation'; import { PaginatedPoapsResponse, PAGINATED_POAPS_QUERY } from './queries'; -import { FetchPoapsInput, EmailClaimtInput, WalletClaimtInput } from './types'; +import { FetchPoapsInput, EmailClaimtInput, WalletClaimInput } from './types'; import { PaginatedResult, nextCursor, createBetweenFilter, creatEqFilter, createInFilter, - creatUndefinedOrder, + createUndefinedOrder, creatAddressFilter, MintingStatus, } from '@poap-xyz/utils'; @@ -61,7 +61,7 @@ export class PoapsClient { const variables = { limit, offset, - orderBy: creatUndefinedOrder(sort_field, sort_dir), + orderBy: createUndefinedOrder(sort_field, sort_dir), where: { ...creatAddressFilter( 'collector_address', @@ -169,10 +169,10 @@ export class PoapsClient { /** * Begins an asynchronous claim process and provides a unique queue ID in return. * @async - * @param {WalletClaimtInput} input - Details required for the claim. + * @param {WalletClaimInput} input - Details required for the claim. * @returns {Promise} A unique queue ID for the initiated claim. */ - async claimAsync(input: WalletClaimtInput): Promise { + async claimAsync(input: WalletClaimInput): Promise { const secret = await this.getCodeSecret(input.qr_hash); const response = await this.tokensApiProvider.postClaimCode({ @@ -187,13 +187,14 @@ export class PoapsClient { /** * Starts a synchronous claim process. The method waits for the claim to be processed and then - * fetches the associated POAP. + * fetches the associated POAP. It combines the asynchronous claim and subsequent status checking + * into a synchronous process for ease of use. * @async - * @param {WalletClaimtInput} input - Details needed for the claim. - * @returns {Promise} The related POAP upon successful claim completion. + * @param {WalletClaimInput} input - Details needed for the claim. + * @returns {Promise} The associated POAP upon successful claim completion. * @throws {FinishedWithError} If there's an error concluding the claim process. */ - async claimSync(input: WalletClaimtInput): Promise { + async claimSync(input: WalletClaimInput): Promise { const queue_uid = await this.claimAsync(input); await this.waitClaimStatus(queue_uid); diff --git a/packages/poaps/src/types/input.ts b/packages/poaps/src/types/input.ts index 4e974abd..c242ec07 100644 --- a/packages/poaps/src/types/input.ts +++ b/packages/poaps/src/types/input.ts @@ -1,28 +1,66 @@ import { Order, Chain, PaginationInput } from '@poap-xyz/utils'; +/** + * Enum to define available fields for sorting Poaps. + * + * @export + * @enum {string} + */ export enum PoapsSortFields { + /** Represents sorting by the date when a Poap was minted. */ MintedOn = 'minted_on', + /** Represents sorting by the ID of a Poap. */ Id = 'id', } +/** + * Represents the input fields for fetching Poaps. + * This interface extends `PaginationInput` to provide pagination capability. + * + * @export + * @interface FetchPoapsInput + * @extends {PaginationInput} + */ export interface FetchPoapsInput extends PaginationInput { + /** Optional filter for the name of a Poap. */ name?: string; + /** Optional filter for the blockchain chain of a Poap. */ chain?: Chain; + /** Optional filter for the start date when a Poap was minted. */ minted_date_from?: string; + /** Optional filter for the end date when a Poap was minted. */ minted_date_to?: string; + /** Optional filter for specific Poap IDs. */ ids?: number[]; + /** Optional filter for the collector's address. */ collector_address?: string; + /** Optional filter for a specific drop ID. */ drop_id?: number; + /** Field by which to sort the results. */ sort_field?: PoapsSortFields; + /** Direction in which to sort the results. */ sort_dir?: Order; + /** Filter to include/exclude Poaps with zero addresses. */ filter_by_zero_address?: boolean; } -export interface WalletClaimtInput { +/** + * Represents the input fields required to claim a Poap for a wallet. + * + * @export + * @interface WalletClaimInput + */ +export interface WalletClaimInput { qr_hash: string; address: string; } +/** + * Represents the input fields required to claim a Poap via email. + * + * @export + * @interface EmailClaimtInput + */ export interface EmailClaimtInput { qr_hash: string; email: string; diff --git a/packages/poaps/src/utils/ClaimChecker.ts b/packages/poaps/src/utils/ClaimChecker.ts index 1df1a9ba..9c7a6f37 100644 --- a/packages/poaps/src/utils/ClaimChecker.ts +++ b/packages/poaps/src/utils/ClaimChecker.ts @@ -6,17 +6,33 @@ const MAX_RETRIES = 20; const INITIAL_DELAY = 1000; const BACKOFF_FACTOR = 1.2; +/** + * A utility class designed to continually check the status of a Poap token claim. + * If a claim is still pending or in process, it implements a backoff retry mechanism. + */ export class ClaimChecker { private retries = 0; private delay: number = INITIAL_DELAY; private queue_uid: string; private tokensApiProvider: TokensApiProvider; + /** + * Initializes a new instance of the `ClaimChecker` class. + * + * @param {string} queue_uid - The unique identifier for the token claim. + * @param {TokensApiProvider} tokensApiProvider - The provider to fetch the claim status. + */ constructor(queue_uid: string, tokensApiProvider: TokensApiProvider) { this.queue_uid = queue_uid; this.tokensApiProvider = tokensApiProvider; } + /** + * Delays the callback function based on a delay that increases after each retry. + * + * @private + * @param {() => Promise} callback - The callback function to retry. + */ private backoffAndRetry(callback: () => Promise): void { if (this.retries >= MAX_RETRIES) { throw new Error('Max retries reached'); @@ -30,12 +46,26 @@ export class ClaimChecker { }, this.delay); // Wrap the callback invocation } + /** + * Determines if a retry should occur based on the minting status. + * + * @private + * @param {MintingStatus} status - The current minting status. + * @returns {boolean} `true` if should retry, otherwise `false`. + */ private shouldRetry(status: MintingStatus): boolean { return ( status === MintingStatus.IN_PROCESS || status === MintingStatus.PENDING ); } + /** + * Handles errors from the claim status response. + * Throws an error if the minting process finished with an error. + * + * @private + * @param {ClaimStatusResponse} claimStatusResponse - The response from the claim status check. + */ private handleErrorStatus(claimStatusResponse: ClaimStatusResponse): void { if ( claimStatusResponse.status === MintingStatus.FINISH_WITH_ERROR && @@ -45,6 +75,13 @@ export class ClaimChecker { } } + /** + * Checks the current status of a token claim. + * Retries the check with an increased delay if the claim is still pending or in process. + * + * @public + * @returns {Promise} A promise that resolves once the status has been checked. + */ public async checkClaimStatus(): Promise { try { const claimStatusResponse = await this.tokensApiProvider.claimStatus( diff --git a/packages/poaps/src/utils/PoapIndexed.ts b/packages/poaps/src/utils/PoapIndexed.ts index 011f5a83..cf695760 100644 --- a/packages/poaps/src/utils/PoapIndexed.ts +++ b/packages/poaps/src/utils/PoapIndexed.ts @@ -4,17 +4,34 @@ const MAX_RETRIES = 20; const INITIAL_DELAY = 1000; const BACKOFF_FACTOR = 1.2; +/** + * A utility class designed to periodically check if a POAP (Proof of Attendance Protocol) token is indexed. + * It implements a backoff retry mechanism if the token hasn't been indexed yet. + */ export class PoapIndexed { private retries = 0; private delay: number = INITIAL_DELAY; private qr_hash: string; private tokensApiProvider: TokensApiProvider; + /** + * Initializes a new instance of the `PoapIndexed` class. + * + * @param {string} qr_hash - The unique QR hash of the token. + * @param {TokensApiProvider} tokensApiProvider - The provider to check if the token is indexed. + */ constructor(qr_hash: string, tokensApiProvider: TokensApiProvider) { this.qr_hash = qr_hash; this.tokensApiProvider = tokensApiProvider; } + /** + * Delays the callback function based on a delay that increases after each retry. + * + * @private + * @param {() => Promise} callback - The callback function to retry. + * @returns {Promise} The response of the callback function. + */ private async backoffAndRetry( callback: () => Promise, ): Promise { @@ -28,6 +45,13 @@ export class PoapIndexed { return callback(); } + /** + * Continuously checks if a POAP token is indexed. + * It will keep retrying based on a delay that increases each time until the token is indexed or max retries are reached. + * + * @public + * @returns {Promise} A promise that resolves with the indexed token's claim code response. + */ public async waitPoapIndexed(): Promise { let response = await this.tokensApiProvider.getClaimCode(this.qr_hash); while (response.result == null) { diff --git a/packages/providers/src/core/PoapTokenApi/PoapTokenApi.ts b/packages/providers/src/core/PoapTokenApi/PoapTokenApi.ts index 008d2186..0bafa321 100644 --- a/packages/providers/src/core/PoapTokenApi/PoapTokenApi.ts +++ b/packages/providers/src/core/PoapTokenApi/PoapTokenApi.ts @@ -15,16 +15,26 @@ const instance = axios.create({ }); const DEFAULT_DROP_BASE_URL = 'https://api.poap.tech'; - +/** + * Represents the main interface to interact with the Poap Drop API. + * + * @export + * @class PoapTokenApi + * @implements {TokensApiProvider} + */ export class PoapTokenApi implements TokensApiProvider { private apiKey: string; private baseUrl: string; private authenticationProvider?: AuthenticationProvider; + /** - * Creates a new instance of the `PoapDropApi` class. + * Constructs a new instance of the `PoapTokenApi` class. * * @constructor - * @param {string} apiKey - The API key to use for requests. + * @param {PoapTokenApiOptions} options - Configuration options for the API. + * @param {string} options.apiKey - The API key for authenticating requests. + * @param {string} [options.baseUrl=DEFAULT_DROP_BASE_URL] - The base URL for the API. + * @param {AuthenticationProvider} [options.authenticationProvider] - Optional provider for JWT authentication. */ constructor({ apiKey, @@ -36,6 +46,12 @@ export class PoapTokenApi implements TokensApiProvider { this.authenticationProvider = authenticationProvider; } + /** + * Retrieves the claim code details. + * + * @param {string} code - The unique QR hash for the claim. + * @returns {Promise} Details of the claim code. + */ async getClaimCode(code: string): Promise { return await this.secureFetch( `${this.baseUrl}/actions/claim-qr?qr_hash=${code}`, @@ -46,6 +62,12 @@ export class PoapTokenApi implements TokensApiProvider { ); } + /** + * Posts a new claim code to the API. + * + * @param {ClaimCodeInput} input - The input data for the claim code. + * @returns {Promise} Response from the claim code creation. + */ async postClaimCode(input: ClaimCodeInput): Promise { return await this.secureFetch( `${this.baseUrl}/actions/claim-qr`, @@ -57,6 +79,12 @@ export class PoapTokenApi implements TokensApiProvider { ); } + /** + * Checks the status of a claim by its unique identifier. + * + * @param {string} uid - The unique identifier for the claim. + * @returns {Promise} Status details of the claim. + */ async claimStatus(uid: string): Promise { return await this.secureFetch( `${this.baseUrl}/queue-message/${uid}`, @@ -68,15 +96,13 @@ export class PoapTokenApi implements TokensApiProvider { } /** - * Sends a secure HTTP request to the Poap Drop API. + * Sends a secure HTTP request to the Poap Drop API with proper headers. * - * @async * @private - * @function - * @name PoapDropApi#secureFetch - * @param {string} url - The URL for the HTTP request. - * @param {any} options - The options for the HTTP request. - * @returns {Promise} A Promise that resolves with the response from the API. + * @template R - Type of the expected response data. + * @param {string} url - The complete URL for the HTTP request. + * @param {any} options - Configuration options for the HTTP request. + * @returns {Promise} A promise that resolves with the parsed API response. */ private async secureFetch(url: string, options: any): Promise { const headersWithApiKey = { @@ -94,6 +120,13 @@ export class PoapTokenApi implements TokensApiProvider { ).data; } + /** + * Retrieves the authorization token for making authenticated requests. + * + * @private + * @throws {MissingAuthenticationProviderError} If no authentication provider is provided. + * @returns {Promise} The bearer token for authentication. + */ private async getAuthorizationToken(): Promise { if (!this.authenticationProvider) { throw new MissingAuthenticationProviderError(); @@ -102,6 +135,15 @@ export class PoapTokenApi implements TokensApiProvider { } } +/** + * Represents the configuration options required when instantiating the `PoapTokenApi` class. + * + * @export + * @interface PoapTokenApiOptions + * @property {string} apiKey - The API key to use for authenticating requests. + * @property {string} [baseUrl] - The base URL for the API. Defaults to 'https://api.poap.tech'. + * @property {AuthenticationProvider} [authenticationProvider] - Optional provider for JWT authentication. + */ export interface PoapTokenApiOptions { apiKey: string; baseUrl?: string; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index df04373d..adf3092c 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -7,7 +7,7 @@ export { PaginatedResult } from './types/pagination'; export { nextCursor } from './functions/nextCursor'; export { filterUndefinedProperties, - creatUndefinedOrder, + createUndefinedOrder, createFilter, creatEqFilter, creatNeqFilter, diff --git a/packages/utils/src/queries/utils.ts b/packages/utils/src/queries/utils.ts index 4ed553ef..fb9502cd 100644 --- a/packages/utils/src/queries/utils.ts +++ b/packages/utils/src/queries/utils.ts @@ -11,7 +11,7 @@ export function filterUndefinedProperties>( return filteredObj; } -export function creatUndefinedOrder( +export function createUndefinedOrder( key: string | undefined, value?: string | undefined, ): Record {