@hasna/skills 0.1.32 → 0.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -16
- package/bin/index.js +57 -14
- package/bin/mcp.js +57 -13
- package/dist/cli/commands/runtime.d.ts +1 -1
- package/dist/index.js +51 -5
- package/dist/lib/skill-validation.d.ts +2 -0
- package/package.json +1 -1
- package/skills/ad-creative-pack/package.json +4 -7
- package/skills/api-docs-portal/package.json +5 -3
- package/skills/audio/package.json +4 -22
- package/skills/audio-transcript-pack/package.json +3 -2
- package/skills/blog-article/package.json +5 -21
- package/skills/brand-kit/package.json +4 -7
- package/skills/brand-photo-shoot/package.json +3 -2
- package/skills/browse/README.md +13 -256
- package/skills/browse/SKILL.md +24 -45
- package/skills/browse/package.json +4 -33
- package/skills/contract-review-report/package.json +3 -2
- package/skills/customer-feedback-report/package.json +3 -2
- package/skills/deepresearch/CLAUDE.md +6 -39
- package/skills/deepresearch/README.md +15 -150
- package/skills/deepresearch/SKILL.md +23 -32
- package/skills/deepresearch/package.json +4 -37
- package/skills/domainpurchase/SKILL.md +14 -31
- package/skills/domainpurchase/package.json +3 -8
- package/skills/email-sequence/package.json +4 -7
- package/skills/generate-book-cover/package.json +5 -23
- package/skills/icon-pack/package.json +4 -22
- package/skills/image/README.md +13 -183
- package/skills/image/package.json +4 -22
- package/skills/invoice-reconciliation/package.json +3 -2
- package/skills/landing-page-pack/package.json +4 -7
- package/skills/logo-design/package.json +4 -2
- package/skills/managemcp/CLAUDE.md +9 -43
- package/skills/managemcp/README.md +12 -198
- package/skills/managemcp/package.json +2 -10
- package/skills/managemcp/tsconfig.json +1 -3
- package/skills/market-research-report/package.json +5 -4
- package/skills/meeting-pack/package.json +3 -2
- package/skills/migration-plan-pack/package.json +3 -2
- package/skills/music/package.json +4 -20
- package/skills/music-album/package.json +3 -2
- package/skills/one-page-website/package.json +3 -2
- package/skills/pdf-read/package.json +5 -23
- package/skills/pdf-to-dataset/package.json +5 -4
- package/skills/pdf-to-markdown/package.json +5 -4
- package/skills/performance-audit-report/package.json +3 -2
- package/skills/photo-album/package.json +4 -2
- package/skills/pitch-deck/package.json +5 -3
- package/skills/playlist-maker/package.json +4 -2
- package/skills/product-mockup/package.json +3 -2
- package/skills/proposal-pack/package.json +5 -4
- package/skills/read-pdf/package.json +4 -29
- package/skills/remove-background/package.json +5 -21
- package/skills/repo-onboarding-report/package.json +3 -2
- package/skills/sdk-generator/package.json +3 -2
- package/skills/security-audit-report/package.json +5 -4
- package/skills/seo-content-pack/package.json +5 -3
- package/skills/short-video-pack/package.json +3 -2
- package/skills/slide-deck-generator/package.json +3 -2
- package/skills/sms/README.md +18 -56
- package/skills/sms/package.json +1 -3
- package/skills/sms/tsconfig.json +1 -2
- package/skills/social-content-calendar/package.json +4 -7
- package/skills/test-suite-generator/package.json +5 -4
- package/skills/transcript/package.json +4 -23
- package/skills/video/package.json +4 -24
- package/skills/video-highlight-pack/package.json +3 -2
- package/skills/voiceover-jingle-pack/package.json +3 -2
- package/skills/webcrawling/CLAUDE.md +6 -17
- package/skills/webcrawling/README.md +13 -66
- package/skills/webcrawling/package.json +4 -32
- package/skills/browse/.env.example +0 -14
- package/skills/deepresearch/.env.example +0 -9
- package/skills/domainpurchase/.env.example +0 -7
- package/skills/domainpurchase/src/lib/api-client.ts +0 -571
- package/skills/domainpurchase/src/lib/config.ts +0 -209
- package/skills/domainpurchase/src/lib/installer.ts +0 -165
- package/skills/image/.env.example +0 -12
- package/skills/image/PROJECT_OVERVIEW.md +0 -216
- package/skills/image/QUICKSTART.md +0 -111
- package/skills/managemcp/.env.example +0 -16
- package/skills/managemcp/scripts/migrate.ts +0 -57
- package/skills/managemcp/scripts/seed.ts +0 -58
- package/skills/managemcp/src/db/index.ts +0 -37
- package/skills/managemcp/src/lib/api-client.ts +0 -108
- package/skills/managemcp/src/lib/config.ts +0 -34
- package/skills/managemcp/src/lib/installer.ts +0 -140
- package/skills/managemcp/src/lib/service-dir.ts +0 -119
- package/skills/sms/scripts/buy-number.ts +0 -63
- package/skills/sms/scripts/test-send.ts +0 -67
- package/skills/sms/src/server.ts +0 -351
- package/skills/sms/src/sse-server.ts +0 -279
- package/skills/transcript/.env.example +0 -10
- package/skills/webcrawling/.env.example +0 -2
|
@@ -1,571 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getApiKey,
|
|
3
|
-
getApiSecret,
|
|
4
|
-
getCustomerId,
|
|
5
|
-
getApiUrl,
|
|
6
|
-
useRemoteServer,
|
|
7
|
-
getRemoteServerUrl,
|
|
8
|
-
getRemoteApiKeyAsync,
|
|
9
|
-
} from "./config";
|
|
10
|
-
|
|
11
|
-
export interface Contact {
|
|
12
|
-
nameFirst: string;
|
|
13
|
-
nameLast: string;
|
|
14
|
-
email: string;
|
|
15
|
-
phone: string;
|
|
16
|
-
addressMailing: {
|
|
17
|
-
address1: string;
|
|
18
|
-
address2?: string;
|
|
19
|
-
city: string;
|
|
20
|
-
state: string;
|
|
21
|
-
postalCode: string;
|
|
22
|
-
country: string;
|
|
23
|
-
};
|
|
24
|
-
organization?: string;
|
|
25
|
-
encoding?: "ASCII" | "UTF-8";
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// V2 API consent format
|
|
29
|
-
export interface ConsentV2 {
|
|
30
|
-
agreedAt: string;
|
|
31
|
-
agreedBy: string;
|
|
32
|
-
agreementKeys: string[];
|
|
33
|
-
price: number; // Price in micro-units (e.g., 1500000 = $1.50)
|
|
34
|
-
currency: string; // ISO currency code (e.g., "USD")
|
|
35
|
-
registryPremiumPricing?: boolean;
|
|
36
|
-
claimToken?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// V2 API contacts format
|
|
40
|
-
export interface DomainContactsV2 {
|
|
41
|
-
admin?: Contact;
|
|
42
|
-
billing?: Contact;
|
|
43
|
-
registrant?: Contact;
|
|
44
|
-
tech?: Contact;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// V2 API purchase request format
|
|
48
|
-
export interface DomainPurchaseRequestV2 {
|
|
49
|
-
domain: string;
|
|
50
|
-
consent: ConsentV2;
|
|
51
|
-
contacts?: DomainContactsV2;
|
|
52
|
-
nameServers?: string[];
|
|
53
|
-
period?: number;
|
|
54
|
-
privacy?: boolean;
|
|
55
|
-
renewAuto?: boolean;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Legacy interface for backwards compatibility
|
|
59
|
-
export interface DomainPurchaseRequest {
|
|
60
|
-
domain: string;
|
|
61
|
-
consent: {
|
|
62
|
-
agreedAt: string;
|
|
63
|
-
agreedBy: string;
|
|
64
|
-
agreementKeys: string[];
|
|
65
|
-
price?: number;
|
|
66
|
-
currency?: string;
|
|
67
|
-
};
|
|
68
|
-
contactAdmin?: Contact;
|
|
69
|
-
contactBilling?: Contact;
|
|
70
|
-
contactRegistrant: Contact;
|
|
71
|
-
contactTech?: Contact;
|
|
72
|
-
nameServers?: string[];
|
|
73
|
-
period?: number;
|
|
74
|
-
privacy?: boolean;
|
|
75
|
-
renewAuto?: boolean;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Convert legacy request to V2 format
|
|
79
|
-
export function toV2Request(request: DomainPurchaseRequest, price: number, currency: string): DomainPurchaseRequestV2 {
|
|
80
|
-
return {
|
|
81
|
-
domain: request.domain,
|
|
82
|
-
consent: {
|
|
83
|
-
agreedAt: request.consent.agreedAt,
|
|
84
|
-
agreedBy: request.consent.agreedBy,
|
|
85
|
-
agreementKeys: request.consent.agreementKeys,
|
|
86
|
-
price: request.consent.price ?? price,
|
|
87
|
-
currency: request.consent.currency ?? currency,
|
|
88
|
-
},
|
|
89
|
-
contacts: {
|
|
90
|
-
registrant: request.contactRegistrant,
|
|
91
|
-
admin: request.contactAdmin,
|
|
92
|
-
billing: request.contactBilling,
|
|
93
|
-
tech: request.contactTech,
|
|
94
|
-
},
|
|
95
|
-
nameServers: request.nameServers,
|
|
96
|
-
period: request.period,
|
|
97
|
-
privacy: request.privacy,
|
|
98
|
-
renewAuto: request.renewAuto,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export interface DomainAvailability {
|
|
103
|
-
domain: string;
|
|
104
|
-
available: boolean;
|
|
105
|
-
price?: number;
|
|
106
|
-
currency?: string;
|
|
107
|
-
period?: number;
|
|
108
|
-
definitive?: boolean;
|
|
109
|
-
registryPremiumPricing?: boolean;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export interface Agreement {
|
|
113
|
-
agreementKey: string;
|
|
114
|
-
title: string;
|
|
115
|
-
url: string;
|
|
116
|
-
content?: string;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface DomainDetails {
|
|
120
|
-
domain: string;
|
|
121
|
-
status: string;
|
|
122
|
-
createdAt: string;
|
|
123
|
-
expires: string;
|
|
124
|
-
renewAuto: boolean;
|
|
125
|
-
privacy: boolean;
|
|
126
|
-
nameServers?: string[];
|
|
127
|
-
contactAdmin?: Contact;
|
|
128
|
-
contactBilling?: Contact;
|
|
129
|
-
contactRegistrant?: Contact;
|
|
130
|
-
contactTech?: Contact;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function getHeaders() {
|
|
134
|
-
const apiKey = getApiKey();
|
|
135
|
-
const apiSecret = getApiSecret();
|
|
136
|
-
|
|
137
|
-
if (!apiKey || !apiSecret) {
|
|
138
|
-
throw new Error(
|
|
139
|
-
"API credentials not configured. Run: service-domainpurchase config --api-key <key> --api-secret <secret>"
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
Authorization: `sso-key ${apiKey}:${apiSecret}`,
|
|
145
|
-
"Content-Type": "application/json",
|
|
146
|
-
Accept: "application/json",
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async function apiRequest<T>(
|
|
151
|
-
endpoint: string,
|
|
152
|
-
method: string = "GET",
|
|
153
|
-
body?: any
|
|
154
|
-
): Promise<{ status: number; data: T; ok: boolean }> {
|
|
155
|
-
const baseUrl = getApiUrl();
|
|
156
|
-
const url = `${baseUrl}${endpoint}`;
|
|
157
|
-
|
|
158
|
-
const options: RequestInit = {
|
|
159
|
-
method,
|
|
160
|
-
headers: getHeaders(),
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
if (body) {
|
|
164
|
-
options.body = JSON.stringify(body);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const response = await fetch(url, options);
|
|
168
|
-
const text = await response.text();
|
|
169
|
-
|
|
170
|
-
let data: T;
|
|
171
|
-
try {
|
|
172
|
-
data = JSON.parse(text);
|
|
173
|
-
} catch {
|
|
174
|
-
data = { rawResponse: text.substring(0, 500) } as T;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
status: response.status,
|
|
179
|
-
data,
|
|
180
|
-
ok: response.ok || response.status === 203,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export const purchaseApi = {
|
|
185
|
-
// Check single domain availability with pricing
|
|
186
|
-
async checkAvailability(
|
|
187
|
-
domain: string,
|
|
188
|
-
forTransfer: boolean = false
|
|
189
|
-
): Promise<DomainAvailability> {
|
|
190
|
-
const type = forTransfer ? "TRANSFER" : "REGISTRATION";
|
|
191
|
-
const result = await apiRequest<DomainAvailability>(
|
|
192
|
-
`/v2/domains/available?domain=${encodeURIComponent(domain)}&type=${type}&optimizeFor=ACCURACY`
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
if (!result.ok) {
|
|
196
|
-
throw new Error(`API Error: ${JSON.stringify(result.data)}`);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return result.data;
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
// Get legal agreements for domain purchase
|
|
203
|
-
async getAgreements(tlds: string[], privacy: boolean = false): Promise<Agreement[]> {
|
|
204
|
-
const customerId = getCustomerId();
|
|
205
|
-
if (!customerId) {
|
|
206
|
-
throw new Error("Customer ID not configured");
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const result = await apiRequest<Agreement[]>(
|
|
210
|
-
`/v2/customers/${customerId}/domains/agreements?tlds=${tlds.join(",")}&privacy=${privacy}`
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
if (!result.ok) {
|
|
214
|
-
throw new Error(`API Error: ${JSON.stringify(result.data)}`);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return result.data;
|
|
218
|
-
},
|
|
219
|
-
|
|
220
|
-
// Validate domain purchase request (dry run) - V2 API
|
|
221
|
-
async validatePurchase(request: DomainPurchaseRequestV2): Promise<any> {
|
|
222
|
-
const customerId = getCustomerId();
|
|
223
|
-
if (!customerId) {
|
|
224
|
-
throw new Error("Customer ID not configured");
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const result = await apiRequest<any>(
|
|
228
|
-
`/v2/customers/${customerId}/domains/register/validate`,
|
|
229
|
-
"POST",
|
|
230
|
-
request
|
|
231
|
-
);
|
|
232
|
-
|
|
233
|
-
return {
|
|
234
|
-
valid: result.ok,
|
|
235
|
-
status: result.status,
|
|
236
|
-
data: result.data,
|
|
237
|
-
};
|
|
238
|
-
},
|
|
239
|
-
|
|
240
|
-
// Purchase domain - V2 API
|
|
241
|
-
async purchaseDomain(request: DomainPurchaseRequestV2): Promise<any> {
|
|
242
|
-
const customerId = getCustomerId();
|
|
243
|
-
if (!customerId) {
|
|
244
|
-
throw new Error("Customer ID not configured");
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const result = await apiRequest<any>(
|
|
248
|
-
`/v2/customers/${customerId}/domains/register`,
|
|
249
|
-
"POST",
|
|
250
|
-
request
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
// 202 Accepted is success for registration
|
|
254
|
-
if (!result.ok && result.status !== 202) {
|
|
255
|
-
throw new Error(`Purchase failed: ${JSON.stringify(result.data)}`);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return result.data;
|
|
259
|
-
},
|
|
260
|
-
|
|
261
|
-
// Get domain details
|
|
262
|
-
async getDomainDetails(domain: string): Promise<DomainDetails> {
|
|
263
|
-
const customerId = getCustomerId();
|
|
264
|
-
if (!customerId) {
|
|
265
|
-
throw new Error("Customer ID not configured");
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const result = await apiRequest<DomainDetails>(
|
|
269
|
-
`/v2/customers/${customerId}/domains/${encodeURIComponent(domain)}?includes=contacts,nameServers`
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
if (!result.ok) {
|
|
273
|
-
throw new Error(`API Error: ${JSON.stringify(result.data)}`);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return result.data;
|
|
277
|
-
},
|
|
278
|
-
|
|
279
|
-
// Update domain settings
|
|
280
|
-
async updateDomain(
|
|
281
|
-
domain: string,
|
|
282
|
-
updates: {
|
|
283
|
-
renewAuto?: boolean;
|
|
284
|
-
privacy?: boolean;
|
|
285
|
-
nameServers?: string[];
|
|
286
|
-
}
|
|
287
|
-
): Promise<any> {
|
|
288
|
-
const customerId = getCustomerId();
|
|
289
|
-
if (!customerId) {
|
|
290
|
-
throw new Error("Customer ID not configured");
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const result = await apiRequest<any>(
|
|
294
|
-
`/v2/customers/${customerId}/domains/${encodeURIComponent(domain)}`,
|
|
295
|
-
"PATCH",
|
|
296
|
-
updates
|
|
297
|
-
);
|
|
298
|
-
|
|
299
|
-
if (!result.ok) {
|
|
300
|
-
throw new Error(`Update failed: ${JSON.stringify(result.data)}`);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return result.data;
|
|
304
|
-
},
|
|
305
|
-
|
|
306
|
-
// Renew domain
|
|
307
|
-
async renewDomain(domain: string, period: number = 1): Promise<any> {
|
|
308
|
-
const customerId = getCustomerId();
|
|
309
|
-
if (!customerId) {
|
|
310
|
-
throw new Error("Customer ID not configured");
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const result = await apiRequest<any>(
|
|
314
|
-
`/v2/customers/${customerId}/domains/${encodeURIComponent(domain)}/renew`,
|
|
315
|
-
"POST",
|
|
316
|
-
{ period }
|
|
317
|
-
);
|
|
318
|
-
|
|
319
|
-
if (!result.ok) {
|
|
320
|
-
throw new Error(`Renewal failed: ${JSON.stringify(result.data)}`);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return result.data;
|
|
324
|
-
},
|
|
325
|
-
|
|
326
|
-
// List owned domains
|
|
327
|
-
async listOwnedDomains(limit: number = 100): Promise<any[]> {
|
|
328
|
-
const customerId = getCustomerId();
|
|
329
|
-
if (!customerId) {
|
|
330
|
-
throw new Error("Customer ID not configured");
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const result = await apiRequest<any[]>(
|
|
334
|
-
`/v2/customers/${customerId}/domains?limit=${limit}`
|
|
335
|
-
);
|
|
336
|
-
|
|
337
|
-
if (!result.ok) {
|
|
338
|
-
throw new Error(`API Error: ${JSON.stringify(result.data)}`);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
return result.data;
|
|
342
|
-
},
|
|
343
|
-
|
|
344
|
-
// Delete/cancel domain (if allowed)
|
|
345
|
-
async deleteDomain(domain: string): Promise<any> {
|
|
346
|
-
const customerId = getCustomerId();
|
|
347
|
-
if (!customerId) {
|
|
348
|
-
throw new Error("Customer ID not configured");
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
const result = await apiRequest<any>(
|
|
352
|
-
`/v2/customers/${customerId}/domains/${encodeURIComponent(domain)}`,
|
|
353
|
-
"DELETE"
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
if (!result.ok) {
|
|
357
|
-
throw new Error(`Delete failed: ${JSON.stringify(result.data)}`);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return result.data;
|
|
361
|
-
},
|
|
362
|
-
|
|
363
|
-
// Transfer domain in
|
|
364
|
-
async initiateTransfer(
|
|
365
|
-
domain: string,
|
|
366
|
-
authCode: string,
|
|
367
|
-
consent: DomainPurchaseRequest["consent"],
|
|
368
|
-
contact: Contact
|
|
369
|
-
): Promise<any> {
|
|
370
|
-
const customerId = getCustomerId();
|
|
371
|
-
if (!customerId) {
|
|
372
|
-
throw new Error("Customer ID not configured");
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
const result = await apiRequest<any>(
|
|
376
|
-
`/v2/customers/${customerId}/domains/${encodeURIComponent(domain)}/transfer`,
|
|
377
|
-
"POST",
|
|
378
|
-
{
|
|
379
|
-
authCode,
|
|
380
|
-
consent,
|
|
381
|
-
contactRegistrant: contact,
|
|
382
|
-
}
|
|
383
|
-
);
|
|
384
|
-
|
|
385
|
-
if (!result.ok) {
|
|
386
|
-
throw new Error(`Transfer failed: ${JSON.stringify(result.data)}`);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
return result.data;
|
|
390
|
-
},
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
// Format price from micro-units to dollars
|
|
394
|
-
export function formatPrice(
|
|
395
|
-
microUnits: number,
|
|
396
|
-
currency: string = "USD"
|
|
397
|
-
): string {
|
|
398
|
-
return `${currency} ${(microUnits / 1000000).toFixed(2)}`;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// ============ REMOTE SERVER API ============
|
|
402
|
-
// When useRemoteServer is enabled, calls go through the remote server
|
|
403
|
-
// instead of directly to the GoDaddy API. This simplifies credential management.
|
|
404
|
-
|
|
405
|
-
async function remoteApiRequest<T>(
|
|
406
|
-
endpoint: string,
|
|
407
|
-
method: string = "GET",
|
|
408
|
-
body?: any
|
|
409
|
-
): Promise<{ status: number; data: T; ok: boolean }> {
|
|
410
|
-
const baseUrl = getRemoteServerUrl();
|
|
411
|
-
const apiKey = await getRemoteApiKeyAsync();
|
|
412
|
-
const url = `${baseUrl}${endpoint}`;
|
|
413
|
-
|
|
414
|
-
const headers: Record<string, string> = {
|
|
415
|
-
"Content-Type": "application/json",
|
|
416
|
-
Accept: "application/json",
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
if (apiKey) {
|
|
420
|
-
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
const options: RequestInit = {
|
|
424
|
-
method,
|
|
425
|
-
headers,
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
if (body) {
|
|
429
|
-
options.body = JSON.stringify(body);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
const response = await fetch(url, options);
|
|
433
|
-
const text = await response.text();
|
|
434
|
-
|
|
435
|
-
let data: T;
|
|
436
|
-
try {
|
|
437
|
-
data = JSON.parse(text);
|
|
438
|
-
} catch {
|
|
439
|
-
data = { rawResponse: text.substring(0, 500) } as T;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
return {
|
|
443
|
-
status: response.status,
|
|
444
|
-
data,
|
|
445
|
-
ok: response.ok,
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// Remote server API - proxies requests through the configured remote server
|
|
450
|
-
export const remoteApi = {
|
|
451
|
-
async checkAvailability(domain: string): Promise<DomainAvailability> {
|
|
452
|
-
const result = await remoteApiRequest<DomainAvailability>(
|
|
453
|
-
`/check?domain=${encodeURIComponent(domain)}`
|
|
454
|
-
);
|
|
455
|
-
if (!result.ok) {
|
|
456
|
-
throw new Error(`API Error: ${JSON.stringify(result.data)}`);
|
|
457
|
-
}
|
|
458
|
-
return result.data;
|
|
459
|
-
},
|
|
460
|
-
|
|
461
|
-
async getAgreements(tlds: string[], privacy: boolean = false): Promise<Agreement[]> {
|
|
462
|
-
const result = await remoteApiRequest<Agreement[]>(
|
|
463
|
-
`/agreements?tlds=${tlds.join(",")}&privacy=${privacy}`
|
|
464
|
-
);
|
|
465
|
-
if (!result.ok) {
|
|
466
|
-
throw new Error(`API Error: ${JSON.stringify(result.data)}`);
|
|
467
|
-
}
|
|
468
|
-
return result.data;
|
|
469
|
-
},
|
|
470
|
-
|
|
471
|
-
async validatePurchase(request: DomainPurchaseRequestV2): Promise<any> {
|
|
472
|
-
const result = await remoteApiRequest<any>("/validate", "POST", request);
|
|
473
|
-
return {
|
|
474
|
-
valid: result.ok,
|
|
475
|
-
status: result.status,
|
|
476
|
-
data: result.data,
|
|
477
|
-
};
|
|
478
|
-
},
|
|
479
|
-
|
|
480
|
-
async purchaseDomain(request: DomainPurchaseRequestV2): Promise<any> {
|
|
481
|
-
const result = await remoteApiRequest<any>("/purchase", "POST", request);
|
|
482
|
-
if (!result.ok && result.status !== 202) {
|
|
483
|
-
throw new Error(`Purchase failed: ${JSON.stringify(result.data)}`);
|
|
484
|
-
}
|
|
485
|
-
return result.data;
|
|
486
|
-
},
|
|
487
|
-
|
|
488
|
-
async listOwnedDomains(limit: number = 100): Promise<any[]> {
|
|
489
|
-
const result = await remoteApiRequest<any[]>(`/list?limit=${limit}`);
|
|
490
|
-
if (!result.ok) {
|
|
491
|
-
throw new Error(`API Error: ${JSON.stringify(result.data)}`);
|
|
492
|
-
}
|
|
493
|
-
return result.data;
|
|
494
|
-
},
|
|
495
|
-
|
|
496
|
-
async getDomainDetails(domain: string): Promise<DomainDetails> {
|
|
497
|
-
const result = await remoteApiRequest<DomainDetails>(
|
|
498
|
-
`/info?domain=${encodeURIComponent(domain)}`
|
|
499
|
-
);
|
|
500
|
-
if (!result.ok) {
|
|
501
|
-
throw new Error(`API Error: ${JSON.stringify(result.data)}`);
|
|
502
|
-
}
|
|
503
|
-
return result.data;
|
|
504
|
-
},
|
|
505
|
-
|
|
506
|
-
async updateDomain(
|
|
507
|
-
domain: string,
|
|
508
|
-
updates: { renewAuto?: boolean; privacy?: boolean; nameServers?: string[] }
|
|
509
|
-
): Promise<any> {
|
|
510
|
-
const result = await remoteApiRequest<any>(
|
|
511
|
-
`/update?domain=${encodeURIComponent(domain)}`,
|
|
512
|
-
"PUT",
|
|
513
|
-
updates
|
|
514
|
-
);
|
|
515
|
-
if (!result.ok) {
|
|
516
|
-
throw new Error(`Update failed: ${JSON.stringify(result.data)}`);
|
|
517
|
-
}
|
|
518
|
-
return result.data;
|
|
519
|
-
},
|
|
520
|
-
|
|
521
|
-
async renewDomain(domain: string, period: number = 1): Promise<any> {
|
|
522
|
-
const result = await remoteApiRequest<any>("/renew", "POST", { domain, period });
|
|
523
|
-
if (!result.ok) {
|
|
524
|
-
throw new Error(`Renewal failed: ${JSON.stringify(result.data)}`);
|
|
525
|
-
}
|
|
526
|
-
return result.data;
|
|
527
|
-
},
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
// Smart API that automatically chooses between direct and remote based on config
|
|
531
|
-
export const domainApi = {
|
|
532
|
-
checkAvailability: (domain: string, forTransfer?: boolean) =>
|
|
533
|
-
useRemoteServer()
|
|
534
|
-
? remoteApi.checkAvailability(domain)
|
|
535
|
-
: purchaseApi.checkAvailability(domain, forTransfer),
|
|
536
|
-
|
|
537
|
-
getAgreements: (tlds: string[], privacy?: boolean) =>
|
|
538
|
-
useRemoteServer()
|
|
539
|
-
? remoteApi.getAgreements(tlds, privacy)
|
|
540
|
-
: purchaseApi.getAgreements(tlds, privacy),
|
|
541
|
-
|
|
542
|
-
validatePurchase: (request: DomainPurchaseRequestV2) =>
|
|
543
|
-
useRemoteServer()
|
|
544
|
-
? remoteApi.validatePurchase(request)
|
|
545
|
-
: purchaseApi.validatePurchase(request),
|
|
546
|
-
|
|
547
|
-
purchaseDomain: (request: DomainPurchaseRequestV2) =>
|
|
548
|
-
useRemoteServer()
|
|
549
|
-
? remoteApi.purchaseDomain(request)
|
|
550
|
-
: purchaseApi.purchaseDomain(request),
|
|
551
|
-
|
|
552
|
-
listOwnedDomains: (limit?: number) =>
|
|
553
|
-
useRemoteServer()
|
|
554
|
-
? remoteApi.listOwnedDomains(limit)
|
|
555
|
-
: purchaseApi.listOwnedDomains(limit),
|
|
556
|
-
|
|
557
|
-
getDomainDetails: (domain: string) =>
|
|
558
|
-
useRemoteServer()
|
|
559
|
-
? remoteApi.getDomainDetails(domain)
|
|
560
|
-
: purchaseApi.getDomainDetails(domain),
|
|
561
|
-
|
|
562
|
-
updateDomain: (domain: string, updates: any) =>
|
|
563
|
-
useRemoteServer()
|
|
564
|
-
? remoteApi.updateDomain(domain, updates)
|
|
565
|
-
: purchaseApi.updateDomain(domain, updates),
|
|
566
|
-
|
|
567
|
-
renewDomain: (domain: string, period?: number) =>
|
|
568
|
-
useRemoteServer()
|
|
569
|
-
? remoteApi.renewDomain(domain, period)
|
|
570
|
-
: purchaseApi.renewDomain(domain, period),
|
|
571
|
-
};
|