Skip to content

Commit

Permalink
feature: Add support for metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
olexandr-mazepa committed Dec 26, 2024
1 parent 28351e1 commit de16ccd
Show file tree
Hide file tree
Showing 17 changed files with 29,659 additions and 6 deletions.
2 changes: 2 additions & 0 deletions dist/Classes/MailgunClient.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { MailgunClientOptions, InputFormData } from '../Types';
import { IDomainsClient, IWebHooksClient, IMailgunClient, IMailingListsClient, IEventClient, IStatsClient, ISuppressionClient, IMessagesClient, IRoutesClient, IValidationClient, IIPsClient, IIPPoolsClient, ISubaccountsClient, IInboxPlacementsClient } from '../Interfaces';
import { IMetricsClient } from '../Interfaces/Metrics/MetricsClient';
export default class MailgunClient implements IMailgunClient {
private request;
domains: IDomainsClient;
webhooks: IWebHooksClient;
events: IEventClient;
stats: IStatsClient;
metrics: IMetricsClient;
suppressions: ISuppressionClient;
messages: IMessagesClient;
routes: IRoutesClient;
Expand Down
13 changes: 13 additions & 0 deletions dist/Classes/Metrics/MetricsClient.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Request from '../common/Request';
import { ILogger } from '../../Interfaces/Common';
import { IMetricsClient } from '../../Interfaces/Metrics/MetricsClient';
import { MetricsQuery, MetricsResult } from '../../Types/Metrics';
export default class MetricsClient implements IMetricsClient {
request: Request;
private logger;
constructor(request: Request, logger?: ILogger);
private convertDateToUTC;
private prepareQuery;
getAccount(query?: MetricsQuery): Promise<MetricsResult>;
getAccountUsage(query?: MetricsQuery): Promise<MetricsResult>;
}
2 changes: 2 additions & 0 deletions dist/Interfaces/MailgunClient/IMailgunClient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import { IIPPoolsClient } from '../IPPools';
import { IMailingListsClient } from '../MailingLists';
import { ISubaccountsClient } from '../Subaccounts';
import { IInboxPlacementsClient } from '../InboxPlacements';
import { IMetricsClient } from '../Metrics/MetricsClient';
export interface IMailgunClient {
domains: IDomainsClient;
webhooks: IWebHooksClient;
events: IEventClient;
stats: IStatsClient;
metrics: IMetricsClient;
suppressions: ISuppressionClient;
messages: IMessagesClient;
routes: IRoutesClient;
Expand Down
5 changes: 5 additions & 0 deletions dist/Interfaces/Metrics/MetricsClient.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { MetricsQuery, MetricsResult } from '../../Types/Metrics';
export interface IMetricsClient {
getAccount(query?: MetricsQuery): Promise<MetricsResult>;
getAccountUsage(query?: MetricsQuery): Promise<MetricsResult>;
}
100 changes: 100 additions & 0 deletions dist/Types/Metrics/Metrics.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Resolution } from '../../Enums';
export type MetricsFilterValue = {
label: string;
value: string;
};
export type MetricsFilter = {
attribute: string;
comparator: string;
values: MetricsFilterValue[];
};
export type MetricsQuery = {
start?: Date;
end?: Date;
resolution?: Resolution;
duration?: string;
dimensions?: string[];
metrics?: string[];
filter?: {
AND: MetricsFilter[];
};
include_subaccounts?: boolean;
include_aggregates?: boolean;
};
export type Metrics = {
accepted_outgoing_count: number;
delivered_smtp_count: number;
accepted_count: number;
delivered_http_count: number;
accepted_incoming_count: number;
delivered_optimized_count: number;
stored_count: number;
delivered_count: number;
processed_count: number;
sent_count: number;
opened_count: number;
unique_opened_count: number;
clicked_count: number;
unique_clicked_count: number;
complained_count: number;
permanent_failed_count: number;
failed_count: number;
rate_limit_count: number;
unsubscribed_count: number;
temporary_failed_count: number;
permanent_failed_optimized_count: number;
bounced_count: number;
esp_block_count: number;
webhook_count: number;
delayed_bounce_count: number;
soft_bounces_count: number;
permanent_failed_old_count: number;
suppressed_bounces_count: number;
delivered_subsequent_count: number;
delivered_rate: string;
delayed_first_attempt_count: number;
unsubscribed_rate: string;
delivered_first_attempt_count: number;
opened_rate: string;
suppressed_complaints_count: number;
delivered_two_plus_attempts_count: number;
hard_bounces_count: number;
suppressed_unsubscribed_count: number;
unique_opened_rate: string;
fail_rate: string;
complained_rate: string;
clicked_rate: string;
unique_clicked_rate: string;
bounce_rate: string;
delayed_rate: string;
permanent_fail_rate: string;
temporary_fail_rate: string;
};
export type MetricsPagination = {
sort: string;
skip: number;
limit: number;
total: number;
};
export type MetricsDimension = {
dimension: string;
value: string;
display_value: string;
};
export type MetricsResponseItem = {
dimensions: MetricsDimension[];
metrics: Metrics;
};
export type MetricsResult = {
items: MetricsResponseItem[];
resolution: string;
start: string;
aggregates: {
metrics: Metrics;
};
dimensions: string[];
pagination: MetricsPagination;
end: string;
duration: string;
status: number;
};
20 changes: 20 additions & 0 deletions dist/Types/Metrics/MetricsAPI.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Metrics, MetricsPagination, MetricsQuery, MetricsResponseItem } from './Metrics';
export type MetricsAPIQuery = Omit<MetricsQuery, 'start' | 'end'> & {
start?: string;
end?: string;
};
export type MetricsAPIResponse = {
status: number;
body: {
items: MetricsResponseItem[];
resolution: string;
start: string;
aggregates: {
metrics: Metrics;
};
dimensions: string[];
pagination: MetricsPagination;
end: string;
duration: string;
};
};
2 changes: 2 additions & 0 deletions dist/Types/Metrics/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Metrics';
export * from './MetricsAPI';
17,023 changes: 17,020 additions & 3 deletions dist/mailgun.node.js

Large diffs are not rendered by default.

12,279 changes: 12,276 additions & 3 deletions dist/mailgun.web.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions lib/Classes/MailgunClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import InboxPlacementsAttributesClient from './InboxPlacements/AttributesClient'
import InboxPlacementsFiltersClient from './InboxPlacements/FiltersClient';
import IPRSharingClient from './InboxPlacements/Results/InboxPlacementsResultsSharingClient';
import InboxPlacementsProvidersClient from './InboxPlacements/providers/InboxPlacementsProviders';
import MetricsClient from './Metrics/MetricsClient';
import { IMetricsClient } from '../Interfaces/Metrics/MetricsClient';

export default class MailgunClient implements IMailgunClient {
private request;
Expand All @@ -51,6 +53,7 @@ export default class MailgunClient implements IMailgunClient {
public webhooks: IWebHooksClient;
public events: IEventClient;
public stats: IStatsClient;
public metrics: IMetricsClient;
public suppressions: ISuppressionClient;
public messages: IMessagesClient;
public routes: IRoutesClient;
Expand Down Expand Up @@ -117,6 +120,7 @@ export default class MailgunClient implements IMailgunClient {
this.webhooks = new WebhooksClient(this.request);
this.events = new EventClient(this.request);
this.stats = new StatsClient(this.request);
this.metrics = new MetricsClient(this.request);
this.suppressions = new SuppressionClient(this.request);
this.messages = new MessagesClient(this.request);
this.routes = new RoutesClient(this.request);
Expand Down
65 changes: 65 additions & 0 deletions lib/Classes/Metrics/MetricsClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import Request from '../common/Request';
import { ILogger } from '../../Interfaces/Common';
import { IMetricsClient } from '../../Interfaces/Metrics/MetricsClient';
import {
MetricsAPIQuery, MetricsAPIResponse, MetricsQuery, MetricsResult
} from '../../Types/Metrics';

export default class MetricsClient implements IMetricsClient {
request: Request;
private logger: ILogger;

constructor(request: Request, logger: ILogger = console) {
this.request = request;
this.logger = logger;
}

private convertDateToUTC(key:string, inputDate: Date): string {
/*
Because "new Date('2022-12-25T00:00:00.000Z')" becomes "Sun Dec 25 2022 02:00:00 GMT+0200"
(plus 2 hours from the timezone)
and because for API, we need to provide the date in the expected format
ex: 'Thu, 13 Oct 2011 18:02:00 +0000'.
Here we try auto-convert them to UTC
*/
this.logger.warn(`Date:"${inputDate}" was auto-converted to UTC time zone.
Value "${inputDate.toUTCString()}" will be used for request.
Consider using string type for property "${key}" to avoid auto-converting`);
return inputDate.toUTCString();
}

private prepareQuery(query: MetricsQuery | undefined): MetricsAPIQuery {
let startDate;
let endDate;
if (query) {
const qStart = query?.start;
const qEnd = query?.end;
startDate = qStart instanceof Date ? this.convertDateToUTC('start', qStart) : qStart ?? '';
endDate = qEnd && qEnd instanceof Date ? this.convertDateToUTC('end', qEnd) : qEnd ?? '';
}
const result: MetricsAPIQuery = {
...query,
start: startDate,
end: endDate
};
return result;
}

async getAccount(query?: MetricsQuery): Promise<MetricsResult> {
const queryData = this.prepareQuery(query);
const response: MetricsAPIResponse = await this.request.post('/v1/analytics/metrics', queryData);
return {
...response.body,
status: response.status
};
}

async getAccountUsage(query?: MetricsQuery): Promise<MetricsResult> {
const queryData = this.prepareQuery(query);
const response: MetricsAPIResponse = await this.request.post('/v1/analytics/usage/metrics', queryData);
return {
...response.body,
status: response.status
};
}
}
2 changes: 2 additions & 0 deletions lib/Interfaces/MailgunClient/IMailgunClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import { IIPPoolsClient } from '../IPPools';
import { IMailingListsClient } from '../MailingLists';
import { ISubaccountsClient } from '../Subaccounts';
import { IInboxPlacementsClient } from '../InboxPlacements';
import { IMetricsClient } from '../Metrics/MetricsClient';

export interface IMailgunClient {
domains: IDomainsClient;
webhooks: IWebHooksClient;
events: IEventClient;
stats: IStatsClient;
metrics: IMetricsClient;
suppressions: ISuppressionClient;
messages: IMessagesClient;
routes: IRoutesClient;
Expand Down
6 changes: 6 additions & 0 deletions lib/Interfaces/Metrics/MetricsClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { MetricsQuery, MetricsResult } from '../../Types/Metrics';

export interface IMetricsClient {
getAccount(query?: MetricsQuery): Promise<MetricsResult>
getAccountUsage(query?: MetricsQuery): Promise<MetricsResult>
}
108 changes: 108 additions & 0 deletions lib/Types/Metrics/Metrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* eslint-disable camelcase */
import { Resolution } from '../../Enums';

export type MetricsFilterValue = {
label: string;
value: string;
}
export type MetricsFilter = {
attribute: string;
comparator: string;
values: MetricsFilterValue[];
}

export type MetricsQuery = {
start?: Date | string;
end?: Date | string;
resolution?: Resolution;
duration?: string;
dimensions?: string[];
metrics?: string[];
filter?: {
AND: MetricsFilter[];
}
include_subaccounts?: boolean;
include_aggregates?: boolean;
}

export type Metrics = {
accepted_outgoing_count?: number;
delivered_smtp_count?: number;
accepted_count?: number;
delivered_http_count?: number;
accepted_incoming_count?: number;
delivered_optimized_count?: number;
stored_count?: number;
delivered_count?: number;
processed_count?: number;
sent_count?: number;
opened_count?: number;
unique_opened_count?: number;
clicked_count?: number;
unique_clicked_count?: number;
complained_count?: number;
permanent_failed_count?: number;
failed_count?: number;
rate_limit_count?: number;
unsubscribed_count?: number;
temporary_failed_count?: number;
permanent_failed_optimized_count?: number;
bounced_count?: number;
esp_block_count?: number;
webhook_count?: number;
delayed_bounce_count?: number;
soft_bounces_count?: number;
permanent_failed_old_count?: number;
suppressed_bounces_count?: number;
delivered_subsequent_count?: number;
delivered_rate?: string;
delayed_first_attempt_count?: number;
unsubscribed_rate?: string;
delivered_first_attempt_count?: number;
opened_rate?: string;
suppressed_complaints_count?: number;
delivered_two_plus_attempts_count?: number;
hard_bounces_count?: number;
suppressed_unsubscribed_count?: number;
unique_opened_rate?: string;
fail_rate?: string;
complained_rate?: string;
clicked_rate?: string;
unique_clicked_rate?: string;
bounce_rate?: string;
delayed_rate?: string;
permanent_fail_rate?: string;
temporary_fail_rate?: string;
}

export type MetricsPagination = {
sort: string;
skip: number;
limit: number;
total: number;
}

export type MetricsDimension = {
dimension: string;
value: string;
display_value: string;
}

export type MetricsResponseItem = {
dimensions: MetricsDimension[];
metrics: Metrics;
}

export type MetricsResult = {
items: MetricsResponseItem[];
resolution: string;
start: string;
aggregates: {
metrics: Metrics;
}
dimensions: string[];
pagination: MetricsPagination;
end: string;
duration: string;
status: number;
}
Loading

0 comments on commit de16ccd

Please sign in to comment.