@framers/agentos-ext-domain-porkbun 0.1.0
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/LICENSE +98 -0
- package/dist/PorkbunService.d.ts +119 -0
- package/dist/PorkbunService.d.ts.map +1 -0
- package/dist/PorkbunService.js +224 -0
- package/dist/PorkbunService.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/configureDns.d.ts +75 -0
- package/dist/tools/configureDns.d.ts.map +1 -0
- package/dist/tools/configureDns.js +91 -0
- package/dist/tools/configureDns.js.map +1 -0
- package/dist/tools/listDomains.d.ts +26 -0
- package/dist/tools/listDomains.d.ts.map +1 -0
- package/dist/tools/listDomains.js +32 -0
- package/dist/tools/listDomains.js.map +1 -0
- package/dist/tools/registerDomain.d.ts +89 -0
- package/dist/tools/registerDomain.d.ts.map +1 -0
- package/dist/tools/registerDomain.js +58 -0
- package/dist/tools/registerDomain.js.map +1 -0
- package/dist/tools/searchDomain.d.ts +34 -0
- package/dist/tools/searchDomain.d.ts.map +1 -0
- package/dist/tools/searchDomain.js +34 -0
- package/dist/tools/searchDomain.js.map +1 -0
- package/dist/tools/transferDomain.d.ts +39 -0
- package/dist/tools/transferDomain.d.ts.map +1 -0
- package/dist/tools/transferDomain.js +35 -0
- package/dist/tools/transferDomain.js.map +1 -0
- package/manifest.json +33 -0
- package/package.json +65 -0
- package/src/PorkbunService.ts +327 -0
- package/src/index.ts +133 -0
- package/src/tools/configureDns.ts +114 -0
- package/src/tools/listDomains.ts +33 -0
- package/src/tools/registerDomain.ts +74 -0
- package/src/tools/searchDomain.ts +39 -0
- package/src/tools/transferDomain.ts +41 -0
- package/test/PorkbunService.test.ts +434 -0
- package/test/index.test.ts +50 -0
- package/test/tools.test.ts +399 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
3
|
+
import { PorkbunConfigureDnsTool } from '../src/tools/configureDns';
|
|
4
|
+
import { PorkbunListDomainsTool } from '../src/tools/listDomains';
|
|
5
|
+
import { PorkbunRegisterDomainTool } from '../src/tools/registerDomain';
|
|
6
|
+
import { PorkbunSearchDomainTool } from '../src/tools/searchDomain';
|
|
7
|
+
import { PorkbunTransferDomainTool } from '../src/tools/transferDomain';
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// PorkbunConfigureDnsTool
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
describe('PorkbunConfigureDnsTool', () => {
|
|
14
|
+
let service: any;
|
|
15
|
+
let tool: PorkbunConfigureDnsTool;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
service = {
|
|
19
|
+
listDnsRecords: vi.fn(),
|
|
20
|
+
createDnsRecord: vi.fn(),
|
|
21
|
+
deleteDnsRecord: vi.fn(),
|
|
22
|
+
editDnsRecord: vi.fn(),
|
|
23
|
+
};
|
|
24
|
+
tool = new PorkbunConfigureDnsTool(service);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should have correct metadata', () => {
|
|
28
|
+
expect(tool.id).toBe('porkbunConfigureDns');
|
|
29
|
+
expect(tool.name).toBe('porkbunConfigureDns');
|
|
30
|
+
expect(tool.displayName).toBe('Configure DNS Records');
|
|
31
|
+
expect(tool.inputSchema.type).toBe('object');
|
|
32
|
+
expect(tool.inputSchema.required).toContain('domain');
|
|
33
|
+
expect(tool.category).toBe('domain');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should list DNS records by default', async () => {
|
|
37
|
+
service.listDnsRecords.mockResolvedValue([
|
|
38
|
+
{ id: '1', type: 'A', name: 'www', content: '1.2.3.4', ttl: '300' },
|
|
39
|
+
{ id: '2', type: 'MX', name: '', content: 'mx.example.com', ttl: '600', prio: '10' },
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
const result = await tool.execute({ domain: 'example.com' });
|
|
43
|
+
|
|
44
|
+
expect(result.success).toBe(true);
|
|
45
|
+
expect(Array.isArray(result.data)).toBe(true);
|
|
46
|
+
expect(service.listDnsRecords).toHaveBeenCalledWith('example.com');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should add a DNS record', async () => {
|
|
50
|
+
service.createDnsRecord.mockResolvedValue({ id: '123' });
|
|
51
|
+
|
|
52
|
+
const result = await tool.execute({
|
|
53
|
+
domain: 'example.com',
|
|
54
|
+
action: 'add',
|
|
55
|
+
type: 'A',
|
|
56
|
+
name: 'www',
|
|
57
|
+
content: '1.2.3.4',
|
|
58
|
+
ttl: '300',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(result.success).toBe(true);
|
|
62
|
+
expect(service.createDnsRecord).toHaveBeenCalledWith('example.com', {
|
|
63
|
+
name: 'www',
|
|
64
|
+
type: 'A',
|
|
65
|
+
content: '1.2.3.4',
|
|
66
|
+
ttl: '300',
|
|
67
|
+
prio: undefined,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should fail add without type', async () => {
|
|
72
|
+
const result = await tool.execute({
|
|
73
|
+
domain: 'example.com',
|
|
74
|
+
action: 'add',
|
|
75
|
+
content: '1.2.3.4',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(result.success).toBe(false);
|
|
79
|
+
expect(result.error).toContain('Record type is required');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should fail add without content', async () => {
|
|
83
|
+
const result = await tool.execute({
|
|
84
|
+
domain: 'example.com',
|
|
85
|
+
action: 'add',
|
|
86
|
+
type: 'A',
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(result.success).toBe(false);
|
|
90
|
+
expect(result.error).toContain('Record content is required');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should remove a DNS record', async () => {
|
|
94
|
+
service.deleteDnsRecord.mockResolvedValue(undefined);
|
|
95
|
+
|
|
96
|
+
const result = await tool.execute({
|
|
97
|
+
domain: 'example.com',
|
|
98
|
+
action: 'remove',
|
|
99
|
+
recordId: '123',
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(result.success).toBe(true);
|
|
103
|
+
expect(result.data).toEqual({ deleted: true });
|
|
104
|
+
expect(service.deleteDnsRecord).toHaveBeenCalledWith('example.com', '123');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should fail remove without recordId', async () => {
|
|
108
|
+
const result = await tool.execute({
|
|
109
|
+
domain: 'example.com',
|
|
110
|
+
action: 'remove',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(result.success).toBe(false);
|
|
114
|
+
expect(result.error).toContain('Record ID is required');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should update a DNS record', async () => {
|
|
118
|
+
service.editDnsRecord.mockResolvedValue(undefined);
|
|
119
|
+
service.listDnsRecords.mockResolvedValue([
|
|
120
|
+
{ id: '123', type: 'A', content: '5.6.7.8' },
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
const result = await tool.execute({
|
|
124
|
+
domain: 'example.com',
|
|
125
|
+
action: 'update',
|
|
126
|
+
recordId: '123',
|
|
127
|
+
content: '5.6.7.8',
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
expect(result.success).toBe(true);
|
|
131
|
+
expect(service.editDnsRecord).toHaveBeenCalledWith('example.com', '123', expect.objectContaining({
|
|
132
|
+
content: '5.6.7.8',
|
|
133
|
+
}));
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should fail update without recordId', async () => {
|
|
137
|
+
const result = await tool.execute({
|
|
138
|
+
domain: 'example.com',
|
|
139
|
+
action: 'update',
|
|
140
|
+
content: '5.6.7.8',
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(result.success).toBe(false);
|
|
144
|
+
expect(result.error).toContain('Record ID is required');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should handle errors gracefully', async () => {
|
|
148
|
+
service.listDnsRecords.mockRejectedValue(new Error('Domain not found'));
|
|
149
|
+
|
|
150
|
+
const result = await tool.execute({ domain: 'nonexistent.com' });
|
|
151
|
+
|
|
152
|
+
expect(result.success).toBe(false);
|
|
153
|
+
expect(result.error).toContain('Domain not found');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// PorkbunListDomainsTool
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
describe('PorkbunListDomainsTool', () => {
|
|
162
|
+
let service: any;
|
|
163
|
+
let tool: PorkbunListDomainsTool;
|
|
164
|
+
|
|
165
|
+
beforeEach(() => {
|
|
166
|
+
service = {
|
|
167
|
+
listDomains: vi.fn(),
|
|
168
|
+
};
|
|
169
|
+
tool = new PorkbunListDomainsTool(service);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should have correct metadata', () => {
|
|
173
|
+
expect(tool.id).toBe('porkbunListDomains');
|
|
174
|
+
expect(tool.name).toBe('porkbunListDomains');
|
|
175
|
+
expect(tool.inputSchema.type).toBe('object');
|
|
176
|
+
expect(tool.inputSchema.required).toEqual([]);
|
|
177
|
+
expect(tool.hasSideEffects).toBe(false);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should list all domains', async () => {
|
|
181
|
+
service.listDomains.mockResolvedValue([
|
|
182
|
+
{ domain: 'example.com', status: 'ACTIVE', autoRenew: true },
|
|
183
|
+
{ domain: 'test.dev', status: 'ACTIVE', autoRenew: false },
|
|
184
|
+
]);
|
|
185
|
+
|
|
186
|
+
const result = await tool.execute({} as Record<string, never>);
|
|
187
|
+
|
|
188
|
+
expect(result.success).toBe(true);
|
|
189
|
+
expect(result.data).toHaveLength(2);
|
|
190
|
+
expect(service.listDomains).toHaveBeenCalled();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should return empty array when no domains', async () => {
|
|
194
|
+
service.listDomains.mockResolvedValue([]);
|
|
195
|
+
|
|
196
|
+
const result = await tool.execute({} as Record<string, never>);
|
|
197
|
+
|
|
198
|
+
expect(result.success).toBe(true);
|
|
199
|
+
expect(result.data).toEqual([]);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should handle errors gracefully', async () => {
|
|
203
|
+
service.listDomains.mockRejectedValue(new Error('Unauthorized'));
|
|
204
|
+
|
|
205
|
+
const result = await tool.execute({} as Record<string, never>);
|
|
206
|
+
|
|
207
|
+
expect(result.success).toBe(false);
|
|
208
|
+
expect(result.error).toContain('Unauthorized');
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// PorkbunRegisterDomainTool
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
|
|
216
|
+
describe('PorkbunRegisterDomainTool', () => {
|
|
217
|
+
let service: any;
|
|
218
|
+
let tool: PorkbunRegisterDomainTool;
|
|
219
|
+
|
|
220
|
+
beforeEach(() => {
|
|
221
|
+
service = {
|
|
222
|
+
registerDomain: vi.fn(),
|
|
223
|
+
};
|
|
224
|
+
tool = new PorkbunRegisterDomainTool(service);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('should have correct metadata', () => {
|
|
228
|
+
expect(tool.id).toBe('porkbunRegisterDomain');
|
|
229
|
+
expect(tool.name).toBe('porkbunRegisterDomain');
|
|
230
|
+
expect(tool.inputSchema.type).toBe('object');
|
|
231
|
+
expect(tool.inputSchema.required).toContain('domain');
|
|
232
|
+
expect(tool.hasSideEffects).toBe(true);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should register a domain successfully', async () => {
|
|
236
|
+
service.registerDomain.mockResolvedValue({
|
|
237
|
+
domain: 'newsite.dev',
|
|
238
|
+
status: 'SUCCESS',
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const result = await tool.execute({ domain: 'newsite.dev' });
|
|
242
|
+
|
|
243
|
+
expect(result.success).toBe(true);
|
|
244
|
+
expect(result.data).toHaveProperty('domain', 'newsite.dev');
|
|
245
|
+
expect(service.registerDomain).toHaveBeenCalledWith(
|
|
246
|
+
expect.objectContaining({ domain: 'newsite.dev' }),
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should pass all contact fields', async () => {
|
|
251
|
+
service.registerDomain.mockResolvedValue({ domain: 'site.com', status: 'SUCCESS' });
|
|
252
|
+
|
|
253
|
+
await tool.execute({
|
|
254
|
+
domain: 'site.com',
|
|
255
|
+
years: 2,
|
|
256
|
+
firstName: 'John',
|
|
257
|
+
lastName: 'Doe',
|
|
258
|
+
email: 'john@example.com',
|
|
259
|
+
phone: '+1.5551234567',
|
|
260
|
+
city: 'New York',
|
|
261
|
+
state: 'NY',
|
|
262
|
+
zip: '10001',
|
|
263
|
+
country: 'US',
|
|
264
|
+
organization: 'Acme',
|
|
265
|
+
address: '123 Main St',
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
expect(service.registerDomain).toHaveBeenCalledWith(
|
|
269
|
+
expect.objectContaining({
|
|
270
|
+
years: 2,
|
|
271
|
+
firstName: 'John',
|
|
272
|
+
lastName: 'Doe',
|
|
273
|
+
country: 'US',
|
|
274
|
+
}),
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should handle errors gracefully', async () => {
|
|
279
|
+
service.registerDomain.mockRejectedValue(new Error('Insufficient funds'));
|
|
280
|
+
|
|
281
|
+
const result = await tool.execute({ domain: 'expensive.io' });
|
|
282
|
+
|
|
283
|
+
expect(result.success).toBe(false);
|
|
284
|
+
expect(result.error).toContain('Insufficient funds');
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// ---------------------------------------------------------------------------
|
|
289
|
+
// PorkbunSearchDomainTool
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
describe('PorkbunSearchDomainTool', () => {
|
|
293
|
+
let service: any;
|
|
294
|
+
let tool: PorkbunSearchDomainTool;
|
|
295
|
+
|
|
296
|
+
beforeEach(() => {
|
|
297
|
+
service = {
|
|
298
|
+
checkAvailability: vi.fn(),
|
|
299
|
+
};
|
|
300
|
+
tool = new PorkbunSearchDomainTool(service);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('should have correct metadata', () => {
|
|
304
|
+
expect(tool.id).toBe('porkbunSearchDomain');
|
|
305
|
+
expect(tool.name).toBe('porkbunSearchDomain');
|
|
306
|
+
expect(tool.inputSchema.type).toBe('object');
|
|
307
|
+
expect(tool.inputSchema.required).toContain('domain');
|
|
308
|
+
expect(tool.hasSideEffects).toBe(false);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should check domain availability', async () => {
|
|
312
|
+
service.checkAvailability.mockResolvedValue({
|
|
313
|
+
domain: 'example.dev',
|
|
314
|
+
available: true,
|
|
315
|
+
pricing: { registration: '9.73', renewal: '9.73' },
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
const result = await tool.execute({ domain: 'example.dev' });
|
|
319
|
+
|
|
320
|
+
expect(result.success).toBe(true);
|
|
321
|
+
expect(result.data).toHaveProperty('available', true);
|
|
322
|
+
expect(result.data).toHaveProperty('domain', 'example.dev');
|
|
323
|
+
expect(service.checkAvailability).toHaveBeenCalledWith('example.dev');
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should return unavailable for taken domains', async () => {
|
|
327
|
+
service.checkAvailability.mockResolvedValue({
|
|
328
|
+
domain: 'google.com',
|
|
329
|
+
available: false,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const result = await tool.execute({ domain: 'google.com' });
|
|
333
|
+
|
|
334
|
+
expect(result.success).toBe(true);
|
|
335
|
+
expect(result.data?.available).toBe(false);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('should handle errors gracefully', async () => {
|
|
339
|
+
service.checkAvailability.mockRejectedValue(new Error('API error'));
|
|
340
|
+
|
|
341
|
+
const result = await tool.execute({ domain: 'test.xyz' });
|
|
342
|
+
|
|
343
|
+
expect(result.success).toBe(false);
|
|
344
|
+
expect(result.error).toContain('API error');
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// ---------------------------------------------------------------------------
|
|
349
|
+
// PorkbunTransferDomainTool
|
|
350
|
+
// ---------------------------------------------------------------------------
|
|
351
|
+
|
|
352
|
+
describe('PorkbunTransferDomainTool', () => {
|
|
353
|
+
let service: any;
|
|
354
|
+
let tool: PorkbunTransferDomainTool;
|
|
355
|
+
|
|
356
|
+
beforeEach(() => {
|
|
357
|
+
service = {
|
|
358
|
+
transferDomain: vi.fn(),
|
|
359
|
+
};
|
|
360
|
+
tool = new PorkbunTransferDomainTool(service);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('should have correct metadata', () => {
|
|
364
|
+
expect(tool.id).toBe('porkbunTransferDomain');
|
|
365
|
+
expect(tool.name).toBe('porkbunTransferDomain');
|
|
366
|
+
expect(tool.inputSchema.type).toBe('object');
|
|
367
|
+
expect(tool.inputSchema.required).toContain('domain');
|
|
368
|
+
expect(tool.inputSchema.required).toContain('authCode');
|
|
369
|
+
expect(tool.hasSideEffects).toBe(true);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('should initiate a domain transfer', async () => {
|
|
373
|
+
service.transferDomain.mockResolvedValue({
|
|
374
|
+
domain: 'example.com',
|
|
375
|
+
status: 'SUCCESS',
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
const result = await tool.execute({
|
|
379
|
+
domain: 'example.com',
|
|
380
|
+
authCode: 'EPP-CODE-123',
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
expect(result.success).toBe(true);
|
|
384
|
+
expect(result.data).toHaveProperty('domain', 'example.com');
|
|
385
|
+
expect(service.transferDomain).toHaveBeenCalledWith('example.com', 'EPP-CODE-123');
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
it('should handle errors gracefully', async () => {
|
|
389
|
+
service.transferDomain.mockRejectedValue(new Error('Domain is locked'));
|
|
390
|
+
|
|
391
|
+
const result = await tool.execute({
|
|
392
|
+
domain: 'locked.com',
|
|
393
|
+
authCode: 'invalid',
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
expect(result.success).toBe(false);
|
|
397
|
+
expect(result.error).toContain('Domain is locked');
|
|
398
|
+
});
|
|
399
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"noEmitOnError": false,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"moduleResolution": "Bundler",
|
|
18
|
+
"types": ["node"]
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*"],
|
|
21
|
+
"exclude": ["node_modules", "dist", "test"]
|
|
22
|
+
}
|