mirror of
https://github.com/LukeHagar/usage-statistics.git
synced 2025-12-06 04:21:55 +00:00
286 lines
7.3 KiB
TypeScript
286 lines
7.3 KiB
TypeScript
/**
|
|
* Postman Collection Download/Fork Tracker
|
|
* Uses Postman API to fetch collection statistics
|
|
*/
|
|
|
|
import type { BaseDownloadStats, PlatformTracker } from '../types';
|
|
|
|
export interface PostmanDownloadStats extends BaseDownloadStats {
|
|
platform: 'postman';
|
|
collectionId: string;
|
|
collectionName: string;
|
|
version: string;
|
|
forkCount: number;
|
|
downloadCount: number;
|
|
viewCount: number;
|
|
author: string;
|
|
publishedDate: Date;
|
|
}
|
|
|
|
export interface PostmanCollectionInfo {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
version: string;
|
|
author: {
|
|
id: string;
|
|
name: string;
|
|
username: string;
|
|
};
|
|
publishedAt: string;
|
|
updatedAt: string;
|
|
forkCount: number;
|
|
downloadCount: number;
|
|
viewCount: number;
|
|
schema: string;
|
|
info: {
|
|
name: string;
|
|
description?: string;
|
|
version: string;
|
|
schema: string;
|
|
};
|
|
item: any[];
|
|
variable: any[];
|
|
}
|
|
|
|
export interface PostmanWorkspaceInfo {
|
|
id: string;
|
|
name: string;
|
|
type: 'personal' | 'team' | 'private';
|
|
description?: string;
|
|
collections: PostmanCollectionInfo[];
|
|
}
|
|
|
|
export class PostmanTracker implements PlatformTracker {
|
|
name = 'postman';
|
|
private baseUrl = 'https://api.getpostman.com';
|
|
private apiKey?: string;
|
|
|
|
constructor(apiKey?: string) {
|
|
this.apiKey = apiKey;
|
|
}
|
|
|
|
async getDownloadStats(collectionId: string, options?: {
|
|
version?: string;
|
|
startDate?: Date;
|
|
endDate?: Date;
|
|
}): Promise<PostmanDownloadStats[]> {
|
|
try {
|
|
const collectionInfo = await this.getPackageInfo(collectionId);
|
|
const stats: PostmanDownloadStats[] = [];
|
|
|
|
// Get collection versions if available
|
|
const versions = await this.getCollectionVersions(collectionId);
|
|
|
|
for (const version of versions) {
|
|
if (options?.version && version.version !== options.version) {
|
|
continue;
|
|
}
|
|
|
|
const publishedDate = new Date(version.publishedAt);
|
|
|
|
// Filter by date range if specified
|
|
if (options?.startDate && publishedDate < options.startDate) {
|
|
continue;
|
|
}
|
|
if (options?.endDate && publishedDate > options.endDate) {
|
|
continue;
|
|
}
|
|
|
|
stats.push({
|
|
platform: 'postman',
|
|
packageName: collectionId,
|
|
collectionId,
|
|
collectionName: version.name,
|
|
version: version.version,
|
|
forkCount: version.forkCount || 0,
|
|
downloadCount: version.downloadCount || 0,
|
|
viewCount: version.viewCount || 0,
|
|
author: version.author?.name || 'Unknown',
|
|
publishedDate,
|
|
metadata: {
|
|
authorId: version.author?.id,
|
|
authorUsername: version.author?.username,
|
|
schema: version.schema,
|
|
itemCount: version.item?.length || 0
|
|
}
|
|
});
|
|
}
|
|
|
|
return stats;
|
|
} catch (error) {
|
|
console.error(`Error fetching Postman stats for ${collectionId}:`, error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
async getLatestVersion(collectionId: string): Promise<string | null> {
|
|
try {
|
|
const collectionInfo = await this.getPackageInfo(collectionId);
|
|
return collectionInfo.version || null;
|
|
} catch (error) {
|
|
console.error(`Error fetching latest version for ${collectionId}:`, error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async getPackageInfo(collectionId: string): Promise<PostmanCollectionInfo> {
|
|
const headers: Record<string, string> = {
|
|
'Accept': 'application/json'
|
|
};
|
|
|
|
if (this.apiKey) {
|
|
headers['X-API-Key'] = this.apiKey;
|
|
}
|
|
|
|
const response = await fetch(`${this.baseUrl}/collections/${collectionId}`, {
|
|
headers
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch collection info for ${collectionId}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
async getCollectionVersions(collectionId: string): Promise<PostmanCollectionInfo[]> {
|
|
try {
|
|
const headers: Record<string, string> = {
|
|
'Accept': 'application/json'
|
|
};
|
|
|
|
if (this.apiKey) {
|
|
headers['X-API-Key'] = this.apiKey;
|
|
}
|
|
|
|
const response = await fetch(`${this.baseUrl}/collections/${collectionId}/versions`, {
|
|
headers
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch versions for ${collectionId}`);
|
|
}
|
|
|
|
return response.json();
|
|
} catch (error) {
|
|
console.error(`Error fetching versions for ${collectionId}:`, error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
async searchCollections(query: string, options?: {
|
|
workspaceId?: string;
|
|
limit?: number;
|
|
offset?: number;
|
|
}): Promise<{
|
|
collections: PostmanCollectionInfo[];
|
|
totalCount: number;
|
|
}> {
|
|
try {
|
|
const headers: Record<string, string> = {
|
|
'Accept': 'application/json'
|
|
};
|
|
|
|
if (this.apiKey) {
|
|
headers['X-API-Key'] = this.apiKey;
|
|
}
|
|
|
|
const params = new URLSearchParams({
|
|
q: query,
|
|
limit: (options?.limit || 50).toString(),
|
|
offset: (options?.offset || 0).toString()
|
|
});
|
|
|
|
if (options?.workspaceId) {
|
|
params.set('workspace', options.workspaceId);
|
|
}
|
|
|
|
const response = await fetch(`${this.baseUrl}/search?${params}`, {
|
|
headers
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to search collections');
|
|
}
|
|
|
|
return response.json();
|
|
} catch (error) {
|
|
console.error('Error searching collections:', error);
|
|
return {
|
|
collections: [],
|
|
totalCount: 0
|
|
};
|
|
}
|
|
}
|
|
|
|
async getWorkspaceCollections(workspaceId: string): Promise<PostmanCollectionInfo[]> {
|
|
try {
|
|
const headers: Record<string, string> = {
|
|
'Accept': 'application/json'
|
|
};
|
|
|
|
if (this.apiKey) {
|
|
headers['X-API-Key'] = this.apiKey;
|
|
}
|
|
|
|
const response = await fetch(`${this.baseUrl}/workspaces/${workspaceId}/collections`, {
|
|
headers
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch workspace collections for ${workspaceId}`);
|
|
}
|
|
|
|
return response.json();
|
|
} catch (error) {
|
|
console.error(`Error fetching workspace collections for ${workspaceId}:`, error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
async getCollectionAnalytics(collectionId: string): Promise<{
|
|
totalDownloads: number;
|
|
totalForks: number;
|
|
totalViews: number;
|
|
downloadsByVersion: Record<string, number>;
|
|
forksByVersion: Record<string, number>;
|
|
}> {
|
|
try {
|
|
const versions = await this.getCollectionVersions(collectionId);
|
|
|
|
const downloadsByVersion: Record<string, number> = {};
|
|
const forksByVersion: Record<string, number> = {};
|
|
let totalDownloads = 0;
|
|
let totalForks = 0;
|
|
let totalViews = 0;
|
|
|
|
for (const version of versions) {
|
|
downloadsByVersion[version.version] = version.downloadCount || 0;
|
|
forksByVersion[version.version] = version.forkCount || 0;
|
|
totalDownloads += version.downloadCount || 0;
|
|
totalForks += version.forkCount || 0;
|
|
totalViews += version.viewCount || 0;
|
|
}
|
|
|
|
return {
|
|
totalDownloads,
|
|
totalForks,
|
|
totalViews,
|
|
downloadsByVersion,
|
|
forksByVersion
|
|
};
|
|
} catch (error) {
|
|
console.error(`Error fetching analytics for ${collectionId}:`, error);
|
|
return {
|
|
totalDownloads: 0,
|
|
totalForks: 0,
|
|
totalViews: 0,
|
|
downloadsByVersion: {},
|
|
forksByVersion: {}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
export default PostmanTracker;
|