Skip to content

Commit

Permalink
PLT-1397 Some documentation and variable refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
rlajous committed Sep 13, 2023
1 parent d27144e commit afe804d
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 24 deletions.
4 changes: 2 additions & 2 deletions packages/drops/src/DropsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
PaginatedResult,
nextCursor,
creatPrivateFilter,
creatUndefinedOrder,
createUndefinedOrder,
createBetweenFilter,
createFilter,
createInFilter,
Expand Down Expand Up @@ -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),
Expand Down
19 changes: 10 additions & 9 deletions packages/poaps/src/PoapsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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<string>} A unique queue ID for the initiated claim.
*/
async claimAsync(input: WalletClaimtInput): Promise<string> {
async claimAsync(input: WalletClaimInput): Promise<string> {
const secret = await this.getCodeSecret(input.qr_hash);

const response = await this.tokensApiProvider.postClaimCode({
Expand All @@ -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<POAP>} The related POAP upon successful claim completion.
* @param {WalletClaimInput} input - Details needed for the claim.
* @returns {Promise<POAP>} The associated POAP upon successful claim completion.
* @throws {FinishedWithError} If there's an error concluding the claim process.
*/
async claimSync(input: WalletClaimtInput): Promise<POAP> {
async claimSync(input: WalletClaimInput): Promise<POAP> {
const queue_uid = await this.claimAsync(input);

await this.waitClaimStatus(queue_uid);
Expand Down
40 changes: 39 additions & 1 deletion packages/poaps/src/types/input.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
37 changes: 37 additions & 0 deletions packages/poaps/src/utils/ClaimChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>} callback - The callback function to retry.
*/
private backoffAndRetry(callback: () => Promise<void>): void {
if (this.retries >= MAX_RETRIES) {
throw new Error('Max retries reached');
Expand All @@ -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 &&
Expand All @@ -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<void>} A promise that resolves once the status has been checked.
*/
public async checkClaimStatus(): Promise<void> {
try {
const claimStatusResponse = await this.tokensApiProvider.claimStatus(
Expand Down
24 changes: 24 additions & 0 deletions packages/poaps/src/utils/PoapIndexed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<GetClaimCodeResponse>} callback - The callback function to retry.
* @returns {Promise<GetClaimCodeResponse>} The response of the callback function.
*/
private async backoffAndRetry(
callback: () => Promise<GetClaimCodeResponse>,
): Promise<GetClaimCodeResponse> {
Expand All @@ -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<GetClaimCodeResponse>} A promise that resolves with the indexed token's claim code response.
*/
public async waitPoapIndexed(): Promise<GetClaimCodeResponse> {
let response = await this.tokensApiProvider.getClaimCode(this.qr_hash);
while (response.result == null) {
Expand Down
62 changes: 52 additions & 10 deletions packages/providers/src/core/PoapTokenApi/PoapTokenApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<GetClaimCodeResponse>} Details of the claim code.
*/
async getClaimCode(code: string): Promise<GetClaimCodeResponse> {
return await this.secureFetch<GetClaimCodeResponse>(
`${this.baseUrl}/actions/claim-qr?qr_hash=${code}`,
Expand All @@ -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<PostClaimCodeResponse>} Response from the claim code creation.
*/
async postClaimCode(input: ClaimCodeInput): Promise<PostClaimCodeResponse> {
return await this.secureFetch<PostClaimCodeResponse>(
`${this.baseUrl}/actions/claim-qr`,
Expand All @@ -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<ClaimStatusResponse>} Status details of the claim.
*/
async claimStatus(uid: string): Promise<ClaimStatusResponse> {
return await this.secureFetch<ClaimStatusResponse>(
`${this.baseUrl}/queue-message/${uid}`,
Expand All @@ -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<R>} 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<R>} A promise that resolves with the parsed API response.
*/
private async secureFetch<R>(url: string, options: any): Promise<R> {
const headersWithApiKey = {
Expand All @@ -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<string>} The bearer token for authentication.
*/
private async getAuthorizationToken(): Promise<string> {
if (!this.authenticationProvider) {
throw new MissingAuthenticationProviderError();
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export { PaginatedResult } from './types/pagination';
export { nextCursor } from './functions/nextCursor';
export {
filterUndefinedProperties,
creatUndefinedOrder,
createUndefinedOrder,
createFilter,
creatEqFilter,
creatNeqFilter,
Expand Down
Loading

0 comments on commit afe804d

Please sign in to comment.