🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@power-seo/integrations

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@power-seo/integrations - npm Package Compare versions

Comparing version
1.0.0
to
1.0.1
+1
-1
dist/index.cjs.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/types.ts","../src/http.ts","../src/semrush/endpoints.ts","../src/semrush/client.ts","../src/ahrefs/endpoints.ts","../src/ahrefs/client.ts"],"names":["createTokenBucket","getWaitTime","sleep","consumeToken","organicKeywordsPath","backlinksPath","keywordDifficultyPath","buildOrganicKeywordsParams","buildBacklinksParams","buildKeywordDifficultyParams","DEFAULT_LIMIT"],"mappings":"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","file":"index.cjs","sourcesContent":["// ============================================================================\r\n// @power-seo/integrations — Types\r\n// ============================================================================\r\n\r\n// --- HTTP Client Types ---\r\n\r\nexport type AuthStrategy =\r\n | { type: 'query'; paramName: string; value: string }\r\n | { type: 'bearer'; token: string };\r\n\r\nexport interface HttpClientConfig {\r\n baseUrl: string;\r\n auth: AuthStrategy;\r\n rateLimitPerMinute?: number;\r\n maxRetries?: number;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface HttpClient {\r\n get: <T>(path: string, params?: Record<string, string>) => Promise<T>;\r\n post: <T>(path: string, body?: unknown) => Promise<T>;\r\n}\r\n\r\n// --- Error ---\r\n\r\nexport class IntegrationApiError extends Error {\r\n readonly status: number;\r\n readonly provider: string;\r\n readonly retryable: boolean;\r\n\r\n constructor(message: string, status: number, provider: string) {\r\n super(message);\r\n this.name = 'IntegrationApiError';\r\n this.status = status;\r\n this.provider = provider;\r\n this.retryable = status === 429 || status >= 500;\r\n }\r\n}\r\n\r\n// --- Pagination ---\r\n\r\nexport interface PaginatedResponse<T> {\r\n data: T[];\r\n total: number;\r\n offset: number;\r\n limit: number;\r\n hasMore: boolean;\r\n}\r\n\r\n// --- Semrush Types ---\r\n\r\nexport interface SemrushDomainOverview {\r\n domain: string;\r\n organicKeywords: number;\r\n organicTraffic: number;\r\n organicCost: number;\r\n paidKeywords: number;\r\n paidTraffic: number;\r\n paidCost: number;\r\n backlinks: number;\r\n authorityScore: number;\r\n}\r\n\r\nexport interface SemrushKeywordData {\r\n keyword: string;\r\n position: number;\r\n previousPosition: number;\r\n searchVolume: number;\r\n cpc: number;\r\n url: string;\r\n traffic: number;\r\n trafficPercent: number;\r\n trafficCost: number;\r\n competition: number;\r\n}\r\n\r\nexport interface SemrushBacklinkData {\r\n sourceUrl: string;\r\n targetUrl: string;\r\n anchorText: string;\r\n isNoFollow: boolean;\r\n firstSeen: string;\r\n lastSeen: string;\r\n sourceAuthorityScore: number;\r\n}\r\n\r\nexport interface SemrushKeywordDifficulty {\r\n keyword: string;\r\n difficulty: number;\r\n searchVolume: number;\r\n cpc: number;\r\n competition: number;\r\n results: number;\r\n}\r\n\r\nexport interface SemrushRelatedKeyword {\r\n keyword: string;\r\n searchVolume: number;\r\n cpc: number;\r\n competition: number;\r\n results: number;\r\n relatedTo: string;\r\n}\r\n\r\nexport interface SemrushClient {\r\n getDomainOverview: (domain: string, database?: string) => Promise<SemrushDomainOverview>;\r\n getOrganicKeywords: (domain: string, options?: SemrushPaginationOptions) => Promise<PaginatedResponse<SemrushKeywordData>>;\r\n getBacklinks: (domain: string, options?: SemrushPaginationOptions) => Promise<PaginatedResponse<SemrushBacklinkData>>;\r\n getKeywordDifficulty: (keywords: string[], database?: string) => Promise<SemrushKeywordDifficulty[]>;\r\n getRelatedKeywords: (keyword: string, database?: string) => Promise<SemrushRelatedKeyword[]>;\r\n}\r\n\r\nexport interface SemrushPaginationOptions {\r\n limit?: number;\r\n offset?: number;\r\n database?: string;\r\n}\r\n\r\n// --- Ahrefs Types ---\r\n\r\nexport interface AhrefsSiteOverview {\r\n domain: string;\r\n domainRating: number;\r\n urlRating: number;\r\n backlinks: number;\r\n referringDomains: number;\r\n organicKeywords: number;\r\n organicTraffic: number;\r\n trafficValue: number;\r\n}\r\n\r\nexport interface AhrefsOrganicKeyword {\r\n keyword: string;\r\n position: number;\r\n searchVolume: number;\r\n cpc: number;\r\n url: string;\r\n traffic: number;\r\n trafficPercent: number;\r\n difficulty: number;\r\n}\r\n\r\nexport interface AhrefsBacklink {\r\n sourceUrl: string;\r\n targetUrl: string;\r\n anchorText: string;\r\n domainRating: number;\r\n urlRating: number;\r\n isDoFollow: boolean;\r\n firstSeen: string;\r\n lastSeen: string;\r\n}\r\n\r\nexport interface AhrefsKeywordDifficulty {\r\n keyword: string;\r\n difficulty: number;\r\n searchVolume: number;\r\n cpc: number;\r\n clicks: number;\r\n globalVolume: number;\r\n}\r\n\r\nexport interface AhrefsReferringDomain {\r\n domain: string;\r\n domainRating: number;\r\n backlinks: number;\r\n firstSeen: string;\r\n lastSeen: string;\r\n isDoFollow: boolean;\r\n}\r\n\r\nexport interface AhrefsClient {\r\n getSiteOverview: (domain: string) => Promise<AhrefsSiteOverview>;\r\n getOrganicKeywords: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsOrganicKeyword>>;\r\n getBacklinks: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsBacklink>>;\r\n getKeywordDifficulty: (keywords: string[]) => Promise<AhrefsKeywordDifficulty[]>;\r\n getReferringDomains: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsReferringDomain>>;\r\n}\r\n\r\nexport interface AhrefsPaginationOptions {\r\n limit?: number;\r\n offset?: number;\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Shared HTTP Client\r\n// ============================================================================\r\n\r\nimport type { HttpClientConfig, HttpClient, AuthStrategy } from './types.js';\r\nimport { IntegrationApiError } from './types.js';\r\nimport { createTokenBucket, consumeToken, getWaitTime, sleep } from '@power-seo/core';\r\n\r\nconst DEFAULT_RATE_LIMIT = 600;\r\nconst DEFAULT_MAX_RETRIES = 3;\r\nconst DEFAULT_TIMEOUT_MS = 30_000;\r\n\r\nfunction buildUrl(\r\n baseUrl: string,\r\n path: string,\r\n params: Record<string, string>,\r\n auth: AuthStrategy,\r\n): string {\r\n const url = new globalThis.URL(`${baseUrl}${path}`);\r\n for (const [key, value] of Object.entries(params)) {\r\n url.searchParams.set(key, value);\r\n }\r\n if (auth.type === 'query') {\r\n url.searchParams.set(auth.paramName, auth.value);\r\n }\r\n return url.toString();\r\n}\r\n\r\nfunction buildHeaders(auth: AuthStrategy): Record<string, string> {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json',\r\n };\r\n if (auth.type === 'bearer') {\r\n headers['Authorization'] = `Bearer ${auth.token}`;\r\n }\r\n return headers;\r\n}\r\n\r\nfunction getProviderFromUrl(baseUrl: string): string {\r\n if (baseUrl.includes('semrush')) return 'semrush';\r\n if (baseUrl.includes('ahrefs')) return 'ahrefs';\r\n return 'unknown';\r\n}\r\n\r\nexport function createHttpClient(config: HttpClientConfig): HttpClient {\r\n const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\r\n const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\r\n const bucket = createTokenBucket(config.rateLimitPerMinute ?? DEFAULT_RATE_LIMIT);\r\n const provider = getProviderFromUrl(config.baseUrl);\r\n\r\n async function makeRequest<T>(\r\n url: string,\r\n init: globalThis.RequestInit,\r\n ): Promise<T> {\r\n const waitTime = getWaitTime(bucket);\r\n if (waitTime > 0) {\r\n await sleep(waitTime);\r\n }\r\n consumeToken(bucket);\r\n\r\n let lastError: Error | null = null;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n const controller = new globalThis.AbortController();\r\n const timeout = globalThis.setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n try {\r\n const response = await globalThis.fetch(url, {\r\n ...init,\r\n signal: controller.signal,\r\n });\r\n\r\n globalThis.clearTimeout(timeout);\r\n\r\n if (response.ok) {\r\n return (await response.json()) as T;\r\n }\r\n\r\n const text = await response.text();\r\n const error = new IntegrationApiError(\r\n `${provider} API error: ${response.status} ${text}`,\r\n response.status,\r\n provider,\r\n );\r\n\r\n if (!error.retryable || attempt === maxRetries) {\r\n throw error;\r\n }\r\n\r\n lastError = error;\r\n const backoff = Math.min(1000 * Math.pow(2, attempt), 30_000);\r\n await sleep(backoff);\r\n } catch (err) {\r\n globalThis.clearTimeout(timeout);\r\n if (err instanceof IntegrationApiError) {\r\n if (!err.retryable || attempt === maxRetries) {\r\n throw err;\r\n }\r\n lastError = err;\r\n const backoff = Math.min(1000 * Math.pow(2, attempt), 30_000);\r\n await sleep(backoff);\r\n } else {\r\n throw err;\r\n }\r\n }\r\n }\r\n\r\n throw lastError ?? new IntegrationApiError('Request failed', 500, provider);\r\n }\r\n\r\n return {\r\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\r\n const url = buildUrl(config.baseUrl, path, params ?? {}, config.auth);\r\n const headers = buildHeaders(config.auth);\r\n return makeRequest<T>(url, { method: 'GET', headers });\r\n },\r\n\r\n async post<T>(path: string, body?: unknown): Promise<T> {\r\n const url = buildUrl(config.baseUrl, path, {}, config.auth);\r\n const headers = buildHeaders(config.auth);\r\n return makeRequest<T>(url, {\r\n method: 'POST',\r\n headers,\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n },\r\n };\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Semrush Endpoints\r\n// ============================================================================\r\n\r\nexport const SEMRUSH_BASE_URL = 'https://api.semrush.com';\r\n\r\nexport function domainOverviewPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function organicKeywordsPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function backlinksPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function keywordDifficultyPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function relatedKeywordsPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function buildDomainOverviewParams(domain: string, database: string): Record<string, string> {\r\n return {\r\n type: 'domain_ranks',\r\n domain,\r\n database,\r\n export_columns: 'Or,Ot,Oc,Ad,At,Ac,Bk,As',\r\n };\r\n}\r\n\r\nexport function buildOrganicKeywordsParams(\r\n domain: string,\r\n database: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n type: 'domain_organic',\r\n domain,\r\n database,\r\n display_limit: String(limit),\r\n display_offset: String(offset),\r\n export_columns: 'Ph,Po,Pp,Nq,Cp,Ur,Tr,Tc,Co,Td',\r\n };\r\n}\r\n\r\nexport function buildBacklinksParams(\r\n domain: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n type: 'backlinks',\r\n target: domain,\r\n target_type: 'root_domain',\r\n display_limit: String(limit),\r\n display_offset: String(offset),\r\n export_columns: 'source_url,target_url,anchor,nofollow,first_seen,last_seen,source_ascore',\r\n };\r\n}\r\n\r\nexport function buildKeywordDifficultyParams(\r\n keywords: string[],\r\n database: string,\r\n): Record<string, string> {\r\n return {\r\n type: 'phrase_all',\r\n phrase: keywords.join(';'),\r\n database,\r\n export_columns: 'Ph,Kd,Nq,Cp,Co,Nr',\r\n };\r\n}\r\n\r\nexport function buildRelatedKeywordsParams(\r\n keyword: string,\r\n database: string,\r\n): Record<string, string> {\r\n return {\r\n type: 'phrase_related',\r\n phrase: keyword,\r\n database,\r\n export_columns: 'Ph,Nq,Cp,Co,Nr,Rr',\r\n };\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Semrush Client\r\n// ============================================================================\r\n\r\nimport type {\r\n SemrushClient,\r\n SemrushDomainOverview,\r\n SemrushKeywordData,\r\n SemrushBacklinkData,\r\n SemrushKeywordDifficulty,\r\n SemrushRelatedKeyword,\r\n PaginatedResponse,\r\n SemrushPaginationOptions,\r\n HttpClientConfig,\r\n} from '../types.js';\r\nimport { createHttpClient } from '../http.js';\r\nimport {\r\n SEMRUSH_BASE_URL,\r\n domainOverviewPath,\r\n organicKeywordsPath,\r\n backlinksPath,\r\n keywordDifficultyPath,\r\n relatedKeywordsPath,\r\n buildDomainOverviewParams,\r\n buildOrganicKeywordsParams,\r\n buildBacklinksParams,\r\n buildKeywordDifficultyParams,\r\n buildRelatedKeywordsParams,\r\n} from './endpoints.js';\r\nimport type {\r\n SemrushRawDomainResponse,\r\n SemrushApiResponse,\r\n SemrushRawKeywordResponse,\r\n SemrushRawBacklinkResponse,\r\n SemrushRawKeywordDifficultyResponse,\r\n SemrushRawRelatedKeywordResponse,\r\n} from './types.js';\r\n\r\nconst DEFAULT_LIMIT = 100;\r\nconst DEFAULT_DATABASE = 'us';\r\n\r\nexport function createSemrushClient(\r\n apiKey: string,\r\n config?: Partial<Omit<HttpClientConfig, 'baseUrl' | 'auth'>>,\r\n): SemrushClient {\r\n const http = createHttpClient({\r\n baseUrl: SEMRUSH_BASE_URL,\r\n auth: { type: 'query', paramName: 'key', value: apiKey },\r\n ...config,\r\n });\r\n\r\n return {\r\n async getDomainOverview(domain, database = DEFAULT_DATABASE) {\r\n const params = buildDomainOverviewParams(domain, database);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawDomainResponse>>(\r\n domainOverviewPath(),\r\n params,\r\n );\r\n const entry = raw.data[0];\r\n return {\r\n domain,\r\n organicKeywords: entry?.Or ?? 0,\r\n organicTraffic: entry?.Ot ?? 0,\r\n organicCost: entry?.Oc ?? 0,\r\n paidKeywords: entry?.Ad ?? 0,\r\n paidTraffic: entry?.At ?? 0,\r\n paidCost: entry?.Ac ?? 0,\r\n backlinks: entry?.Bk ?? 0,\r\n authorityScore: entry?.As ?? 0,\r\n } satisfies SemrushDomainOverview;\r\n },\r\n\r\n async getOrganicKeywords(domain, options?: SemrushPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const database = options?.database ?? DEFAULT_DATABASE;\r\n const params = buildOrganicKeywordsParams(domain, database, limit, offset);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawKeywordResponse>>(\r\n organicKeywordsPath(),\r\n params,\r\n );\r\n const data: SemrushKeywordData[] = (raw.data ?? []).map((r) => ({\r\n keyword: r.Ph,\r\n position: r.Po,\r\n previousPosition: r.Pp,\r\n searchVolume: r.Nq,\r\n cpc: r.Cp,\r\n url: r.Ur,\r\n traffic: r.Tr,\r\n trafficPercent: r.Td,\r\n trafficCost: r.Tc,\r\n competition: r.Co,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<SemrushKeywordData>;\r\n },\r\n\r\n async getBacklinks(domain, options?: SemrushPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const params = buildBacklinksParams(domain, limit, offset);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawBacklinkResponse>>(\r\n backlinksPath(),\r\n params,\r\n );\r\n const data: SemrushBacklinkData[] = (raw.data ?? []).map((r) => ({\r\n sourceUrl: r.source_url,\r\n targetUrl: r.target_url,\r\n anchorText: r.anchor,\r\n isNoFollow: r.nofollow,\r\n firstSeen: r.first_seen,\r\n lastSeen: r.last_seen,\r\n sourceAuthorityScore: r.source_ascore,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<SemrushBacklinkData>;\r\n },\r\n\r\n async getKeywordDifficulty(keywords, database = DEFAULT_DATABASE) {\r\n const params = buildKeywordDifficultyParams(keywords, database);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawKeywordDifficultyResponse>>(\r\n keywordDifficultyPath(),\r\n params,\r\n );\r\n return (raw.data ?? []).map((r): SemrushKeywordDifficulty => ({\r\n keyword: r.Ph,\r\n difficulty: r.Kd,\r\n searchVolume: r.Nq,\r\n cpc: r.Cp,\r\n competition: r.Co,\r\n results: r.Nr,\r\n }));\r\n },\r\n\r\n async getRelatedKeywords(keyword, database = DEFAULT_DATABASE) {\r\n const params = buildRelatedKeywordsParams(keyword, database);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawRelatedKeywordResponse>>(\r\n relatedKeywordsPath(),\r\n params,\r\n );\r\n return (raw.data ?? []).map((r): SemrushRelatedKeyword => ({\r\n keyword: r.Ph,\r\n searchVolume: r.Nq,\r\n cpc: r.Cp,\r\n competition: r.Co,\r\n results: r.Nr,\r\n relatedTo: r.Rr,\r\n }));\r\n },\r\n };\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Ahrefs Endpoints\r\n// ============================================================================\r\n\r\nexport const AHREFS_BASE_URL = 'https://api.ahrefs.com/v3';\r\n\r\nexport function siteOverviewPath(): string {\r\n return '/site-explorer/overview';\r\n}\r\n\r\nexport function organicKeywordsPath(): string {\r\n return '/site-explorer/organic-keywords';\r\n}\r\n\r\nexport function backlinksPath(): string {\r\n return '/site-explorer/backlinks';\r\n}\r\n\r\nexport function keywordDifficultyPath(): string {\r\n return '/keywords-explorer/keyword-difficulty';\r\n}\r\n\r\nexport function referringDomainsPath(): string {\r\n return '/site-explorer/referring-domains';\r\n}\r\n\r\nexport function buildSiteOverviewParams(domain: string): Record<string, string> {\r\n return { target: domain, mode: 'domain' };\r\n}\r\n\r\nexport function buildOrganicKeywordsParams(\r\n domain: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n target: domain,\r\n mode: 'domain',\r\n limit: String(limit),\r\n offset: String(offset),\r\n };\r\n}\r\n\r\nexport function buildBacklinksParams(\r\n domain: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n target: domain,\r\n mode: 'domain',\r\n limit: String(limit),\r\n offset: String(offset),\r\n };\r\n}\r\n\r\nexport function buildKeywordDifficultyParams(\r\n keywords: string[],\r\n): Record<string, string> {\r\n return {\r\n keywords: keywords.join(','),\r\n };\r\n}\r\n\r\nexport function buildReferringDomainsParams(\r\n domain: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n target: domain,\r\n mode: 'domain',\r\n limit: String(limit),\r\n offset: String(offset),\r\n };\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Ahrefs Client\r\n// ============================================================================\r\n\r\nimport type {\r\n AhrefsClient,\r\n AhrefsSiteOverview,\r\n AhrefsOrganicKeyword,\r\n AhrefsBacklink,\r\n AhrefsKeywordDifficulty,\r\n AhrefsReferringDomain,\r\n PaginatedResponse,\r\n AhrefsPaginationOptions,\r\n HttpClientConfig,\r\n} from '../types.js';\r\nimport { createHttpClient } from '../http.js';\r\nimport {\r\n AHREFS_BASE_URL,\r\n siteOverviewPath,\r\n organicKeywordsPath,\r\n backlinksPath,\r\n keywordDifficultyPath,\r\n referringDomainsPath,\r\n buildSiteOverviewParams,\r\n buildOrganicKeywordsParams,\r\n buildBacklinksParams,\r\n buildKeywordDifficultyParams,\r\n buildReferringDomainsParams,\r\n} from './endpoints.js';\r\nimport type {\r\n AhrefsRawSiteOverview,\r\n AhrefsApiResponse,\r\n AhrefsRawOrganicKeyword,\r\n AhrefsRawBacklink,\r\n AhrefsRawKeywordDifficulty,\r\n AhrefsRawReferringDomain,\r\n} from './types.js';\r\n\r\nconst DEFAULT_LIMIT = 100;\r\n\r\nexport function createAhrefsClient(\r\n apiToken: string,\r\n config?: Partial<Omit<HttpClientConfig, 'baseUrl' | 'auth'>>,\r\n): AhrefsClient {\r\n const http = createHttpClient({\r\n baseUrl: AHREFS_BASE_URL,\r\n auth: { type: 'bearer', token: apiToken },\r\n ...config,\r\n });\r\n\r\n return {\r\n async getSiteOverview(domain) {\r\n const params = buildSiteOverviewParams(domain);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawSiteOverview>>(\r\n siteOverviewPath(),\r\n params,\r\n );\r\n const entry = raw.data[0];\r\n return {\r\n domain,\r\n domainRating: entry?.domain_rating ?? 0,\r\n urlRating: entry?.url_rating ?? 0,\r\n backlinks: entry?.backlinks ?? 0,\r\n referringDomains: entry?.referring_domains ?? 0,\r\n organicKeywords: entry?.organic_keywords ?? 0,\r\n organicTraffic: entry?.organic_traffic ?? 0,\r\n trafficValue: entry?.traffic_value ?? 0,\r\n } satisfies AhrefsSiteOverview;\r\n },\r\n\r\n async getOrganicKeywords(domain, options?: AhrefsPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const params = buildOrganicKeywordsParams(domain, limit, offset);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawOrganicKeyword>>(\r\n organicKeywordsPath(),\r\n params,\r\n );\r\n const data: AhrefsOrganicKeyword[] = (raw.data ?? []).map((r) => ({\r\n keyword: r.keyword,\r\n position: r.position,\r\n searchVolume: r.volume,\r\n cpc: r.cpc,\r\n url: r.url,\r\n traffic: r.traffic,\r\n trafficPercent: r.traffic_percent,\r\n difficulty: r.difficulty,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<AhrefsOrganicKeyword>;\r\n },\r\n\r\n async getBacklinks(domain, options?: AhrefsPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const params = buildBacklinksParams(domain, limit, offset);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawBacklink>>(\r\n backlinksPath(),\r\n params,\r\n );\r\n const data: AhrefsBacklink[] = (raw.data ?? []).map((r) => ({\r\n sourceUrl: r.url_from,\r\n targetUrl: r.url_to,\r\n anchorText: r.anchor,\r\n domainRating: r.domain_rating,\r\n urlRating: r.url_rating,\r\n isDoFollow: r.is_dofollow,\r\n firstSeen: r.first_seen,\r\n lastSeen: r.last_seen,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<AhrefsBacklink>;\r\n },\r\n\r\n async getKeywordDifficulty(keywords) {\r\n const params = buildKeywordDifficultyParams(keywords);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawKeywordDifficulty>>(\r\n keywordDifficultyPath(),\r\n params,\r\n );\r\n return (raw.data ?? []).map((r): AhrefsKeywordDifficulty => ({\r\n keyword: r.keyword,\r\n difficulty: r.difficulty,\r\n searchVolume: r.volume,\r\n cpc: r.cpc,\r\n clicks: r.clicks,\r\n globalVolume: r.global_volume,\r\n }));\r\n },\r\n\r\n async getReferringDomains(domain, options?: AhrefsPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const params = buildReferringDomainsParams(domain, limit, offset);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawReferringDomain>>(\r\n referringDomainsPath(),\r\n params,\r\n );\r\n const data: AhrefsReferringDomain[] = (raw.data ?? []).map((r) => ({\r\n domain: r.domain,\r\n domainRating: r.domain_rating,\r\n backlinks: r.backlinks,\r\n firstSeen: r.first_seen,\r\n lastSeen: r.last_seen,\r\n isDoFollow: r.is_dofollow,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<AhrefsReferringDomain>;\r\n },\r\n };\r\n}\r\n"]}
{"version":3,"sources":["../src/types.ts","../src/http.ts","../src/semrush/endpoints.ts","../src/semrush/client.ts","../src/ahrefs/endpoints.ts","../src/ahrefs/client.ts"],"names":["createTokenBucket","getWaitTime","sleep","consumeToken","organicKeywordsPath","backlinksPath","keywordDifficultyPath","buildOrganicKeywordsParams","buildBacklinksParams","buildKeywordDifficultyParams","DEFAULT_LIMIT"],"mappings":"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","file":"index.cjs","sourcesContent":["// ============================================================================\n// @power-seo/integrations — Types\n// ============================================================================\n\n// --- HTTP Client Types ---\n\nexport type AuthStrategy =\n | { type: 'query'; paramName: string; value: string }\n | { type: 'bearer'; token: string };\n\nexport interface HttpClientConfig {\n baseUrl: string;\n auth: AuthStrategy;\n rateLimitPerMinute?: number;\n maxRetries?: number;\n timeoutMs?: number;\n}\n\nexport interface HttpClient {\n get: <T>(path: string, params?: Record<string, string>) => Promise<T>;\n post: <T>(path: string, body?: unknown) => Promise<T>;\n}\n\n// --- Error ---\n\nexport class IntegrationApiError extends Error {\n readonly status: number;\n readonly provider: string;\n readonly retryable: boolean;\n\n constructor(message: string, status: number, provider: string) {\n super(message);\n this.name = 'IntegrationApiError';\n this.status = status;\n this.provider = provider;\n this.retryable = status === 429 || status >= 500;\n }\n}\n\n// --- Pagination ---\n\nexport interface PaginatedResponse<T> {\n data: T[];\n total: number;\n offset: number;\n limit: number;\n hasMore: boolean;\n}\n\n// --- Semrush Types ---\n\nexport interface SemrushDomainOverview {\n domain: string;\n organicKeywords: number;\n organicTraffic: number;\n organicCost: number;\n paidKeywords: number;\n paidTraffic: number;\n paidCost: number;\n backlinks: number;\n authorityScore: number;\n}\n\nexport interface SemrushKeywordData {\n keyword: string;\n position: number;\n previousPosition: number;\n searchVolume: number;\n cpc: number;\n url: string;\n traffic: number;\n trafficPercent: number;\n trafficCost: number;\n competition: number;\n}\n\nexport interface SemrushBacklinkData {\n sourceUrl: string;\n targetUrl: string;\n anchorText: string;\n isNoFollow: boolean;\n firstSeen: string;\n lastSeen: string;\n sourceAuthorityScore: number;\n}\n\nexport interface SemrushKeywordDifficulty {\n keyword: string;\n difficulty: number;\n searchVolume: number;\n cpc: number;\n competition: number;\n results: number;\n}\n\nexport interface SemrushRelatedKeyword {\n keyword: string;\n searchVolume: number;\n cpc: number;\n competition: number;\n results: number;\n relatedTo: string;\n}\n\nexport interface SemrushClient {\n getDomainOverview: (domain: string, database?: string) => Promise<SemrushDomainOverview>;\n getOrganicKeywords: (domain: string, options?: SemrushPaginationOptions) => Promise<PaginatedResponse<SemrushKeywordData>>;\n getBacklinks: (domain: string, options?: SemrushPaginationOptions) => Promise<PaginatedResponse<SemrushBacklinkData>>;\n getKeywordDifficulty: (keywords: string[], database?: string) => Promise<SemrushKeywordDifficulty[]>;\n getRelatedKeywords: (keyword: string, database?: string) => Promise<SemrushRelatedKeyword[]>;\n}\n\nexport interface SemrushPaginationOptions {\n limit?: number;\n offset?: number;\n database?: string;\n}\n\n// --- Ahrefs Types ---\n\nexport interface AhrefsSiteOverview {\n domain: string;\n domainRating: number;\n urlRating: number;\n backlinks: number;\n referringDomains: number;\n organicKeywords: number;\n organicTraffic: number;\n trafficValue: number;\n}\n\nexport interface AhrefsOrganicKeyword {\n keyword: string;\n position: number;\n searchVolume: number;\n cpc: number;\n url: string;\n traffic: number;\n trafficPercent: number;\n difficulty: number;\n}\n\nexport interface AhrefsBacklink {\n sourceUrl: string;\n targetUrl: string;\n anchorText: string;\n domainRating: number;\n urlRating: number;\n isDoFollow: boolean;\n firstSeen: string;\n lastSeen: string;\n}\n\nexport interface AhrefsKeywordDifficulty {\n keyword: string;\n difficulty: number;\n searchVolume: number;\n cpc: number;\n clicks: number;\n globalVolume: number;\n}\n\nexport interface AhrefsReferringDomain {\n domain: string;\n domainRating: number;\n backlinks: number;\n firstSeen: string;\n lastSeen: string;\n isDoFollow: boolean;\n}\n\nexport interface AhrefsClient {\n getSiteOverview: (domain: string) => Promise<AhrefsSiteOverview>;\n getOrganicKeywords: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsOrganicKeyword>>;\n getBacklinks: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsBacklink>>;\n getKeywordDifficulty: (keywords: string[]) => Promise<AhrefsKeywordDifficulty[]>;\n getReferringDomains: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsReferringDomain>>;\n}\n\nexport interface AhrefsPaginationOptions {\n limit?: number;\n offset?: number;\n}\n","// ============================================================================\n// @power-seo/integrations — Shared HTTP Client\n// ============================================================================\n\nimport type { HttpClientConfig, HttpClient, AuthStrategy } from './types.js';\nimport { IntegrationApiError } from './types.js';\nimport { createTokenBucket, consumeToken, getWaitTime, sleep } from '@power-seo/core';\n\nconst DEFAULT_RATE_LIMIT = 600;\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nfunction buildUrl(\n baseUrl: string,\n path: string,\n params: Record<string, string>,\n auth: AuthStrategy,\n): string {\n const url = new globalThis.URL(`${baseUrl}${path}`);\n for (const [key, value] of Object.entries(params)) {\n url.searchParams.set(key, value);\n }\n if (auth.type === 'query') {\n url.searchParams.set(auth.paramName, auth.value);\n }\n return url.toString();\n}\n\nfunction buildHeaders(auth: AuthStrategy): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n };\n if (auth.type === 'bearer') {\n headers['Authorization'] = `Bearer ${auth.token}`;\n }\n return headers;\n}\n\nfunction getProviderFromUrl(baseUrl: string): string {\n if (baseUrl.includes('semrush')) return 'semrush';\n if (baseUrl.includes('ahrefs')) return 'ahrefs';\n return 'unknown';\n}\n\nexport function createHttpClient(config: HttpClientConfig): HttpClient {\n const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const bucket = createTokenBucket(config.rateLimitPerMinute ?? DEFAULT_RATE_LIMIT);\n const provider = getProviderFromUrl(config.baseUrl);\n\n async function makeRequest<T>(\n url: string,\n init: globalThis.RequestInit,\n ): Promise<T> {\n const waitTime = getWaitTime(bucket);\n if (waitTime > 0) {\n await sleep(waitTime);\n }\n consumeToken(bucket);\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const controller = new globalThis.AbortController();\n const timeout = globalThis.setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await globalThis.fetch(url, {\n ...init,\n signal: controller.signal,\n });\n\n globalThis.clearTimeout(timeout);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const text = await response.text();\n const error = new IntegrationApiError(\n `${provider} API error: ${response.status} ${text}`,\n response.status,\n provider,\n );\n\n if (!error.retryable || attempt === maxRetries) {\n throw error;\n }\n\n lastError = error;\n const backoff = Math.min(1000 * Math.pow(2, attempt), 30_000);\n await sleep(backoff);\n } catch (err) {\n globalThis.clearTimeout(timeout);\n if (err instanceof IntegrationApiError) {\n if (!err.retryable || attempt === maxRetries) {\n throw err;\n }\n lastError = err;\n const backoff = Math.min(1000 * Math.pow(2, attempt), 30_000);\n await sleep(backoff);\n } else {\n throw err;\n }\n }\n }\n\n throw lastError ?? new IntegrationApiError('Request failed', 500, provider);\n }\n\n return {\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n const url = buildUrl(config.baseUrl, path, params ?? {}, config.auth);\n const headers = buildHeaders(config.auth);\n return makeRequest<T>(url, { method: 'GET', headers });\n },\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n const url = buildUrl(config.baseUrl, path, {}, config.auth);\n const headers = buildHeaders(config.auth);\n return makeRequest<T>(url, {\n method: 'POST',\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n },\n };\n}\n","// ============================================================================\n// @power-seo/integrations — Semrush Endpoints\n// ============================================================================\n\nexport const SEMRUSH_BASE_URL = 'https://api.semrush.com';\n\nexport function domainOverviewPath(): string {\n return '/analytics/v1/';\n}\n\nexport function organicKeywordsPath(): string {\n return '/analytics/v1/';\n}\n\nexport function backlinksPath(): string {\n return '/analytics/v1/';\n}\n\nexport function keywordDifficultyPath(): string {\n return '/analytics/v1/';\n}\n\nexport function relatedKeywordsPath(): string {\n return '/analytics/v1/';\n}\n\nexport function buildDomainOverviewParams(domain: string, database: string): Record<string, string> {\n return {\n type: 'domain_ranks',\n domain,\n database,\n export_columns: 'Or,Ot,Oc,Ad,At,Ac,Bk,As',\n };\n}\n\nexport function buildOrganicKeywordsParams(\n domain: string,\n database: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n type: 'domain_organic',\n domain,\n database,\n display_limit: String(limit),\n display_offset: String(offset),\n export_columns: 'Ph,Po,Pp,Nq,Cp,Ur,Tr,Tc,Co,Td',\n };\n}\n\nexport function buildBacklinksParams(\n domain: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n type: 'backlinks',\n target: domain,\n target_type: 'root_domain',\n display_limit: String(limit),\n display_offset: String(offset),\n export_columns: 'source_url,target_url,anchor,nofollow,first_seen,last_seen,source_ascore',\n };\n}\n\nexport function buildKeywordDifficultyParams(\n keywords: string[],\n database: string,\n): Record<string, string> {\n return {\n type: 'phrase_all',\n phrase: keywords.join(';'),\n database,\n export_columns: 'Ph,Kd,Nq,Cp,Co,Nr',\n };\n}\n\nexport function buildRelatedKeywordsParams(\n keyword: string,\n database: string,\n): Record<string, string> {\n return {\n type: 'phrase_related',\n phrase: keyword,\n database,\n export_columns: 'Ph,Nq,Cp,Co,Nr,Rr',\n };\n}\n","// ============================================================================\n// @power-seo/integrations — Semrush Client\n// ============================================================================\n\nimport type {\n SemrushClient,\n SemrushDomainOverview,\n SemrushKeywordData,\n SemrushBacklinkData,\n SemrushKeywordDifficulty,\n SemrushRelatedKeyword,\n PaginatedResponse,\n SemrushPaginationOptions,\n HttpClientConfig,\n} from '../types.js';\nimport { createHttpClient } from '../http.js';\nimport {\n SEMRUSH_BASE_URL,\n domainOverviewPath,\n organicKeywordsPath,\n backlinksPath,\n keywordDifficultyPath,\n relatedKeywordsPath,\n buildDomainOverviewParams,\n buildOrganicKeywordsParams,\n buildBacklinksParams,\n buildKeywordDifficultyParams,\n buildRelatedKeywordsParams,\n} from './endpoints.js';\nimport type {\n SemrushRawDomainResponse,\n SemrushApiResponse,\n SemrushRawKeywordResponse,\n SemrushRawBacklinkResponse,\n SemrushRawKeywordDifficultyResponse,\n SemrushRawRelatedKeywordResponse,\n} from './types.js';\n\nconst DEFAULT_LIMIT = 100;\nconst DEFAULT_DATABASE = 'us';\n\nexport function createSemrushClient(\n apiKey: string,\n config?: Partial<Omit<HttpClientConfig, 'baseUrl' | 'auth'>>,\n): SemrushClient {\n const http = createHttpClient({\n baseUrl: SEMRUSH_BASE_URL,\n auth: { type: 'query', paramName: 'key', value: apiKey },\n ...config,\n });\n\n return {\n async getDomainOverview(domain, database = DEFAULT_DATABASE) {\n const params = buildDomainOverviewParams(domain, database);\n const raw = await http.get<SemrushApiResponse<SemrushRawDomainResponse>>(\n domainOverviewPath(),\n params,\n );\n const entry = raw.data[0];\n return {\n domain,\n organicKeywords: entry?.Or ?? 0,\n organicTraffic: entry?.Ot ?? 0,\n organicCost: entry?.Oc ?? 0,\n paidKeywords: entry?.Ad ?? 0,\n paidTraffic: entry?.At ?? 0,\n paidCost: entry?.Ac ?? 0,\n backlinks: entry?.Bk ?? 0,\n authorityScore: entry?.As ?? 0,\n } satisfies SemrushDomainOverview;\n },\n\n async getOrganicKeywords(domain, options?: SemrushPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const database = options?.database ?? DEFAULT_DATABASE;\n const params = buildOrganicKeywordsParams(domain, database, limit, offset);\n const raw = await http.get<SemrushApiResponse<SemrushRawKeywordResponse>>(\n organicKeywordsPath(),\n params,\n );\n const data: SemrushKeywordData[] = (raw.data ?? []).map((r) => ({\n keyword: r.Ph,\n position: r.Po,\n previousPosition: r.Pp,\n searchVolume: r.Nq,\n cpc: r.Cp,\n url: r.Ur,\n traffic: r.Tr,\n trafficPercent: r.Td,\n trafficCost: r.Tc,\n competition: r.Co,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<SemrushKeywordData>;\n },\n\n async getBacklinks(domain, options?: SemrushPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const params = buildBacklinksParams(domain, limit, offset);\n const raw = await http.get<SemrushApiResponse<SemrushRawBacklinkResponse>>(\n backlinksPath(),\n params,\n );\n const data: SemrushBacklinkData[] = (raw.data ?? []).map((r) => ({\n sourceUrl: r.source_url,\n targetUrl: r.target_url,\n anchorText: r.anchor,\n isNoFollow: r.nofollow,\n firstSeen: r.first_seen,\n lastSeen: r.last_seen,\n sourceAuthorityScore: r.source_ascore,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<SemrushBacklinkData>;\n },\n\n async getKeywordDifficulty(keywords, database = DEFAULT_DATABASE) {\n const params = buildKeywordDifficultyParams(keywords, database);\n const raw = await http.get<SemrushApiResponse<SemrushRawKeywordDifficultyResponse>>(\n keywordDifficultyPath(),\n params,\n );\n return (raw.data ?? []).map((r): SemrushKeywordDifficulty => ({\n keyword: r.Ph,\n difficulty: r.Kd,\n searchVolume: r.Nq,\n cpc: r.Cp,\n competition: r.Co,\n results: r.Nr,\n }));\n },\n\n async getRelatedKeywords(keyword, database = DEFAULT_DATABASE) {\n const params = buildRelatedKeywordsParams(keyword, database);\n const raw = await http.get<SemrushApiResponse<SemrushRawRelatedKeywordResponse>>(\n relatedKeywordsPath(),\n params,\n );\n return (raw.data ?? []).map((r): SemrushRelatedKeyword => ({\n keyword: r.Ph,\n searchVolume: r.Nq,\n cpc: r.Cp,\n competition: r.Co,\n results: r.Nr,\n relatedTo: r.Rr,\n }));\n },\n };\n}\n","// ============================================================================\n// @power-seo/integrations — Ahrefs Endpoints\n// ============================================================================\n\nexport const AHREFS_BASE_URL = 'https://api.ahrefs.com/v3';\n\nexport function siteOverviewPath(): string {\n return '/site-explorer/overview';\n}\n\nexport function organicKeywordsPath(): string {\n return '/site-explorer/organic-keywords';\n}\n\nexport function backlinksPath(): string {\n return '/site-explorer/backlinks';\n}\n\nexport function keywordDifficultyPath(): string {\n return '/keywords-explorer/keyword-difficulty';\n}\n\nexport function referringDomainsPath(): string {\n return '/site-explorer/referring-domains';\n}\n\nexport function buildSiteOverviewParams(domain: string): Record<string, string> {\n return { target: domain, mode: 'domain' };\n}\n\nexport function buildOrganicKeywordsParams(\n domain: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n target: domain,\n mode: 'domain',\n limit: String(limit),\n offset: String(offset),\n };\n}\n\nexport function buildBacklinksParams(\n domain: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n target: domain,\n mode: 'domain',\n limit: String(limit),\n offset: String(offset),\n };\n}\n\nexport function buildKeywordDifficultyParams(\n keywords: string[],\n): Record<string, string> {\n return {\n keywords: keywords.join(','),\n };\n}\n\nexport function buildReferringDomainsParams(\n domain: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n target: domain,\n mode: 'domain',\n limit: String(limit),\n offset: String(offset),\n };\n}\n","// ============================================================================\n// @power-seo/integrations — Ahrefs Client\n// ============================================================================\n\nimport type {\n AhrefsClient,\n AhrefsSiteOverview,\n AhrefsOrganicKeyword,\n AhrefsBacklink,\n AhrefsKeywordDifficulty,\n AhrefsReferringDomain,\n PaginatedResponse,\n AhrefsPaginationOptions,\n HttpClientConfig,\n} from '../types.js';\nimport { createHttpClient } from '../http.js';\nimport {\n AHREFS_BASE_URL,\n siteOverviewPath,\n organicKeywordsPath,\n backlinksPath,\n keywordDifficultyPath,\n referringDomainsPath,\n buildSiteOverviewParams,\n buildOrganicKeywordsParams,\n buildBacklinksParams,\n buildKeywordDifficultyParams,\n buildReferringDomainsParams,\n} from './endpoints.js';\nimport type {\n AhrefsRawSiteOverview,\n AhrefsApiResponse,\n AhrefsRawOrganicKeyword,\n AhrefsRawBacklink,\n AhrefsRawKeywordDifficulty,\n AhrefsRawReferringDomain,\n} from './types.js';\n\nconst DEFAULT_LIMIT = 100;\n\nexport function createAhrefsClient(\n apiToken: string,\n config?: Partial<Omit<HttpClientConfig, 'baseUrl' | 'auth'>>,\n): AhrefsClient {\n const http = createHttpClient({\n baseUrl: AHREFS_BASE_URL,\n auth: { type: 'bearer', token: apiToken },\n ...config,\n });\n\n return {\n async getSiteOverview(domain) {\n const params = buildSiteOverviewParams(domain);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawSiteOverview>>(\n siteOverviewPath(),\n params,\n );\n const entry = raw.data[0];\n return {\n domain,\n domainRating: entry?.domain_rating ?? 0,\n urlRating: entry?.url_rating ?? 0,\n backlinks: entry?.backlinks ?? 0,\n referringDomains: entry?.referring_domains ?? 0,\n organicKeywords: entry?.organic_keywords ?? 0,\n organicTraffic: entry?.organic_traffic ?? 0,\n trafficValue: entry?.traffic_value ?? 0,\n } satisfies AhrefsSiteOverview;\n },\n\n async getOrganicKeywords(domain, options?: AhrefsPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const params = buildOrganicKeywordsParams(domain, limit, offset);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawOrganicKeyword>>(\n organicKeywordsPath(),\n params,\n );\n const data: AhrefsOrganicKeyword[] = (raw.data ?? []).map((r) => ({\n keyword: r.keyword,\n position: r.position,\n searchVolume: r.volume,\n cpc: r.cpc,\n url: r.url,\n traffic: r.traffic,\n trafficPercent: r.traffic_percent,\n difficulty: r.difficulty,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<AhrefsOrganicKeyword>;\n },\n\n async getBacklinks(domain, options?: AhrefsPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const params = buildBacklinksParams(domain, limit, offset);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawBacklink>>(\n backlinksPath(),\n params,\n );\n const data: AhrefsBacklink[] = (raw.data ?? []).map((r) => ({\n sourceUrl: r.url_from,\n targetUrl: r.url_to,\n anchorText: r.anchor,\n domainRating: r.domain_rating,\n urlRating: r.url_rating,\n isDoFollow: r.is_dofollow,\n firstSeen: r.first_seen,\n lastSeen: r.last_seen,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<AhrefsBacklink>;\n },\n\n async getKeywordDifficulty(keywords) {\n const params = buildKeywordDifficultyParams(keywords);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawKeywordDifficulty>>(\n keywordDifficultyPath(),\n params,\n );\n return (raw.data ?? []).map((r): AhrefsKeywordDifficulty => ({\n keyword: r.keyword,\n difficulty: r.difficulty,\n searchVolume: r.volume,\n cpc: r.cpc,\n clicks: r.clicks,\n globalVolume: r.global_volume,\n }));\n },\n\n async getReferringDomains(domain, options?: AhrefsPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const params = buildReferringDomainsParams(domain, limit, offset);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawReferringDomain>>(\n referringDomainsPath(),\n params,\n );\n const data: AhrefsReferringDomain[] = (raw.data ?? []).map((r) => ({\n domain: r.domain,\n domainRating: r.domain_rating,\n backlinks: r.backlinks,\n firstSeen: r.first_seen,\n lastSeen: r.last_seen,\n isDoFollow: r.is_dofollow,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<AhrefsReferringDomain>;\n },\n };\n}\n"]}

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/types.ts","../src/http.ts","../src/semrush/endpoints.ts","../src/semrush/client.ts","../src/ahrefs/endpoints.ts","../src/ahrefs/client.ts"],"names":["organicKeywordsPath","backlinksPath","keywordDifficultyPath","buildOrganicKeywordsParams","buildBacklinksParams","buildKeywordDifficultyParams","DEFAULT_LIMIT"],"mappings":"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","file":"index.js","sourcesContent":["// ============================================================================\r\n// @power-seo/integrations — Types\r\n// ============================================================================\r\n\r\n// --- HTTP Client Types ---\r\n\r\nexport type AuthStrategy =\r\n | { type: 'query'; paramName: string; value: string }\r\n | { type: 'bearer'; token: string };\r\n\r\nexport interface HttpClientConfig {\r\n baseUrl: string;\r\n auth: AuthStrategy;\r\n rateLimitPerMinute?: number;\r\n maxRetries?: number;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface HttpClient {\r\n get: <T>(path: string, params?: Record<string, string>) => Promise<T>;\r\n post: <T>(path: string, body?: unknown) => Promise<T>;\r\n}\r\n\r\n// --- Error ---\r\n\r\nexport class IntegrationApiError extends Error {\r\n readonly status: number;\r\n readonly provider: string;\r\n readonly retryable: boolean;\r\n\r\n constructor(message: string, status: number, provider: string) {\r\n super(message);\r\n this.name = 'IntegrationApiError';\r\n this.status = status;\r\n this.provider = provider;\r\n this.retryable = status === 429 || status >= 500;\r\n }\r\n}\r\n\r\n// --- Pagination ---\r\n\r\nexport interface PaginatedResponse<T> {\r\n data: T[];\r\n total: number;\r\n offset: number;\r\n limit: number;\r\n hasMore: boolean;\r\n}\r\n\r\n// --- Semrush Types ---\r\n\r\nexport interface SemrushDomainOverview {\r\n domain: string;\r\n organicKeywords: number;\r\n organicTraffic: number;\r\n organicCost: number;\r\n paidKeywords: number;\r\n paidTraffic: number;\r\n paidCost: number;\r\n backlinks: number;\r\n authorityScore: number;\r\n}\r\n\r\nexport interface SemrushKeywordData {\r\n keyword: string;\r\n position: number;\r\n previousPosition: number;\r\n searchVolume: number;\r\n cpc: number;\r\n url: string;\r\n traffic: number;\r\n trafficPercent: number;\r\n trafficCost: number;\r\n competition: number;\r\n}\r\n\r\nexport interface SemrushBacklinkData {\r\n sourceUrl: string;\r\n targetUrl: string;\r\n anchorText: string;\r\n isNoFollow: boolean;\r\n firstSeen: string;\r\n lastSeen: string;\r\n sourceAuthorityScore: number;\r\n}\r\n\r\nexport interface SemrushKeywordDifficulty {\r\n keyword: string;\r\n difficulty: number;\r\n searchVolume: number;\r\n cpc: number;\r\n competition: number;\r\n results: number;\r\n}\r\n\r\nexport interface SemrushRelatedKeyword {\r\n keyword: string;\r\n searchVolume: number;\r\n cpc: number;\r\n competition: number;\r\n results: number;\r\n relatedTo: string;\r\n}\r\n\r\nexport interface SemrushClient {\r\n getDomainOverview: (domain: string, database?: string) => Promise<SemrushDomainOverview>;\r\n getOrganicKeywords: (domain: string, options?: SemrushPaginationOptions) => Promise<PaginatedResponse<SemrushKeywordData>>;\r\n getBacklinks: (domain: string, options?: SemrushPaginationOptions) => Promise<PaginatedResponse<SemrushBacklinkData>>;\r\n getKeywordDifficulty: (keywords: string[], database?: string) => Promise<SemrushKeywordDifficulty[]>;\r\n getRelatedKeywords: (keyword: string, database?: string) => Promise<SemrushRelatedKeyword[]>;\r\n}\r\n\r\nexport interface SemrushPaginationOptions {\r\n limit?: number;\r\n offset?: number;\r\n database?: string;\r\n}\r\n\r\n// --- Ahrefs Types ---\r\n\r\nexport interface AhrefsSiteOverview {\r\n domain: string;\r\n domainRating: number;\r\n urlRating: number;\r\n backlinks: number;\r\n referringDomains: number;\r\n organicKeywords: number;\r\n organicTraffic: number;\r\n trafficValue: number;\r\n}\r\n\r\nexport interface AhrefsOrganicKeyword {\r\n keyword: string;\r\n position: number;\r\n searchVolume: number;\r\n cpc: number;\r\n url: string;\r\n traffic: number;\r\n trafficPercent: number;\r\n difficulty: number;\r\n}\r\n\r\nexport interface AhrefsBacklink {\r\n sourceUrl: string;\r\n targetUrl: string;\r\n anchorText: string;\r\n domainRating: number;\r\n urlRating: number;\r\n isDoFollow: boolean;\r\n firstSeen: string;\r\n lastSeen: string;\r\n}\r\n\r\nexport interface AhrefsKeywordDifficulty {\r\n keyword: string;\r\n difficulty: number;\r\n searchVolume: number;\r\n cpc: number;\r\n clicks: number;\r\n globalVolume: number;\r\n}\r\n\r\nexport interface AhrefsReferringDomain {\r\n domain: string;\r\n domainRating: number;\r\n backlinks: number;\r\n firstSeen: string;\r\n lastSeen: string;\r\n isDoFollow: boolean;\r\n}\r\n\r\nexport interface AhrefsClient {\r\n getSiteOverview: (domain: string) => Promise<AhrefsSiteOverview>;\r\n getOrganicKeywords: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsOrganicKeyword>>;\r\n getBacklinks: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsBacklink>>;\r\n getKeywordDifficulty: (keywords: string[]) => Promise<AhrefsKeywordDifficulty[]>;\r\n getReferringDomains: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsReferringDomain>>;\r\n}\r\n\r\nexport interface AhrefsPaginationOptions {\r\n limit?: number;\r\n offset?: number;\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Shared HTTP Client\r\n// ============================================================================\r\n\r\nimport type { HttpClientConfig, HttpClient, AuthStrategy } from './types.js';\r\nimport { IntegrationApiError } from './types.js';\r\nimport { createTokenBucket, consumeToken, getWaitTime, sleep } from '@power-seo/core';\r\n\r\nconst DEFAULT_RATE_LIMIT = 600;\r\nconst DEFAULT_MAX_RETRIES = 3;\r\nconst DEFAULT_TIMEOUT_MS = 30_000;\r\n\r\nfunction buildUrl(\r\n baseUrl: string,\r\n path: string,\r\n params: Record<string, string>,\r\n auth: AuthStrategy,\r\n): string {\r\n const url = new globalThis.URL(`${baseUrl}${path}`);\r\n for (const [key, value] of Object.entries(params)) {\r\n url.searchParams.set(key, value);\r\n }\r\n if (auth.type === 'query') {\r\n url.searchParams.set(auth.paramName, auth.value);\r\n }\r\n return url.toString();\r\n}\r\n\r\nfunction buildHeaders(auth: AuthStrategy): Record<string, string> {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json',\r\n };\r\n if (auth.type === 'bearer') {\r\n headers['Authorization'] = `Bearer ${auth.token}`;\r\n }\r\n return headers;\r\n}\r\n\r\nfunction getProviderFromUrl(baseUrl: string): string {\r\n if (baseUrl.includes('semrush')) return 'semrush';\r\n if (baseUrl.includes('ahrefs')) return 'ahrefs';\r\n return 'unknown';\r\n}\r\n\r\nexport function createHttpClient(config: HttpClientConfig): HttpClient {\r\n const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\r\n const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\r\n const bucket = createTokenBucket(config.rateLimitPerMinute ?? DEFAULT_RATE_LIMIT);\r\n const provider = getProviderFromUrl(config.baseUrl);\r\n\r\n async function makeRequest<T>(\r\n url: string,\r\n init: globalThis.RequestInit,\r\n ): Promise<T> {\r\n const waitTime = getWaitTime(bucket);\r\n if (waitTime > 0) {\r\n await sleep(waitTime);\r\n }\r\n consumeToken(bucket);\r\n\r\n let lastError: Error | null = null;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n const controller = new globalThis.AbortController();\r\n const timeout = globalThis.setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n try {\r\n const response = await globalThis.fetch(url, {\r\n ...init,\r\n signal: controller.signal,\r\n });\r\n\r\n globalThis.clearTimeout(timeout);\r\n\r\n if (response.ok) {\r\n return (await response.json()) as T;\r\n }\r\n\r\n const text = await response.text();\r\n const error = new IntegrationApiError(\r\n `${provider} API error: ${response.status} ${text}`,\r\n response.status,\r\n provider,\r\n );\r\n\r\n if (!error.retryable || attempt === maxRetries) {\r\n throw error;\r\n }\r\n\r\n lastError = error;\r\n const backoff = Math.min(1000 * Math.pow(2, attempt), 30_000);\r\n await sleep(backoff);\r\n } catch (err) {\r\n globalThis.clearTimeout(timeout);\r\n if (err instanceof IntegrationApiError) {\r\n if (!err.retryable || attempt === maxRetries) {\r\n throw err;\r\n }\r\n lastError = err;\r\n const backoff = Math.min(1000 * Math.pow(2, attempt), 30_000);\r\n await sleep(backoff);\r\n } else {\r\n throw err;\r\n }\r\n }\r\n }\r\n\r\n throw lastError ?? new IntegrationApiError('Request failed', 500, provider);\r\n }\r\n\r\n return {\r\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\r\n const url = buildUrl(config.baseUrl, path, params ?? {}, config.auth);\r\n const headers = buildHeaders(config.auth);\r\n return makeRequest<T>(url, { method: 'GET', headers });\r\n },\r\n\r\n async post<T>(path: string, body?: unknown): Promise<T> {\r\n const url = buildUrl(config.baseUrl, path, {}, config.auth);\r\n const headers = buildHeaders(config.auth);\r\n return makeRequest<T>(url, {\r\n method: 'POST',\r\n headers,\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n },\r\n };\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Semrush Endpoints\r\n// ============================================================================\r\n\r\nexport const SEMRUSH_BASE_URL = 'https://api.semrush.com';\r\n\r\nexport function domainOverviewPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function organicKeywordsPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function backlinksPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function keywordDifficultyPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function relatedKeywordsPath(): string {\r\n return '/analytics/v1/';\r\n}\r\n\r\nexport function buildDomainOverviewParams(domain: string, database: string): Record<string, string> {\r\n return {\r\n type: 'domain_ranks',\r\n domain,\r\n database,\r\n export_columns: 'Or,Ot,Oc,Ad,At,Ac,Bk,As',\r\n };\r\n}\r\n\r\nexport function buildOrganicKeywordsParams(\r\n domain: string,\r\n database: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n type: 'domain_organic',\r\n domain,\r\n database,\r\n display_limit: String(limit),\r\n display_offset: String(offset),\r\n export_columns: 'Ph,Po,Pp,Nq,Cp,Ur,Tr,Tc,Co,Td',\r\n };\r\n}\r\n\r\nexport function buildBacklinksParams(\r\n domain: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n type: 'backlinks',\r\n target: domain,\r\n target_type: 'root_domain',\r\n display_limit: String(limit),\r\n display_offset: String(offset),\r\n export_columns: 'source_url,target_url,anchor,nofollow,first_seen,last_seen,source_ascore',\r\n };\r\n}\r\n\r\nexport function buildKeywordDifficultyParams(\r\n keywords: string[],\r\n database: string,\r\n): Record<string, string> {\r\n return {\r\n type: 'phrase_all',\r\n phrase: keywords.join(';'),\r\n database,\r\n export_columns: 'Ph,Kd,Nq,Cp,Co,Nr',\r\n };\r\n}\r\n\r\nexport function buildRelatedKeywordsParams(\r\n keyword: string,\r\n database: string,\r\n): Record<string, string> {\r\n return {\r\n type: 'phrase_related',\r\n phrase: keyword,\r\n database,\r\n export_columns: 'Ph,Nq,Cp,Co,Nr,Rr',\r\n };\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Semrush Client\r\n// ============================================================================\r\n\r\nimport type {\r\n SemrushClient,\r\n SemrushDomainOverview,\r\n SemrushKeywordData,\r\n SemrushBacklinkData,\r\n SemrushKeywordDifficulty,\r\n SemrushRelatedKeyword,\r\n PaginatedResponse,\r\n SemrushPaginationOptions,\r\n HttpClientConfig,\r\n} from '../types.js';\r\nimport { createHttpClient } from '../http.js';\r\nimport {\r\n SEMRUSH_BASE_URL,\r\n domainOverviewPath,\r\n organicKeywordsPath,\r\n backlinksPath,\r\n keywordDifficultyPath,\r\n relatedKeywordsPath,\r\n buildDomainOverviewParams,\r\n buildOrganicKeywordsParams,\r\n buildBacklinksParams,\r\n buildKeywordDifficultyParams,\r\n buildRelatedKeywordsParams,\r\n} from './endpoints.js';\r\nimport type {\r\n SemrushRawDomainResponse,\r\n SemrushApiResponse,\r\n SemrushRawKeywordResponse,\r\n SemrushRawBacklinkResponse,\r\n SemrushRawKeywordDifficultyResponse,\r\n SemrushRawRelatedKeywordResponse,\r\n} from './types.js';\r\n\r\nconst DEFAULT_LIMIT = 100;\r\nconst DEFAULT_DATABASE = 'us';\r\n\r\nexport function createSemrushClient(\r\n apiKey: string,\r\n config?: Partial<Omit<HttpClientConfig, 'baseUrl' | 'auth'>>,\r\n): SemrushClient {\r\n const http = createHttpClient({\r\n baseUrl: SEMRUSH_BASE_URL,\r\n auth: { type: 'query', paramName: 'key', value: apiKey },\r\n ...config,\r\n });\r\n\r\n return {\r\n async getDomainOverview(domain, database = DEFAULT_DATABASE) {\r\n const params = buildDomainOverviewParams(domain, database);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawDomainResponse>>(\r\n domainOverviewPath(),\r\n params,\r\n );\r\n const entry = raw.data[0];\r\n return {\r\n domain,\r\n organicKeywords: entry?.Or ?? 0,\r\n organicTraffic: entry?.Ot ?? 0,\r\n organicCost: entry?.Oc ?? 0,\r\n paidKeywords: entry?.Ad ?? 0,\r\n paidTraffic: entry?.At ?? 0,\r\n paidCost: entry?.Ac ?? 0,\r\n backlinks: entry?.Bk ?? 0,\r\n authorityScore: entry?.As ?? 0,\r\n } satisfies SemrushDomainOverview;\r\n },\r\n\r\n async getOrganicKeywords(domain, options?: SemrushPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const database = options?.database ?? DEFAULT_DATABASE;\r\n const params = buildOrganicKeywordsParams(domain, database, limit, offset);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawKeywordResponse>>(\r\n organicKeywordsPath(),\r\n params,\r\n );\r\n const data: SemrushKeywordData[] = (raw.data ?? []).map((r) => ({\r\n keyword: r.Ph,\r\n position: r.Po,\r\n previousPosition: r.Pp,\r\n searchVolume: r.Nq,\r\n cpc: r.Cp,\r\n url: r.Ur,\r\n traffic: r.Tr,\r\n trafficPercent: r.Td,\r\n trafficCost: r.Tc,\r\n competition: r.Co,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<SemrushKeywordData>;\r\n },\r\n\r\n async getBacklinks(domain, options?: SemrushPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const params = buildBacklinksParams(domain, limit, offset);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawBacklinkResponse>>(\r\n backlinksPath(),\r\n params,\r\n );\r\n const data: SemrushBacklinkData[] = (raw.data ?? []).map((r) => ({\r\n sourceUrl: r.source_url,\r\n targetUrl: r.target_url,\r\n anchorText: r.anchor,\r\n isNoFollow: r.nofollow,\r\n firstSeen: r.first_seen,\r\n lastSeen: r.last_seen,\r\n sourceAuthorityScore: r.source_ascore,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<SemrushBacklinkData>;\r\n },\r\n\r\n async getKeywordDifficulty(keywords, database = DEFAULT_DATABASE) {\r\n const params = buildKeywordDifficultyParams(keywords, database);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawKeywordDifficultyResponse>>(\r\n keywordDifficultyPath(),\r\n params,\r\n );\r\n return (raw.data ?? []).map((r): SemrushKeywordDifficulty => ({\r\n keyword: r.Ph,\r\n difficulty: r.Kd,\r\n searchVolume: r.Nq,\r\n cpc: r.Cp,\r\n competition: r.Co,\r\n results: r.Nr,\r\n }));\r\n },\r\n\r\n async getRelatedKeywords(keyword, database = DEFAULT_DATABASE) {\r\n const params = buildRelatedKeywordsParams(keyword, database);\r\n const raw = await http.get<SemrushApiResponse<SemrushRawRelatedKeywordResponse>>(\r\n relatedKeywordsPath(),\r\n params,\r\n );\r\n return (raw.data ?? []).map((r): SemrushRelatedKeyword => ({\r\n keyword: r.Ph,\r\n searchVolume: r.Nq,\r\n cpc: r.Cp,\r\n competition: r.Co,\r\n results: r.Nr,\r\n relatedTo: r.Rr,\r\n }));\r\n },\r\n };\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Ahrefs Endpoints\r\n// ============================================================================\r\n\r\nexport const AHREFS_BASE_URL = 'https://api.ahrefs.com/v3';\r\n\r\nexport function siteOverviewPath(): string {\r\n return '/site-explorer/overview';\r\n}\r\n\r\nexport function organicKeywordsPath(): string {\r\n return '/site-explorer/organic-keywords';\r\n}\r\n\r\nexport function backlinksPath(): string {\r\n return '/site-explorer/backlinks';\r\n}\r\n\r\nexport function keywordDifficultyPath(): string {\r\n return '/keywords-explorer/keyword-difficulty';\r\n}\r\n\r\nexport function referringDomainsPath(): string {\r\n return '/site-explorer/referring-domains';\r\n}\r\n\r\nexport function buildSiteOverviewParams(domain: string): Record<string, string> {\r\n return { target: domain, mode: 'domain' };\r\n}\r\n\r\nexport function buildOrganicKeywordsParams(\r\n domain: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n target: domain,\r\n mode: 'domain',\r\n limit: String(limit),\r\n offset: String(offset),\r\n };\r\n}\r\n\r\nexport function buildBacklinksParams(\r\n domain: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n target: domain,\r\n mode: 'domain',\r\n limit: String(limit),\r\n offset: String(offset),\r\n };\r\n}\r\n\r\nexport function buildKeywordDifficultyParams(\r\n keywords: string[],\r\n): Record<string, string> {\r\n return {\r\n keywords: keywords.join(','),\r\n };\r\n}\r\n\r\nexport function buildReferringDomainsParams(\r\n domain: string,\r\n limit: number,\r\n offset: number,\r\n): Record<string, string> {\r\n return {\r\n target: domain,\r\n mode: 'domain',\r\n limit: String(limit),\r\n offset: String(offset),\r\n };\r\n}\r\n","// ============================================================================\r\n// @power-seo/integrations — Ahrefs Client\r\n// ============================================================================\r\n\r\nimport type {\r\n AhrefsClient,\r\n AhrefsSiteOverview,\r\n AhrefsOrganicKeyword,\r\n AhrefsBacklink,\r\n AhrefsKeywordDifficulty,\r\n AhrefsReferringDomain,\r\n PaginatedResponse,\r\n AhrefsPaginationOptions,\r\n HttpClientConfig,\r\n} from '../types.js';\r\nimport { createHttpClient } from '../http.js';\r\nimport {\r\n AHREFS_BASE_URL,\r\n siteOverviewPath,\r\n organicKeywordsPath,\r\n backlinksPath,\r\n keywordDifficultyPath,\r\n referringDomainsPath,\r\n buildSiteOverviewParams,\r\n buildOrganicKeywordsParams,\r\n buildBacklinksParams,\r\n buildKeywordDifficultyParams,\r\n buildReferringDomainsParams,\r\n} from './endpoints.js';\r\nimport type {\r\n AhrefsRawSiteOverview,\r\n AhrefsApiResponse,\r\n AhrefsRawOrganicKeyword,\r\n AhrefsRawBacklink,\r\n AhrefsRawKeywordDifficulty,\r\n AhrefsRawReferringDomain,\r\n} from './types.js';\r\n\r\nconst DEFAULT_LIMIT = 100;\r\n\r\nexport function createAhrefsClient(\r\n apiToken: string,\r\n config?: Partial<Omit<HttpClientConfig, 'baseUrl' | 'auth'>>,\r\n): AhrefsClient {\r\n const http = createHttpClient({\r\n baseUrl: AHREFS_BASE_URL,\r\n auth: { type: 'bearer', token: apiToken },\r\n ...config,\r\n });\r\n\r\n return {\r\n async getSiteOverview(domain) {\r\n const params = buildSiteOverviewParams(domain);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawSiteOverview>>(\r\n siteOverviewPath(),\r\n params,\r\n );\r\n const entry = raw.data[0];\r\n return {\r\n domain,\r\n domainRating: entry?.domain_rating ?? 0,\r\n urlRating: entry?.url_rating ?? 0,\r\n backlinks: entry?.backlinks ?? 0,\r\n referringDomains: entry?.referring_domains ?? 0,\r\n organicKeywords: entry?.organic_keywords ?? 0,\r\n organicTraffic: entry?.organic_traffic ?? 0,\r\n trafficValue: entry?.traffic_value ?? 0,\r\n } satisfies AhrefsSiteOverview;\r\n },\r\n\r\n async getOrganicKeywords(domain, options?: AhrefsPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const params = buildOrganicKeywordsParams(domain, limit, offset);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawOrganicKeyword>>(\r\n organicKeywordsPath(),\r\n params,\r\n );\r\n const data: AhrefsOrganicKeyword[] = (raw.data ?? []).map((r) => ({\r\n keyword: r.keyword,\r\n position: r.position,\r\n searchVolume: r.volume,\r\n cpc: r.cpc,\r\n url: r.url,\r\n traffic: r.traffic,\r\n trafficPercent: r.traffic_percent,\r\n difficulty: r.difficulty,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<AhrefsOrganicKeyword>;\r\n },\r\n\r\n async getBacklinks(domain, options?: AhrefsPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const params = buildBacklinksParams(domain, limit, offset);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawBacklink>>(\r\n backlinksPath(),\r\n params,\r\n );\r\n const data: AhrefsBacklink[] = (raw.data ?? []).map((r) => ({\r\n sourceUrl: r.url_from,\r\n targetUrl: r.url_to,\r\n anchorText: r.anchor,\r\n domainRating: r.domain_rating,\r\n urlRating: r.url_rating,\r\n isDoFollow: r.is_dofollow,\r\n firstSeen: r.first_seen,\r\n lastSeen: r.last_seen,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<AhrefsBacklink>;\r\n },\r\n\r\n async getKeywordDifficulty(keywords) {\r\n const params = buildKeywordDifficultyParams(keywords);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawKeywordDifficulty>>(\r\n keywordDifficultyPath(),\r\n params,\r\n );\r\n return (raw.data ?? []).map((r): AhrefsKeywordDifficulty => ({\r\n keyword: r.keyword,\r\n difficulty: r.difficulty,\r\n searchVolume: r.volume,\r\n cpc: r.cpc,\r\n clicks: r.clicks,\r\n globalVolume: r.global_volume,\r\n }));\r\n },\r\n\r\n async getReferringDomains(domain, options?: AhrefsPaginationOptions) {\r\n const limit = options?.limit ?? DEFAULT_LIMIT;\r\n const offset = options?.offset ?? 0;\r\n const params = buildReferringDomainsParams(domain, limit, offset);\r\n const raw = await http.get<AhrefsApiResponse<AhrefsRawReferringDomain>>(\r\n referringDomainsPath(),\r\n params,\r\n );\r\n const data: AhrefsReferringDomain[] = (raw.data ?? []).map((r) => ({\r\n domain: r.domain,\r\n domainRating: r.domain_rating,\r\n backlinks: r.backlinks,\r\n firstSeen: r.first_seen,\r\n lastSeen: r.last_seen,\r\n isDoFollow: r.is_dofollow,\r\n }));\r\n return {\r\n data,\r\n total: raw.total ?? 0,\r\n offset,\r\n limit,\r\n hasMore: data.length === limit,\r\n } satisfies PaginatedResponse<AhrefsReferringDomain>;\r\n },\r\n };\r\n}\r\n"]}
{"version":3,"sources":["../src/types.ts","../src/http.ts","../src/semrush/endpoints.ts","../src/semrush/client.ts","../src/ahrefs/endpoints.ts","../src/ahrefs/client.ts"],"names":["organicKeywordsPath","backlinksPath","keywordDifficultyPath","buildOrganicKeywordsParams","buildBacklinksParams","buildKeywordDifficultyParams","DEFAULT_LIMIT"],"mappings":"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","file":"index.js","sourcesContent":["// ============================================================================\n// @power-seo/integrations — Types\n// ============================================================================\n\n// --- HTTP Client Types ---\n\nexport type AuthStrategy =\n | { type: 'query'; paramName: string; value: string }\n | { type: 'bearer'; token: string };\n\nexport interface HttpClientConfig {\n baseUrl: string;\n auth: AuthStrategy;\n rateLimitPerMinute?: number;\n maxRetries?: number;\n timeoutMs?: number;\n}\n\nexport interface HttpClient {\n get: <T>(path: string, params?: Record<string, string>) => Promise<T>;\n post: <T>(path: string, body?: unknown) => Promise<T>;\n}\n\n// --- Error ---\n\nexport class IntegrationApiError extends Error {\n readonly status: number;\n readonly provider: string;\n readonly retryable: boolean;\n\n constructor(message: string, status: number, provider: string) {\n super(message);\n this.name = 'IntegrationApiError';\n this.status = status;\n this.provider = provider;\n this.retryable = status === 429 || status >= 500;\n }\n}\n\n// --- Pagination ---\n\nexport interface PaginatedResponse<T> {\n data: T[];\n total: number;\n offset: number;\n limit: number;\n hasMore: boolean;\n}\n\n// --- Semrush Types ---\n\nexport interface SemrushDomainOverview {\n domain: string;\n organicKeywords: number;\n organicTraffic: number;\n organicCost: number;\n paidKeywords: number;\n paidTraffic: number;\n paidCost: number;\n backlinks: number;\n authorityScore: number;\n}\n\nexport interface SemrushKeywordData {\n keyword: string;\n position: number;\n previousPosition: number;\n searchVolume: number;\n cpc: number;\n url: string;\n traffic: number;\n trafficPercent: number;\n trafficCost: number;\n competition: number;\n}\n\nexport interface SemrushBacklinkData {\n sourceUrl: string;\n targetUrl: string;\n anchorText: string;\n isNoFollow: boolean;\n firstSeen: string;\n lastSeen: string;\n sourceAuthorityScore: number;\n}\n\nexport interface SemrushKeywordDifficulty {\n keyword: string;\n difficulty: number;\n searchVolume: number;\n cpc: number;\n competition: number;\n results: number;\n}\n\nexport interface SemrushRelatedKeyword {\n keyword: string;\n searchVolume: number;\n cpc: number;\n competition: number;\n results: number;\n relatedTo: string;\n}\n\nexport interface SemrushClient {\n getDomainOverview: (domain: string, database?: string) => Promise<SemrushDomainOverview>;\n getOrganicKeywords: (domain: string, options?: SemrushPaginationOptions) => Promise<PaginatedResponse<SemrushKeywordData>>;\n getBacklinks: (domain: string, options?: SemrushPaginationOptions) => Promise<PaginatedResponse<SemrushBacklinkData>>;\n getKeywordDifficulty: (keywords: string[], database?: string) => Promise<SemrushKeywordDifficulty[]>;\n getRelatedKeywords: (keyword: string, database?: string) => Promise<SemrushRelatedKeyword[]>;\n}\n\nexport interface SemrushPaginationOptions {\n limit?: number;\n offset?: number;\n database?: string;\n}\n\n// --- Ahrefs Types ---\n\nexport interface AhrefsSiteOverview {\n domain: string;\n domainRating: number;\n urlRating: number;\n backlinks: number;\n referringDomains: number;\n organicKeywords: number;\n organicTraffic: number;\n trafficValue: number;\n}\n\nexport interface AhrefsOrganicKeyword {\n keyword: string;\n position: number;\n searchVolume: number;\n cpc: number;\n url: string;\n traffic: number;\n trafficPercent: number;\n difficulty: number;\n}\n\nexport interface AhrefsBacklink {\n sourceUrl: string;\n targetUrl: string;\n anchorText: string;\n domainRating: number;\n urlRating: number;\n isDoFollow: boolean;\n firstSeen: string;\n lastSeen: string;\n}\n\nexport interface AhrefsKeywordDifficulty {\n keyword: string;\n difficulty: number;\n searchVolume: number;\n cpc: number;\n clicks: number;\n globalVolume: number;\n}\n\nexport interface AhrefsReferringDomain {\n domain: string;\n domainRating: number;\n backlinks: number;\n firstSeen: string;\n lastSeen: string;\n isDoFollow: boolean;\n}\n\nexport interface AhrefsClient {\n getSiteOverview: (domain: string) => Promise<AhrefsSiteOverview>;\n getOrganicKeywords: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsOrganicKeyword>>;\n getBacklinks: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsBacklink>>;\n getKeywordDifficulty: (keywords: string[]) => Promise<AhrefsKeywordDifficulty[]>;\n getReferringDomains: (domain: string, options?: AhrefsPaginationOptions) => Promise<PaginatedResponse<AhrefsReferringDomain>>;\n}\n\nexport interface AhrefsPaginationOptions {\n limit?: number;\n offset?: number;\n}\n","// ============================================================================\n// @power-seo/integrations — Shared HTTP Client\n// ============================================================================\n\nimport type { HttpClientConfig, HttpClient, AuthStrategy } from './types.js';\nimport { IntegrationApiError } from './types.js';\nimport { createTokenBucket, consumeToken, getWaitTime, sleep } from '@power-seo/core';\n\nconst DEFAULT_RATE_LIMIT = 600;\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nfunction buildUrl(\n baseUrl: string,\n path: string,\n params: Record<string, string>,\n auth: AuthStrategy,\n): string {\n const url = new globalThis.URL(`${baseUrl}${path}`);\n for (const [key, value] of Object.entries(params)) {\n url.searchParams.set(key, value);\n }\n if (auth.type === 'query') {\n url.searchParams.set(auth.paramName, auth.value);\n }\n return url.toString();\n}\n\nfunction buildHeaders(auth: AuthStrategy): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n };\n if (auth.type === 'bearer') {\n headers['Authorization'] = `Bearer ${auth.token}`;\n }\n return headers;\n}\n\nfunction getProviderFromUrl(baseUrl: string): string {\n if (baseUrl.includes('semrush')) return 'semrush';\n if (baseUrl.includes('ahrefs')) return 'ahrefs';\n return 'unknown';\n}\n\nexport function createHttpClient(config: HttpClientConfig): HttpClient {\n const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const bucket = createTokenBucket(config.rateLimitPerMinute ?? DEFAULT_RATE_LIMIT);\n const provider = getProviderFromUrl(config.baseUrl);\n\n async function makeRequest<T>(\n url: string,\n init: globalThis.RequestInit,\n ): Promise<T> {\n const waitTime = getWaitTime(bucket);\n if (waitTime > 0) {\n await sleep(waitTime);\n }\n consumeToken(bucket);\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const controller = new globalThis.AbortController();\n const timeout = globalThis.setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await globalThis.fetch(url, {\n ...init,\n signal: controller.signal,\n });\n\n globalThis.clearTimeout(timeout);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const text = await response.text();\n const error = new IntegrationApiError(\n `${provider} API error: ${response.status} ${text}`,\n response.status,\n provider,\n );\n\n if (!error.retryable || attempt === maxRetries) {\n throw error;\n }\n\n lastError = error;\n const backoff = Math.min(1000 * Math.pow(2, attempt), 30_000);\n await sleep(backoff);\n } catch (err) {\n globalThis.clearTimeout(timeout);\n if (err instanceof IntegrationApiError) {\n if (!err.retryable || attempt === maxRetries) {\n throw err;\n }\n lastError = err;\n const backoff = Math.min(1000 * Math.pow(2, attempt), 30_000);\n await sleep(backoff);\n } else {\n throw err;\n }\n }\n }\n\n throw lastError ?? new IntegrationApiError('Request failed', 500, provider);\n }\n\n return {\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n const url = buildUrl(config.baseUrl, path, params ?? {}, config.auth);\n const headers = buildHeaders(config.auth);\n return makeRequest<T>(url, { method: 'GET', headers });\n },\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n const url = buildUrl(config.baseUrl, path, {}, config.auth);\n const headers = buildHeaders(config.auth);\n return makeRequest<T>(url, {\n method: 'POST',\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n },\n };\n}\n","// ============================================================================\n// @power-seo/integrations — Semrush Endpoints\n// ============================================================================\n\nexport const SEMRUSH_BASE_URL = 'https://api.semrush.com';\n\nexport function domainOverviewPath(): string {\n return '/analytics/v1/';\n}\n\nexport function organicKeywordsPath(): string {\n return '/analytics/v1/';\n}\n\nexport function backlinksPath(): string {\n return '/analytics/v1/';\n}\n\nexport function keywordDifficultyPath(): string {\n return '/analytics/v1/';\n}\n\nexport function relatedKeywordsPath(): string {\n return '/analytics/v1/';\n}\n\nexport function buildDomainOverviewParams(domain: string, database: string): Record<string, string> {\n return {\n type: 'domain_ranks',\n domain,\n database,\n export_columns: 'Or,Ot,Oc,Ad,At,Ac,Bk,As',\n };\n}\n\nexport function buildOrganicKeywordsParams(\n domain: string,\n database: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n type: 'domain_organic',\n domain,\n database,\n display_limit: String(limit),\n display_offset: String(offset),\n export_columns: 'Ph,Po,Pp,Nq,Cp,Ur,Tr,Tc,Co,Td',\n };\n}\n\nexport function buildBacklinksParams(\n domain: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n type: 'backlinks',\n target: domain,\n target_type: 'root_domain',\n display_limit: String(limit),\n display_offset: String(offset),\n export_columns: 'source_url,target_url,anchor,nofollow,first_seen,last_seen,source_ascore',\n };\n}\n\nexport function buildKeywordDifficultyParams(\n keywords: string[],\n database: string,\n): Record<string, string> {\n return {\n type: 'phrase_all',\n phrase: keywords.join(';'),\n database,\n export_columns: 'Ph,Kd,Nq,Cp,Co,Nr',\n };\n}\n\nexport function buildRelatedKeywordsParams(\n keyword: string,\n database: string,\n): Record<string, string> {\n return {\n type: 'phrase_related',\n phrase: keyword,\n database,\n export_columns: 'Ph,Nq,Cp,Co,Nr,Rr',\n };\n}\n","// ============================================================================\n// @power-seo/integrations — Semrush Client\n// ============================================================================\n\nimport type {\n SemrushClient,\n SemrushDomainOverview,\n SemrushKeywordData,\n SemrushBacklinkData,\n SemrushKeywordDifficulty,\n SemrushRelatedKeyword,\n PaginatedResponse,\n SemrushPaginationOptions,\n HttpClientConfig,\n} from '../types.js';\nimport { createHttpClient } from '../http.js';\nimport {\n SEMRUSH_BASE_URL,\n domainOverviewPath,\n organicKeywordsPath,\n backlinksPath,\n keywordDifficultyPath,\n relatedKeywordsPath,\n buildDomainOverviewParams,\n buildOrganicKeywordsParams,\n buildBacklinksParams,\n buildKeywordDifficultyParams,\n buildRelatedKeywordsParams,\n} from './endpoints.js';\nimport type {\n SemrushRawDomainResponse,\n SemrushApiResponse,\n SemrushRawKeywordResponse,\n SemrushRawBacklinkResponse,\n SemrushRawKeywordDifficultyResponse,\n SemrushRawRelatedKeywordResponse,\n} from './types.js';\n\nconst DEFAULT_LIMIT = 100;\nconst DEFAULT_DATABASE = 'us';\n\nexport function createSemrushClient(\n apiKey: string,\n config?: Partial<Omit<HttpClientConfig, 'baseUrl' | 'auth'>>,\n): SemrushClient {\n const http = createHttpClient({\n baseUrl: SEMRUSH_BASE_URL,\n auth: { type: 'query', paramName: 'key', value: apiKey },\n ...config,\n });\n\n return {\n async getDomainOverview(domain, database = DEFAULT_DATABASE) {\n const params = buildDomainOverviewParams(domain, database);\n const raw = await http.get<SemrushApiResponse<SemrushRawDomainResponse>>(\n domainOverviewPath(),\n params,\n );\n const entry = raw.data[0];\n return {\n domain,\n organicKeywords: entry?.Or ?? 0,\n organicTraffic: entry?.Ot ?? 0,\n organicCost: entry?.Oc ?? 0,\n paidKeywords: entry?.Ad ?? 0,\n paidTraffic: entry?.At ?? 0,\n paidCost: entry?.Ac ?? 0,\n backlinks: entry?.Bk ?? 0,\n authorityScore: entry?.As ?? 0,\n } satisfies SemrushDomainOverview;\n },\n\n async getOrganicKeywords(domain, options?: SemrushPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const database = options?.database ?? DEFAULT_DATABASE;\n const params = buildOrganicKeywordsParams(domain, database, limit, offset);\n const raw = await http.get<SemrushApiResponse<SemrushRawKeywordResponse>>(\n organicKeywordsPath(),\n params,\n );\n const data: SemrushKeywordData[] = (raw.data ?? []).map((r) => ({\n keyword: r.Ph,\n position: r.Po,\n previousPosition: r.Pp,\n searchVolume: r.Nq,\n cpc: r.Cp,\n url: r.Ur,\n traffic: r.Tr,\n trafficPercent: r.Td,\n trafficCost: r.Tc,\n competition: r.Co,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<SemrushKeywordData>;\n },\n\n async getBacklinks(domain, options?: SemrushPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const params = buildBacklinksParams(domain, limit, offset);\n const raw = await http.get<SemrushApiResponse<SemrushRawBacklinkResponse>>(\n backlinksPath(),\n params,\n );\n const data: SemrushBacklinkData[] = (raw.data ?? []).map((r) => ({\n sourceUrl: r.source_url,\n targetUrl: r.target_url,\n anchorText: r.anchor,\n isNoFollow: r.nofollow,\n firstSeen: r.first_seen,\n lastSeen: r.last_seen,\n sourceAuthorityScore: r.source_ascore,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<SemrushBacklinkData>;\n },\n\n async getKeywordDifficulty(keywords, database = DEFAULT_DATABASE) {\n const params = buildKeywordDifficultyParams(keywords, database);\n const raw = await http.get<SemrushApiResponse<SemrushRawKeywordDifficultyResponse>>(\n keywordDifficultyPath(),\n params,\n );\n return (raw.data ?? []).map((r): SemrushKeywordDifficulty => ({\n keyword: r.Ph,\n difficulty: r.Kd,\n searchVolume: r.Nq,\n cpc: r.Cp,\n competition: r.Co,\n results: r.Nr,\n }));\n },\n\n async getRelatedKeywords(keyword, database = DEFAULT_DATABASE) {\n const params = buildRelatedKeywordsParams(keyword, database);\n const raw = await http.get<SemrushApiResponse<SemrushRawRelatedKeywordResponse>>(\n relatedKeywordsPath(),\n params,\n );\n return (raw.data ?? []).map((r): SemrushRelatedKeyword => ({\n keyword: r.Ph,\n searchVolume: r.Nq,\n cpc: r.Cp,\n competition: r.Co,\n results: r.Nr,\n relatedTo: r.Rr,\n }));\n },\n };\n}\n","// ============================================================================\n// @power-seo/integrations — Ahrefs Endpoints\n// ============================================================================\n\nexport const AHREFS_BASE_URL = 'https://api.ahrefs.com/v3';\n\nexport function siteOverviewPath(): string {\n return '/site-explorer/overview';\n}\n\nexport function organicKeywordsPath(): string {\n return '/site-explorer/organic-keywords';\n}\n\nexport function backlinksPath(): string {\n return '/site-explorer/backlinks';\n}\n\nexport function keywordDifficultyPath(): string {\n return '/keywords-explorer/keyword-difficulty';\n}\n\nexport function referringDomainsPath(): string {\n return '/site-explorer/referring-domains';\n}\n\nexport function buildSiteOverviewParams(domain: string): Record<string, string> {\n return { target: domain, mode: 'domain' };\n}\n\nexport function buildOrganicKeywordsParams(\n domain: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n target: domain,\n mode: 'domain',\n limit: String(limit),\n offset: String(offset),\n };\n}\n\nexport function buildBacklinksParams(\n domain: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n target: domain,\n mode: 'domain',\n limit: String(limit),\n offset: String(offset),\n };\n}\n\nexport function buildKeywordDifficultyParams(\n keywords: string[],\n): Record<string, string> {\n return {\n keywords: keywords.join(','),\n };\n}\n\nexport function buildReferringDomainsParams(\n domain: string,\n limit: number,\n offset: number,\n): Record<string, string> {\n return {\n target: domain,\n mode: 'domain',\n limit: String(limit),\n offset: String(offset),\n };\n}\n","// ============================================================================\n// @power-seo/integrations — Ahrefs Client\n// ============================================================================\n\nimport type {\n AhrefsClient,\n AhrefsSiteOverview,\n AhrefsOrganicKeyword,\n AhrefsBacklink,\n AhrefsKeywordDifficulty,\n AhrefsReferringDomain,\n PaginatedResponse,\n AhrefsPaginationOptions,\n HttpClientConfig,\n} from '../types.js';\nimport { createHttpClient } from '../http.js';\nimport {\n AHREFS_BASE_URL,\n siteOverviewPath,\n organicKeywordsPath,\n backlinksPath,\n keywordDifficultyPath,\n referringDomainsPath,\n buildSiteOverviewParams,\n buildOrganicKeywordsParams,\n buildBacklinksParams,\n buildKeywordDifficultyParams,\n buildReferringDomainsParams,\n} from './endpoints.js';\nimport type {\n AhrefsRawSiteOverview,\n AhrefsApiResponse,\n AhrefsRawOrganicKeyword,\n AhrefsRawBacklink,\n AhrefsRawKeywordDifficulty,\n AhrefsRawReferringDomain,\n} from './types.js';\n\nconst DEFAULT_LIMIT = 100;\n\nexport function createAhrefsClient(\n apiToken: string,\n config?: Partial<Omit<HttpClientConfig, 'baseUrl' | 'auth'>>,\n): AhrefsClient {\n const http = createHttpClient({\n baseUrl: AHREFS_BASE_URL,\n auth: { type: 'bearer', token: apiToken },\n ...config,\n });\n\n return {\n async getSiteOverview(domain) {\n const params = buildSiteOverviewParams(domain);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawSiteOverview>>(\n siteOverviewPath(),\n params,\n );\n const entry = raw.data[0];\n return {\n domain,\n domainRating: entry?.domain_rating ?? 0,\n urlRating: entry?.url_rating ?? 0,\n backlinks: entry?.backlinks ?? 0,\n referringDomains: entry?.referring_domains ?? 0,\n organicKeywords: entry?.organic_keywords ?? 0,\n organicTraffic: entry?.organic_traffic ?? 0,\n trafficValue: entry?.traffic_value ?? 0,\n } satisfies AhrefsSiteOverview;\n },\n\n async getOrganicKeywords(domain, options?: AhrefsPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const params = buildOrganicKeywordsParams(domain, limit, offset);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawOrganicKeyword>>(\n organicKeywordsPath(),\n params,\n );\n const data: AhrefsOrganicKeyword[] = (raw.data ?? []).map((r) => ({\n keyword: r.keyword,\n position: r.position,\n searchVolume: r.volume,\n cpc: r.cpc,\n url: r.url,\n traffic: r.traffic,\n trafficPercent: r.traffic_percent,\n difficulty: r.difficulty,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<AhrefsOrganicKeyword>;\n },\n\n async getBacklinks(domain, options?: AhrefsPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const params = buildBacklinksParams(domain, limit, offset);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawBacklink>>(\n backlinksPath(),\n params,\n );\n const data: AhrefsBacklink[] = (raw.data ?? []).map((r) => ({\n sourceUrl: r.url_from,\n targetUrl: r.url_to,\n anchorText: r.anchor,\n domainRating: r.domain_rating,\n urlRating: r.url_rating,\n isDoFollow: r.is_dofollow,\n firstSeen: r.first_seen,\n lastSeen: r.last_seen,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<AhrefsBacklink>;\n },\n\n async getKeywordDifficulty(keywords) {\n const params = buildKeywordDifficultyParams(keywords);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawKeywordDifficulty>>(\n keywordDifficultyPath(),\n params,\n );\n return (raw.data ?? []).map((r): AhrefsKeywordDifficulty => ({\n keyword: r.keyword,\n difficulty: r.difficulty,\n searchVolume: r.volume,\n cpc: r.cpc,\n clicks: r.clicks,\n globalVolume: r.global_volume,\n }));\n },\n\n async getReferringDomains(domain, options?: AhrefsPaginationOptions) {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const offset = options?.offset ?? 0;\n const params = buildReferringDomainsParams(domain, limit, offset);\n const raw = await http.get<AhrefsApiResponse<AhrefsRawReferringDomain>>(\n referringDomainsPath(),\n params,\n );\n const data: AhrefsReferringDomain[] = (raw.data ?? []).map((r) => ({\n domain: r.domain,\n domainRating: r.domain_rating,\n backlinks: r.backlinks,\n firstSeen: r.first_seen,\n lastSeen: r.last_seen,\n isDoFollow: r.is_dofollow,\n }));\n return {\n data,\n total: raw.total ?? 0,\n offset,\n limit,\n hasMore: data.length === limit,\n } satisfies PaginatedResponse<AhrefsReferringDomain>;\n },\n };\n}\n"]}
{
"name": "@power-seo/integrations",
"version": "1.0.0",
"version": "1.0.1",
"description": "Third-party SEO tool API clients for Semrush and Ahrefs with shared HTTP client",

@@ -9,5 +9,5 @@ "license": "MIT",

".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
"require": "./dist/index.cjs"
}

@@ -52,3 +52,3 @@ },

"type": "git",
"url": "https://github.com/cybercraftbd/ccbd-power-seo.git",
"url": "git+https://github.com/CyberCraftBD/power-seo.git",
"directory": "packages/integrations"

@@ -55,0 +55,0 @@ },

+69
-63

@@ -15,2 +15,8 @@ # @power-seo/integrations — Semrush & Ahrefs API Clients for TypeScript — Rate Limiting, Pagination & Full Type Safety

## Documentation
- **Package docs:** [`apps/docs/src/content/docs/packages/integrations.mdx`](../../apps/docs/src/content/docs/packages/integrations.mdx)
- **Ecosystem overview:** [`README.md`](../../README.md)
- **Contributing guide:** [`CONTRIBUTING.md`](../../CONTRIBUTING.md)
## Features

@@ -84,4 +90,4 @@

const semrush = createSemrushClient({
apiKey: process.env.SEMRUSH_API_KEY!,
database: 'us', // default: 'us'
apiKey: process.env.SEMRUSH_API_KEY!,
database: 'us', // default: 'us'
rateLimiting: { maxRequests: 10, windowMs: 60_000 }, // optional

@@ -98,3 +104,3 @@ });

const keyword: SemrushKeywordData = await semrush.getKeywordData({
keyword: 'react seo',
keyword: 'react seo',
database: 'us',

@@ -106,4 +112,4 @@ });

const backlinks = await semrush.getBacklinks({
domain: 'example.com',
limit: 100,
domain: 'example.com',
limit: 100,
});

@@ -128,3 +134,3 @@ // [{ sourcePage, targetPage, type, anchorText, firstSeen, lastSeen }]

const ahrefs = createAhrefsClient({
apiKey: process.env.AHREFS_API_KEY!,
apiKey: process.env.AHREFS_API_KEY!,
rateLimiting: { maxRequests: 5, windowMs: 60_000 }, // optional

@@ -136,3 +142,3 @@ });

target: 'example.com',
mode: 'domain', // 'domain' | 'subdomains' | 'exact'
mode: 'domain', // 'domain' | 'subdomains' | 'exact'
});

@@ -143,4 +149,4 @@ // { domainRating, urlRating, organicTraffic, organicKeywords, backlinks, referringDomains }

const keywords: AhrefsOrganicKeyword[] = await ahrefs.getOrganicKeywords({
target: 'example.com',
limit: 200,
target: 'example.com',
limit: 200,
orderBy: 'traffic:desc',

@@ -153,4 +159,4 @@ });

target: 'example.com',
limit: 100,
mode: 'domain',
limit: 100,
mode: 'domain',
});

@@ -165,4 +171,4 @@ // [{ anchorText, domainRating, urlFrom, urlTo, firstSeen, linkType }]

const domains = await ahrefs.getReferringDomains({
target: 'example.com',
limit: 50,
target: 'example.com',
limit: 50,
orderBy: 'domain_rating:desc',

@@ -181,7 +187,7 @@ });

const http = createHttpClient({
baseUrl: 'https://api.example.com',
headers: { Authorization: `Bearer ${token}` },
baseUrl: 'https://api.example.com',
headers: { Authorization: `Bearer ${token}` },
rateLimiting: {
maxRequests: 10, // max requests allowed
windowMs: 60_000, // per this window in ms
maxRequests: 10, // max requests allowed
windowMs: 60_000, // per this window in ms
},

@@ -220,3 +226,3 @@ });

```ts
function createSemrushClient(config: SemrushConfig): SemrushClient
function createSemrushClient(config: SemrushConfig): SemrushClient;
```

@@ -226,9 +232,9 @@

| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| `getDomainOverview` | `{ domain }` | `SemrushDomainOverview` | Traffic, keywords, backlinks summary |
| `getKeywordData` | `{ keyword, database? }` | `SemrushKeywordData` | Volume, CPC, competition, trend |
| `getBacklinks` | `{ domain, limit? }` | `SemrushBacklinkData[]` | Backlink list with follow/nofollow |
| `getKeywordDifficulty` | `{ keyword }` | `{ keyword, difficulty }` | KD score 0–100 |
| `getRelatedKeywords` | `{ keyword, limit? }` | `SemrushRelatedKeyword[]` | Related keyword suggestions |
| Method | Parameters | Returns | Description |
| ---------------------- | ------------------------ | ------------------------- | ------------------------------------ |
| `getDomainOverview` | `{ domain }` | `SemrushDomainOverview` | Traffic, keywords, backlinks summary |
| `getKeywordData` | `{ keyword, database? }` | `SemrushKeywordData` | Volume, CPC, competition, trend |
| `getBacklinks` | `{ domain, limit? }` | `SemrushBacklinkData[]` | Backlink list with follow/nofollow |
| `getKeywordDifficulty` | `{ keyword }` | `{ keyword, difficulty }` | KD score 0–100 |
| `getRelatedKeywords` | `{ keyword, limit? }` | `SemrushRelatedKeyword[]` | Related keyword suggestions |

@@ -238,3 +244,3 @@ ### Ahrefs

```ts
function createAhrefsClient(config: AhrefsConfig): AhrefsClient
function createAhrefsClient(config: AhrefsConfig): AhrefsClient;
```

@@ -244,9 +250,9 @@

| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| `getSiteOverview` | `{ target, mode? }` | `AhrefsSiteOverview` | DR, organic traffic, backlinks |
| `getOrganicKeywords` | `{ target, limit?, orderBy? }` | `AhrefsOrganicKeyword[]` | Ranking keywords with positions |
| `getBacklinks` | `{ target, limit?, mode? }` | `AhrefsBacklink[]` | Backlinks with anchor text |
| `getKeywordDifficulty` | `{ keyword }` | `{ keyword, difficulty }` | KD score 0–100 |
| `getReferringDomains` | `{ target, limit?, orderBy? }` | `AhrefsReferringDomain[]` | Referring domains by DR |
| Method | Parameters | Returns | Description |
| ---------------------- | ------------------------------ | ------------------------- | ------------------------------- |
| `getSiteOverview` | `{ target, mode? }` | `AhrefsSiteOverview` | DR, organic traffic, backlinks |
| `getOrganicKeywords` | `{ target, limit?, orderBy? }` | `AhrefsOrganicKeyword[]` | Ranking keywords with positions |
| `getBacklinks` | `{ target, limit?, mode? }` | `AhrefsBacklink[]` | Backlinks with anchor text |
| `getKeywordDifficulty` | `{ keyword }` | `{ keyword, difficulty }` | KD score 0–100 |
| `getReferringDomains` | `{ target, limit?, orderBy? }` | `AhrefsReferringDomain[]` | Referring domains by DR |

@@ -256,3 +262,3 @@ ### Shared

```ts
function createHttpClient(config: HttpClientConfig): HttpClient
function createHttpClient(config: HttpClientConfig): HttpClient;
```

@@ -262,7 +268,7 @@

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `baseUrl` | `string` | — | Base URL for all requests |
| `headers` | `Record<string, string>` | `{}` | Default request headers |
| `rateLimiting` | `{ maxRequests, windowMs }` | — | Optional rate limiting config |
| Prop | Type | Default | Description |
| -------------- | --------------------------- | ------- | ----------------------------- |
| `baseUrl` | `string` | — | Base URL for all requests |
| `headers` | `Record<string, string>` | `{}` | Default request headers |
| `rateLimiting` | `{ maxRequests, windowMs }` | — | Optional rate limiting config |

@@ -295,21 +301,21 @@ ### Types

| Package | Install | Description |
|---------|---------|-------------|
| [`@power-seo/core`](https://www.npmjs.com/package/@power-seo/core) | `npm i @power-seo/core` | Framework-agnostic utilities, types, validators, and constants |
| [`@power-seo/react`](https://www.npmjs.com/package/@power-seo/react) | `npm i @power-seo/react` | React SEO components — meta, Open Graph, Twitter Card, breadcrumbs |
| [`@power-seo/meta`](https://www.npmjs.com/package/@power-seo/meta) | `npm i @power-seo/meta` | SSR meta helpers for Next.js App Router, Remix v2, and generic SSR |
| [`@power-seo/schema`](https://www.npmjs.com/package/@power-seo/schema) | `npm i @power-seo/schema` | Type-safe JSON-LD structured data — 20 builders + 18 React components |
| [`@power-seo/content-analysis`](https://www.npmjs.com/package/@power-seo/content-analysis) | `npm i @power-seo/content-analysis` | Yoast-style SEO content scoring engine with React components |
| [`@power-seo/readability`](https://www.npmjs.com/package/@power-seo/readability) | `npm i @power-seo/readability` | Readability scoring — Flesch-Kincaid, Gunning Fog, Coleman-Liau, ARI |
| [`@power-seo/preview`](https://www.npmjs.com/package/@power-seo/preview) | `npm i @power-seo/preview` | SERP, Open Graph, and Twitter/X Card preview generators |
| [`@power-seo/sitemap`](https://www.npmjs.com/package/@power-seo/sitemap) | `npm i @power-seo/sitemap` | XML sitemap generation, streaming, index splitting, and validation |
| [`@power-seo/redirects`](https://www.npmjs.com/package/@power-seo/redirects) | `npm i @power-seo/redirects` | Redirect engine with Next.js, Remix, and Express adapters |
| [`@power-seo/links`](https://www.npmjs.com/package/@power-seo/links) | `npm i @power-seo/links` | Link graph analysis — orphan detection, suggestions, equity scoring |
| [`@power-seo/audit`](https://www.npmjs.com/package/@power-seo/audit) | `npm i @power-seo/audit` | Full SEO audit engine — meta, content, structure, performance rules |
| [`@power-seo/images`](https://www.npmjs.com/package/@power-seo/images) | `npm i @power-seo/images` | Image SEO — alt text, lazy loading, format analysis, image sitemaps |
| [`@power-seo/ai`](https://www.npmjs.com/package/@power-seo/ai) | `npm i @power-seo/ai` | LLM-agnostic AI prompt templates and parsers for SEO tasks |
| [`@power-seo/analytics`](https://www.npmjs.com/package/@power-seo/analytics) | `npm i @power-seo/analytics` | Merge GSC + audit data, trend analysis, ranking insights, dashboard |
| [`@power-seo/search-console`](https://www.npmjs.com/package/@power-seo/search-console) | `npm i @power-seo/search-console` | Google Search Console API — OAuth2, service account, URL inspection |
| [`@power-seo/integrations`](https://www.npmjs.com/package/@power-seo/integrations) | `npm i @power-seo/integrations` | Semrush and Ahrefs API clients with rate limiting and pagination |
| [`@power-seo/tracking`](https://www.npmjs.com/package/@power-seo/tracking) | `npm i @power-seo/tracking` | GA4, Clarity, PostHog, Plausible, Fathom — scripts + consent management |
| Package | Install | Description |
| ------------------------------------------------------------------------------------------ | ----------------------------------- | ----------------------------------------------------------------------- |
| [`@power-seo/core`](https://www.npmjs.com/package/@power-seo/core) | `npm i @power-seo/core` | Framework-agnostic utilities, types, validators, and constants |
| [`@power-seo/react`](https://www.npmjs.com/package/@power-seo/react) | `npm i @power-seo/react` | React SEO components — meta, Open Graph, Twitter Card, breadcrumbs |
| [`@power-seo/meta`](https://www.npmjs.com/package/@power-seo/meta) | `npm i @power-seo/meta` | SSR meta helpers for Next.js App Router, Remix v2, and generic SSR |
| [`@power-seo/schema`](https://www.npmjs.com/package/@power-seo/schema) | `npm i @power-seo/schema` | Type-safe JSON-LD structured data — 20 builders + 18 React components |
| [`@power-seo/content-analysis`](https://www.npmjs.com/package/@power-seo/content-analysis) | `npm i @power-seo/content-analysis` | Yoast-style SEO content scoring engine with React components |
| [`@power-seo/readability`](https://www.npmjs.com/package/@power-seo/readability) | `npm i @power-seo/readability` | Readability scoring — Flesch-Kincaid, Gunning Fog, Coleman-Liau, ARI |
| [`@power-seo/preview`](https://www.npmjs.com/package/@power-seo/preview) | `npm i @power-seo/preview` | SERP, Open Graph, and Twitter/X Card preview generators |
| [`@power-seo/sitemap`](https://www.npmjs.com/package/@power-seo/sitemap) | `npm i @power-seo/sitemap` | XML sitemap generation, streaming, index splitting, and validation |
| [`@power-seo/redirects`](https://www.npmjs.com/package/@power-seo/redirects) | `npm i @power-seo/redirects` | Redirect engine with Next.js, Remix, and Express adapters |
| [`@power-seo/links`](https://www.npmjs.com/package/@power-seo/links) | `npm i @power-seo/links` | Link graph analysis — orphan detection, suggestions, equity scoring |
| [`@power-seo/audit`](https://www.npmjs.com/package/@power-seo/audit) | `npm i @power-seo/audit` | Full SEO audit engine — meta, content, structure, performance rules |
| [`@power-seo/images`](https://www.npmjs.com/package/@power-seo/images) | `npm i @power-seo/images` | Image SEO — alt text, lazy loading, format analysis, image sitemaps |
| [`@power-seo/ai`](https://www.npmjs.com/package/@power-seo/ai) | `npm i @power-seo/ai` | LLM-agnostic AI prompt templates and parsers for SEO tasks |
| [`@power-seo/analytics`](https://www.npmjs.com/package/@power-seo/analytics) | `npm i @power-seo/analytics` | Merge GSC + audit data, trend analysis, ranking insights, dashboard |
| [`@power-seo/search-console`](https://www.npmjs.com/package/@power-seo/search-console) | `npm i @power-seo/search-console` | Google Search Console API — OAuth2, service account, URL inspection |
| [`@power-seo/integrations`](https://www.npmjs.com/package/@power-seo/integrations) | `npm i @power-seo/integrations` | Semrush and Ahrefs API clients with rate limiting and pagination |
| [`@power-seo/tracking`](https://www.npmjs.com/package/@power-seo/tracking) | `npm i @power-seo/tracking` | GA4, Clarity, PostHog, Plausible, Fathom — scripts + consent management |

@@ -322,9 +328,9 @@ ---

| | |
|---|---|
| **Website** | [ccbd.dev](https://ccbd.dev) |
| **GitHub** | [github.com/cybercraftbd](https://github.com/cybercraftbd) |
| | |
| -------------------- | -------------------------------------------------------------- |
| **Website** | [ccbd.dev](https://ccbd.dev) |
| **GitHub** | [github.com/cybercraftbd](https://github.com/cybercraftbd) |
| **npm Organization** | [npmjs.com/org/power-seo](https://www.npmjs.com/org/power-seo) |
| **Email** | [info@ccbd.dev](mailto:info@ccbd.dev) |
| **Email** | [info@ccbd.dev](mailto:info@ccbd.dev) |
© 2026 CyberCraft Bangladesh · Released under the [MIT License](../../LICENSE)