porkbun-sdk 1.0.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/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # Porkbun SDK
2
+
3
+ TypeScript SDK for the [Porkbun](https://porkbun.com) API v3 — manage domains, DNS, SSL and more programmatically.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install porkbun-sdk
9
+ ```
10
+
11
+ ## Authentication
12
+
13
+ The SDK requires API keys from [porkbun.com/account/api](https://porkbun.com/account/api).
14
+
15
+ ```typescript
16
+ import { PorkbunClient } from "porkbun-sdk";
17
+
18
+ const client = new PorkbunClient({
19
+ apikey: "pk1_xxxxx",
20
+ secretapikey: "sk1_xxxxx",
21
+ });
22
+ ```
23
+
24
+ ### Via environment variables
25
+
26
+ ```bash
27
+ export PORKBUN_API_KEY=pk1_xxxxx
28
+ export PORKBUN_API_SECRET=sk1_xxxxx
29
+ ```
30
+
31
+ ```typescript
32
+ const client = new PorkbunClient({
33
+ apikey: process.env.PORKBUN_API_KEY!,
34
+ secretapikey: process.env.PORKBUN_API_SECRET!,
35
+ });
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```typescript
41
+ import { PorkbunClient } from "porkbun-sdk";
42
+
43
+ const client = new PorkbunClient({
44
+ apikey: process.env.PORKBUN_API_KEY!,
45
+ secretapikey: process.env.PORKBUN_API_SECRET!,
46
+ });
47
+
48
+ // Ping (test credentials)
49
+ const ping = await client.ping();
50
+ console.log(ping.yourIp);
51
+
52
+ // Pricing
53
+ const pricing = await client.pricing.get();
54
+
55
+ // Domains
56
+ const domains = await client.domain.listAll();
57
+ const check = await client.domain.check("example.com");
58
+ const ns = await client.domain.getNameServers("example.com");
59
+ await client.domain.updateNameServers("example.com", ["ns1.dns.com", "ns2.dns.com"]);
60
+ await client.domain.updateAutoRenew({ status: "on" }, "example.com");
61
+
62
+ // URL Forwarding
63
+ const forwards = await client.domain.getUrlForwarding("example.com");
64
+ await client.domain.addUrlForward("example.com", {
65
+ location: "https://target.com",
66
+ type: "permanent",
67
+ includePath: "no",
68
+ wildcard: "no",
69
+ });
70
+
71
+ // DNS
72
+ const records = await client.dns.retrieve("example.com");
73
+ const aRecords = await client.dns.retrieveByNameType("example.com", "A", "www");
74
+ const created = await client.dns.create("example.com", {
75
+ type: "A",
76
+ content: "1.2.3.4",
77
+ name: "www",
78
+ ttl: 600,
79
+ });
80
+ await client.dns.edit("example.com", "12345", {
81
+ type: "A",
82
+ content: "5.6.7.8",
83
+ });
84
+ await client.dns.delete("example.com", "12345");
85
+
86
+ // DNSSEC
87
+ const dnssecRecords = await client.dnssec.get("example.com");
88
+ await client.dnssec.create("example.com", {
89
+ keyTag: "12345",
90
+ alg: "13",
91
+ digestType: "2",
92
+ digest: "abc123",
93
+ });
94
+
95
+ // SSL
96
+ const ssl = await client.ssl.retrieve("example.com");
97
+ console.log(ssl.certificatechain);
98
+ ```
99
+
100
+ ## Available resources
101
+
102
+ | Resource | Access | Description |
103
+ |----------|--------|-------------|
104
+ | Pricing | `client.pricing` | Get domain pricing for all TLDs |
105
+ | Domains | `client.domain` | List, check, register, nameservers, auto-renew |
106
+ | URL Forwards | `client.domain` | Add, list, delete URL forwards |
107
+ | Glue Records | `client.domain` | Create, update, delete glue records |
108
+ | DNS | `client.dns` | CRUD DNS records, filter by type/subdomain |
109
+ | DNSSEC | `client.dnssec` | Create, list, delete DS records |
110
+ | SSL | `client.ssl` | Retrieve certificate bundles |
111
+
112
+ ## Error handling
113
+
114
+ ```typescript
115
+ import { PorkbunClient, PorkbunError } from "porkbun-sdk";
116
+
117
+ try {
118
+ const records = await client.dns.retrieve("example.com");
119
+ } catch (error) {
120
+ if (error instanceof PorkbunError) {
121
+ console.error(`Error ${error.status}: ${error.message}`);
122
+ console.error(`Endpoint: ${error.endpoint}`);
123
+ }
124
+ }
125
+ ```
126
+
127
+ ## Options
128
+
129
+ ```typescript
130
+ const client = new PorkbunClient({
131
+ apikey: "pk1_xxxxx",
132
+ secretapikey: "sk1_xxxxx",
133
+ baseURL: "https://api-ipv4.porkbun.com/api/json/v3", // IPv4-only endpoint
134
+ retry: 3, // Number of retries (default: 2)
135
+ retryDelay: 1000, // Delay between retries in ms (default: 500)
136
+ });
137
+ ```
138
+
139
+ ## License
140
+
141
+ MIT — yabbal
@@ -0,0 +1,283 @@
1
+ type FetchFn = <T = unknown>(path: string, options?: {
2
+ method?: string;
3
+ body?: Record<string, unknown>;
4
+ }) => Promise<T>;
5
+
6
+ interface PorkbunCredentials {
7
+ apikey: string;
8
+ secretapikey: string;
9
+ }
10
+ interface PingResponse {
11
+ status: string;
12
+ yourIp: string;
13
+ }
14
+ interface TldPricing {
15
+ registration: string;
16
+ renewal: string;
17
+ transfer: string;
18
+ coupons?: {
19
+ registration?: {
20
+ code: string;
21
+ amount: number;
22
+ type: string;
23
+ };
24
+ };
25
+ }
26
+ interface PricingResponse {
27
+ status: string;
28
+ pricing: Record<string, TldPricing>;
29
+ }
30
+ interface Domain {
31
+ domain: string;
32
+ status: string;
33
+ tld: string;
34
+ createDate: string;
35
+ expireDate: string;
36
+ securityLock: string;
37
+ whoisPrivacy: string;
38
+ autoRenew: number;
39
+ notLocal: number;
40
+ labels?: DomainLabel[];
41
+ }
42
+ interface DomainLabel {
43
+ id: string;
44
+ title: string;
45
+ }
46
+ interface DomainListResponse {
47
+ status: string;
48
+ domains: Domain[];
49
+ }
50
+ interface DomainCheckResponse {
51
+ status: string;
52
+ response: {
53
+ avail: string;
54
+ type?: string;
55
+ pricing?: {
56
+ registration?: string;
57
+ renewal?: string;
58
+ transfer?: string;
59
+ };
60
+ premium?: boolean;
61
+ yourIp?: string;
62
+ };
63
+ limits?: {
64
+ ttl: number;
65
+ limit: number;
66
+ used: number;
67
+ };
68
+ }
69
+ interface DomainCreateParams {
70
+ cost: number;
71
+ agreeToTerms: string;
72
+ }
73
+ interface DomainCreateResponse {
74
+ status: string;
75
+ domain: string;
76
+ cost: number;
77
+ orderId: number;
78
+ balance: number;
79
+ limits?: {
80
+ ttl: number;
81
+ limit: number;
82
+ used: number;
83
+ };
84
+ }
85
+ interface AutoRenewUpdateParams {
86
+ status: "on" | "off";
87
+ domains?: string[];
88
+ }
89
+ interface AutoRenewUpdateResponse {
90
+ status: string;
91
+ results?: Record<string, {
92
+ status: string;
93
+ message?: string;
94
+ }>;
95
+ }
96
+ interface NameServersResponse {
97
+ status: string;
98
+ ns: string[];
99
+ }
100
+ interface UrlForward {
101
+ id: string;
102
+ subdomain: string;
103
+ location: string;
104
+ type: string;
105
+ includePath: string;
106
+ wildcard: string;
107
+ }
108
+ interface UrlForwardCreateParams {
109
+ subdomain?: string;
110
+ location: string;
111
+ type: "temporary" | "permanent";
112
+ includePath: "yes" | "no";
113
+ wildcard: "yes" | "no";
114
+ }
115
+ interface UrlForwardingResponse {
116
+ status: string;
117
+ forwards: UrlForward[];
118
+ }
119
+ interface GlueRecord {
120
+ hostname: string;
121
+ ips: string[];
122
+ }
123
+ interface GlueRecordsResponse {
124
+ status: string;
125
+ hosts: GlueRecord[];
126
+ }
127
+ type DnsRecordType = "A" | "MX" | "CNAME" | "ALIAS" | "TXT" | "NS" | "AAAA" | "SRV" | "TLSA" | "CAA" | "HTTPS" | "SVCB" | "SSHFP";
128
+ interface DnsRecord {
129
+ id: string;
130
+ name: string;
131
+ type: DnsRecordType;
132
+ content: string;
133
+ ttl: string;
134
+ prio: string | null;
135
+ notes: string | null;
136
+ }
137
+ interface DnsCreateParams {
138
+ name?: string;
139
+ type: DnsRecordType;
140
+ content: string;
141
+ ttl?: number;
142
+ prio?: number;
143
+ notes?: string;
144
+ }
145
+ interface DnsEditParams {
146
+ name?: string;
147
+ type: DnsRecordType;
148
+ content: string;
149
+ ttl?: number;
150
+ prio?: number;
151
+ notes?: string | null;
152
+ }
153
+ interface DnsCreateResponse {
154
+ status: string;
155
+ id: string;
156
+ }
157
+ interface DnsRetrieveResponse {
158
+ status: string;
159
+ records: DnsRecord[];
160
+ }
161
+ interface DnssecRecord {
162
+ keyTag: string;
163
+ alg: string;
164
+ digestType: string;
165
+ digest: string;
166
+ }
167
+ interface DnssecCreateParams {
168
+ keyTag: string;
169
+ alg: string;
170
+ digestType: string;
171
+ digest: string;
172
+ maxSigLife?: number;
173
+ keyDataFlags?: number;
174
+ keyDataProtocol?: number;
175
+ keyDataAlgo?: number;
176
+ keyDataPubKey?: string;
177
+ }
178
+ interface DnssecRecordsResponse {
179
+ status: string;
180
+ records: Record<string, DnssecRecord>;
181
+ }
182
+ interface SslBundle {
183
+ status: string;
184
+ certificatechain: string;
185
+ privatekey: string;
186
+ publickey: string;
187
+ }
188
+ interface StatusResponse {
189
+ status: string;
190
+ message?: string;
191
+ }
192
+
193
+ declare class Resource {
194
+ protected fetch: FetchFn;
195
+ protected credentials: PorkbunCredentials;
196
+ constructor(fetch: FetchFn, credentials: PorkbunCredentials);
197
+ protected authBody(extra?: object): Record<string, unknown>;
198
+ }
199
+
200
+ declare class DnsResource extends Resource {
201
+ create(domain: string, params: DnsCreateParams): Promise<DnsCreateResponse>;
202
+ edit(domain: string, id: string, params: DnsEditParams): Promise<StatusResponse>;
203
+ editByNameType(domain: string, type: string, subdomain?: string, params?: {
204
+ content: string;
205
+ ttl?: number;
206
+ prio?: number;
207
+ notes?: string;
208
+ }): Promise<StatusResponse>;
209
+ delete(domain: string, id: string): Promise<StatusResponse>;
210
+ deleteByNameType(domain: string, type: string, subdomain?: string): Promise<StatusResponse>;
211
+ retrieve(domain: string, id?: string): Promise<DnsRecord[]>;
212
+ retrieveByNameType(domain: string, type: string, subdomain?: string): Promise<DnsRecord[]>;
213
+ }
214
+
215
+ declare class DnssecResource extends Resource {
216
+ create(domain: string, params: DnssecCreateParams): Promise<StatusResponse>;
217
+ get(domain: string): Promise<Record<string, DnssecRecord>>;
218
+ delete(domain: string, keyTag: string): Promise<StatusResponse>;
219
+ }
220
+
221
+ declare class DomainResource extends Resource {
222
+ listAll(params?: {
223
+ start?: number;
224
+ includeLabels?: boolean;
225
+ }): Promise<DomainListResponse>;
226
+ check(domain: string): Promise<DomainCheckResponse>;
227
+ create(domain: string, params: DomainCreateParams): Promise<DomainCreateResponse>;
228
+ getNameServers(domain: string): Promise<NameServersResponse>;
229
+ updateNameServers(domain: string, ns: string[]): Promise<StatusResponse>;
230
+ updateAutoRenew(params: AutoRenewUpdateParams, domain?: string): Promise<AutoRenewUpdateResponse>;
231
+ getUrlForwarding(domain: string): Promise<UrlForward[]>;
232
+ addUrlForward(domain: string, params: UrlForwardCreateParams): Promise<StatusResponse>;
233
+ deleteUrlForward(domain: string, recordId: string): Promise<StatusResponse>;
234
+ getGlueRecords(domain: string): Promise<GlueRecordsResponse>;
235
+ createGlueRecord(domain: string, subdomain: string, ips: string[]): Promise<StatusResponse>;
236
+ updateGlueRecord(domain: string, subdomain: string, ips: string[]): Promise<StatusResponse>;
237
+ deleteGlueRecord(domain: string, subdomain: string): Promise<StatusResponse>;
238
+ }
239
+
240
+ declare class PricingResource {
241
+ private fetch;
242
+ constructor(fetch: FetchFn);
243
+ get(): Promise<PricingResponse>;
244
+ }
245
+
246
+ declare class SslResource extends Resource {
247
+ retrieve(domain: string): Promise<SslBundle>;
248
+ }
249
+
250
+ interface PorkbunClientOptions {
251
+ apikey: string;
252
+ secretapikey: string;
253
+ baseURL?: string;
254
+ retry?: number;
255
+ retryDelay?: number;
256
+ }
257
+ declare class PorkbunClient {
258
+ readonly fetch: FetchFn;
259
+ private readonly credentials;
260
+ readonly pricing: PricingResource;
261
+ readonly domain: DomainResource;
262
+ readonly dns: DnsResource;
263
+ readonly dnssec: DnssecResource;
264
+ readonly ssl: SslResource;
265
+ constructor(options: PorkbunClientOptions);
266
+ ping(): Promise<PingResponse>;
267
+ }
268
+
269
+ declare class PorkbunError extends Error {
270
+ status: number;
271
+ endpoint: string;
272
+ details?: unknown | undefined;
273
+ constructor(message: string, status: number, endpoint: string, details?: unknown | undefined);
274
+ toJSON(): {
275
+ error: string;
276
+ message: string;
277
+ status: number;
278
+ endpoint: string;
279
+ details: unknown;
280
+ };
281
+ }
282
+
283
+ export { type AutoRenewUpdateParams, type AutoRenewUpdateResponse, type DnsCreateParams, type DnsCreateResponse, type DnsEditParams, type DnsRecord, type DnsRecordType, type DnsRetrieveResponse, type DnssecCreateParams, type DnssecRecord, type DnssecRecordsResponse, type Domain, type DomainCheckResponse, type DomainCreateParams, type DomainCreateResponse, type DomainLabel, type DomainListResponse, type GlueRecord, type GlueRecordsResponse, type NameServersResponse, type PingResponse, PorkbunClient, type PorkbunClientOptions, type PorkbunCredentials, PorkbunError, type PricingResponse, type SslBundle, type StatusResponse, type TldPricing, type UrlForward, type UrlForwardCreateParams, type UrlForwardingResponse };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var c=class extends Error{constructor(t,s,i,a){super(t);this.status=s;this.endpoint=i;this.details=a;this.name="PorkbunError";}toJSON(){return {error:this.name,message:this.message,status:this.status,endpoint:this.endpoint,details:this.details}}};var D=r=>new Promise(e=>setTimeout(e,r)),P=r=>{let{baseURL:e,retry:t=2,retryDelay:s=500,retryStatusCodes:i=[408,429,500,502,503,504]}=r;return async(a,R)=>{let w=`${e}/${a}`,$=R?.method??"POST",S=R?.body?JSON.stringify(R.body):void 0,g;for(let d=0;d<=t;d++){d>0&&await D(s*d);try{let n=await fetch(w,{method:$,headers:{"Content-Type":"application/json"},body:S}),u=await n.json();if(!n.ok||u.status&&u.status!=="SUCCESS"){let b=u.message??n.statusText;if(d<t&&i.includes(n.status)){g=new c(b,n.status,a,u);continue}throw new c(b,n.status,a,u)}return u}catch(n){if(n instanceof c)throw n;if(g=n,d===t)break}}throw g??new c("Request failed",0,a)}};var o=class{constructor(e,t){this.fetch=e;this.credentials=t;}authBody(e){return {...this.credentials,...e}}};var p=class extends o{async create(e,t){return this.fetch(`dns/create/${e}`,{body:this.authBody(t)})}async edit(e,t,s){return this.fetch(`dns/edit/${e}/${t}`,{body:this.authBody(s)})}async editByNameType(e,t,s,i){let a=s?`dns/editByNameType/${e}/${t}/${s}`:`dns/editByNameType/${e}/${t}`;return this.fetch(a,{body:this.authBody(i)})}async delete(e,t){return this.fetch(`dns/delete/${e}/${t}`,{body:this.authBody()})}async deleteByNameType(e,t,s){let i=s?`dns/deleteByNameType/${e}/${t}/${s}`:`dns/deleteByNameType/${e}/${t}`;return this.fetch(i,{body:this.authBody()})}async retrieve(e,t){let s=t?`dns/retrieve/${e}/${t}`:`dns/retrieve/${e}`;return (await this.fetch(s,{body:this.authBody()})).records??[]}async retrieveByNameType(e,t,s){let i=s?`dns/retrieveByNameType/${e}/${t}/${s}`:`dns/retrieveByNameType/${e}/${t}`;return (await this.fetch(i,{body:this.authBody()})).records??[]}};var h=class extends o{async create(e,t){return this.fetch(`dns/createDnssecRecord/${e}`,{body:this.authBody(t)})}async get(e){return (await this.fetch(`dns/getDnssecRecords/${e}`,{body:this.authBody()})).records??{}}async delete(e,t){return this.fetch(`dns/deleteDnssecRecord/${e}/${t}`,{body:this.authBody()})}};var y=class extends o{async listAll(e){return this.fetch("domain/listAll",{body:this.authBody({...e?.start!==void 0&&{start:e.start},...e?.includeLabels&&{includeLabels:"yes"}})})}async check(e){return this.fetch(`domain/checkDomain/${e}`,{body:this.authBody()})}async create(e,t){return this.fetch(`domain/create/${e}`,{body:this.authBody(t)})}async getNameServers(e){return this.fetch(`domain/getNs/${e}`,{body:this.authBody()})}async updateNameServers(e,t){return this.fetch(`domain/updateNs/${e}`,{body:this.authBody({ns:t})})}async updateAutoRenew(e,t){let s=t?`domain/updateAutoRenew/${t}`:"domain/updateAutoRenew";return this.fetch(s,{body:this.authBody({status:e.status,...e.domains&&{domains:e.domains}})})}async getUrlForwarding(e){return (await this.fetch(`domain/getUrlForwarding/${e}`,{body:this.authBody()})).forwards??[]}async addUrlForward(e,t){return this.fetch(`domain/addUrlForward/${e}`,{body:this.authBody(t)})}async deleteUrlForward(e,t){return this.fetch(`domain/deleteUrlForward/${e}/${t}`,{body:this.authBody()})}async getGlueRecords(e){return this.fetch(`domain/getGlue/${e}`,{body:this.authBody()})}async createGlueRecord(e,t,s){return this.fetch(`domain/createGlue/${e}/${t}`,{body:this.authBody({ips:s})})}async updateGlueRecord(e,t,s){return this.fetch(`domain/updateGlue/${e}/${t}`,{body:this.authBody({ips:s})})}async deleteGlueRecord(e,t){return this.fetch(`domain/deleteGlue/${e}/${t}`,{body:this.authBody()})}};var m=class{constructor(e){this.fetch=e;}async get(){return this.fetch("pricing/get")}};var l=class extends o{async retrieve(e){return this.fetch(`ssl/retrieve/${e}`,{body:this.authBody()})}};var f=class{fetch;credentials;pricing;domain;dns;dnssec;ssl;constructor(e){this.credentials={apikey:e.apikey,secretapikey:e.secretapikey},this.fetch=P({baseURL:e.baseURL??"https://api.porkbun.com/api/json/v3",retry:e.retry??2,retryDelay:e.retryDelay??500,retryStatusCodes:[408,429,500,502,503,504]}),this.pricing=new m(this.fetch),this.domain=new y(this.fetch,this.credentials),this.dns=new p(this.fetch,this.credentials),this.dnssec=new h(this.fetch,this.credentials),this.ssl=new l(this.fetch,this.credentials);}async ping(){return this.fetch("ping",{body:{...this.credentials}})}};
2
+ export{f as PorkbunClient,c as PorkbunError};
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "porkbun-sdk",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript SDK for the Porkbun API — manage domains, DNS, SSL and more",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "yabbal",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/yabbal/porkbun.git",
11
+ "directory": "packages/porkbun-sdk"
12
+ },
13
+ "homepage": "https://github.com/yabbal/porkbun",
14
+ "bugs": {
15
+ "url": "https://github.com/yabbal/porkbun/issues"
16
+ },
17
+ "keywords": [
18
+ "porkbun",
19
+ "sdk",
20
+ "api",
21
+ "domain",
22
+ "dns",
23
+ "ssl",
24
+ "registrar",
25
+ "typescript"
26
+ ],
27
+ "exports": {
28
+ ".": {
29
+ "import": "./dist/index.js",
30
+ "types": "./dist/index.d.ts"
31
+ }
32
+ },
33
+ "files": ["dist"],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsup",
39
+ "dev": "tsup --watch",
40
+ "typecheck": "tsc --noEmit",
41
+ "lint": "biome check src/",
42
+ "format": "biome format --write src/"
43
+ },
44
+ "devDependencies": {
45
+ "@biomejs/biome": "^2.0.6",
46
+ "tsup": "^8.5.0",
47
+ "typescript": "^5.8.3"
48
+ }
49
+ }