1+ import { NamecheapClient } from './namecheap-client.js' ;
2+
3+ interface TldInfo {
4+ name : string ;
5+ isApiRegisterable : boolean ;
6+ isRenewalAllowed : boolean ;
7+ minRegisterYears : number ;
8+ maxRegisterYears : number ;
9+ minRenewYears : number ;
10+ maxRenewYears : number ;
11+ isTransferrable : boolean ;
12+ transferLockDays : number ;
13+ isPrivacyProtectionAllowed : boolean ;
14+ isIdnSupported : boolean ;
15+ supportedIdnLanguages ?: string [ ] ;
16+ categories ?: string [ ] ;
17+ isPremium ?: boolean ;
18+ }
19+
20+ export class TldCache {
21+ private cache : TldInfo [ ] | null = null ;
22+ private cacheTimestamp : number = 0 ;
23+ private readonly CACHE_DURATION = 24 * 60 * 60 * 1000 ; // 24 hours
24+ private readonly client : NamecheapClient ;
25+
26+ constructor ( client : NamecheapClient ) {
27+ this . client = client ;
28+ }
29+
30+ private async fetchAndParseTldList ( ) : Promise < TldInfo [ ] > {
31+ const response = await this . client . domainsGetTldList ( ) ;
32+ const tlds : TldInfo [ ] = [ ] ;
33+
34+ // Parse the XML response to extract TLD information
35+ if ( response && typeof response === 'object' && 'raw' in response && typeof response . raw === 'string' ) {
36+ // Simple regex parsing for demonstration
37+ // In production, use a proper XML parser
38+ const tldMatches = response . raw . matchAll ( / < T l d N a m e = " ( [ ^ " ] + ) " [ ^ > ] * > / g) ;
39+
40+ for ( const match of tldMatches ) {
41+ const tldElement = match [ 0 ] ;
42+ const name = match [ 1 ] ;
43+
44+ tlds . push ( {
45+ name,
46+ isApiRegisterable : tldElement . includes ( 'IsApiRegisterable="true"' ) ,
47+ isRenewalAllowed : tldElement . includes ( 'IsApiRenewalAllowed="true"' ) ,
48+ minRegisterYears : parseInt ( tldElement . match ( / M i n R e g i s t e r Y e a r s = " ( \d + ) " / ) ?. [ 1 ] || '1' ) ,
49+ maxRegisterYears : parseInt ( tldElement . match ( / M a x R e g i s t e r Y e a r s = " ( \d + ) " / ) ?. [ 1 ] || '10' ) ,
50+ minRenewYears : parseInt ( tldElement . match ( / M i n R e n e w Y e a r s = " ( \d + ) " / ) ?. [ 1 ] || '1' ) ,
51+ maxRenewYears : parseInt ( tldElement . match ( / M a x R e n e w Y e a r s = " ( \d + ) " / ) ?. [ 1 ] || '10' ) ,
52+ isTransferrable : ! tldElement . includes ( 'IsApiTransferrable="false"' ) ,
53+ transferLockDays : parseInt ( tldElement . match ( / T r a n s f e r L o c k D a y s = " ( \d + ) " / ) ?. [ 1 ] || '60' ) ,
54+ isPrivacyProtectionAllowed : ! tldElement . includes ( 'IsPrivacyProtectionAllowed="false"' ) ,
55+ isIdnSupported : tldElement . includes ( 'IsIdnSupported="true"' ) ,
56+ isPremium : tldElement . includes ( 'IsPremiumTLD="true"' ) ,
57+ } ) ;
58+ }
59+ }
60+
61+ return tlds ;
62+ }
63+
64+ private async ensureCache ( ) : Promise < TldInfo [ ] > {
65+ const now = Date . now ( ) ;
66+
67+ if ( ! this . cache || ( now - this . cacheTimestamp ) > this . CACHE_DURATION ) {
68+ this . cache = await this . fetchAndParseTldList ( ) ;
69+ this . cacheTimestamp = now ;
70+ }
71+
72+ return this . cache ;
73+ }
74+
75+ async getTlds ( options ?: {
76+ search ?: string ;
77+ category ?: string ;
78+ registerable ?: boolean ;
79+ page ?: number ;
80+ pageSize ?: number ;
81+ sortBy ?: 'name' | 'popularity' ;
82+ } ) : Promise < {
83+ tlds : TldInfo [ ] ;
84+ totalCount : number ;
85+ page : number ;
86+ pageSize : number ;
87+ totalPages : number ;
88+ } > {
89+ const allTlds = await this . ensureCache ( ) ;
90+
91+ // Apply filters
92+ let filteredTlds = [ ...allTlds ] ;
93+
94+ if ( options ?. search ) {
95+ const searchLower = options . search . toLowerCase ( ) ;
96+ filteredTlds = filteredTlds . filter ( tld =>
97+ tld . name . toLowerCase ( ) . includes ( searchLower )
98+ ) ;
99+ }
100+
101+ if ( options ?. registerable !== undefined ) {
102+ filteredTlds = filteredTlds . filter ( tld =>
103+ tld . isApiRegisterable === options . registerable
104+ ) ;
105+ }
106+
107+ if ( options ?. category ) {
108+ filteredTlds = filteredTlds . filter ( tld =>
109+ tld . categories ?. includes ( options . category ! )
110+ ) ;
111+ }
112+
113+ // Sort
114+ if ( options ?. sortBy === 'name' ) {
115+ filteredTlds . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
116+ }
117+
118+ // Paginate
119+ const page = options ?. page || 1 ;
120+ const pageSize = options ?. pageSize || 50 ;
121+ const totalCount = filteredTlds . length ;
122+ const totalPages = Math . ceil ( totalCount / pageSize ) ;
123+ const startIndex = ( page - 1 ) * pageSize ;
124+ const endIndex = startIndex + pageSize ;
125+
126+ const paginatedTlds = filteredTlds . slice ( startIndex , endIndex ) ;
127+
128+ return {
129+ tlds : paginatedTlds ,
130+ totalCount,
131+ page,
132+ pageSize,
133+ totalPages,
134+ } ;
135+ }
136+
137+ async refreshCache ( ) : Promise < void > {
138+ this . cache = null ;
139+ this . cacheTimestamp = 0 ;
140+ await this . ensureCache ( ) ;
141+ }
142+ }
0 commit comments