@chez14/rdap-sdk 0.1.1-13
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 +21 -0
- package/README.md +133 -0
- package/dist/index.d.ts +250 -0
- package/dist/index.js +139 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
- package/src/client.ts +115 -0
- package/src/index.ts +3 -0
- package/src/types.ts +216 -0
- package/src/utils/fetcher.ts +77 -0
- package/src/utils/throwables.ts +6 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Gunawan "chez14" Christianto <chris@christianto.net>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# RDAP.net SDK
|
|
2
|
+
|
|
3
|
+
A TypeScript SDK for RDAP.net. Directly calls RDAP APIs from RDAP.net as the
|
|
4
|
+
main RDAP Server Database.
|
|
5
|
+
|
|
6
|
+
Support RDAP.net/RDAP.org here: https://about.rdap.org/
|
|
7
|
+
|
|
8
|
+
References:
|
|
9
|
+
- API Usage: \
|
|
10
|
+
https://www.openrdap.org/api
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Using pnpm
|
|
16
|
+
pnpm add @chez14/rdap-sdk
|
|
17
|
+
|
|
18
|
+
# Using npm
|
|
19
|
+
npm install @chez14/rdap-sdk
|
|
20
|
+
|
|
21
|
+
# Using yarn
|
|
22
|
+
yarn add @chez14/rdap-sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { RdapClient } from '@chez14/rdap-sdk';
|
|
29
|
+
|
|
30
|
+
// Create a client
|
|
31
|
+
const client = new RdapClient();
|
|
32
|
+
|
|
33
|
+
// Query domain information
|
|
34
|
+
const domain = await client.domain('example.com');
|
|
35
|
+
console.log(domain.ldhName);
|
|
36
|
+
|
|
37
|
+
// Query internationalized domain name (IDN)
|
|
38
|
+
const idn = await client.domain('münchen.de');
|
|
39
|
+
console.log(idn.ldhName); // Automatically converts to punycode
|
|
40
|
+
|
|
41
|
+
// Query IP information
|
|
42
|
+
const ip = await client.ip('8.8.8.8');
|
|
43
|
+
console.log(ip.name);
|
|
44
|
+
|
|
45
|
+
// Query IP network (CIDR notation)
|
|
46
|
+
const network = await client.ip('2001:db8::1/128');
|
|
47
|
+
console.log(network.startAddress, network.endAddress);
|
|
48
|
+
|
|
49
|
+
// Query ASN information
|
|
50
|
+
const asn = await client.autnum(174);
|
|
51
|
+
console.log(asn.name);
|
|
52
|
+
|
|
53
|
+
// Use custom base domain (default is www.rdap.net)
|
|
54
|
+
const customClient = new RdapClient({
|
|
55
|
+
baseDomain: 'custom.rdap.example.com'
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Advanced Usage
|
|
60
|
+
|
|
61
|
+
### Custom Fetcher Implementation
|
|
62
|
+
|
|
63
|
+
You can provide your own fetcher implementation to customize how HTTP requests
|
|
64
|
+
are made. This is useful for:
|
|
65
|
+
- Adding custom headers
|
|
66
|
+
- Implementing custom retry logic
|
|
67
|
+
- Using different HTTP clients
|
|
68
|
+
- Adding request/response interceptors
|
|
69
|
+
- Custom error handling
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { RdapClient, Fetcher } from '@chez14/rdap-sdk';
|
|
73
|
+
|
|
74
|
+
// Define your custom types
|
|
75
|
+
interface CustomHeaders {
|
|
76
|
+
Accept: string;
|
|
77
|
+
'User-Agent': string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Implement a typed fetcher
|
|
81
|
+
class CustomFetcher implements Fetcher {
|
|
82
|
+
constructor(private userAgent: string) {}
|
|
83
|
+
|
|
84
|
+
// Your implementation here
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Use your custom fetcher
|
|
88
|
+
const client = new RdapClient({
|
|
89
|
+
fetcher: new CustomFetcher('MyApp/1.0 (https://example.com)'),
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Type Safety
|
|
94
|
+
|
|
95
|
+
The SDK is fully typed and provides interfaces for customizing request behavior.
|
|
96
|
+
You can implement your own fetcher with custom types:
|
|
97
|
+
|
|
98
|
+
The SDK exports these key types for customization:
|
|
99
|
+
- `HttpMethod`: Supported HTTP methods ('GET' | 'POST' | 'PUT' | 'DELETE' |
|
|
100
|
+
'PATCH')
|
|
101
|
+
- `FetchOptions`: Request configuration including method, URL, body, and headers
|
|
102
|
+
- `FetchResponse`: Standardized response format with status, data, and headers
|
|
103
|
+
- `Fetcher`: Interface for implementing custom HTTP clients
|
|
104
|
+
|
|
105
|
+
Response types:
|
|
106
|
+
- `DomainResponse`: Type for domain query responses
|
|
107
|
+
- `IpNetworkResponse`: Type for IP network query responses
|
|
108
|
+
- `AutonomousSystemResponse`: Type for ASN query responses
|
|
109
|
+
|
|
110
|
+
For type safety, we recommend:
|
|
111
|
+
1. Define interfaces for your request and response data
|
|
112
|
+
2. Use TypeScript's strict mode
|
|
113
|
+
3. Avoid using `unknown` or `any` types in your implementations
|
|
114
|
+
|
|
115
|
+
## Development
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Install dependencies
|
|
119
|
+
pnpm install
|
|
120
|
+
|
|
121
|
+
# Build
|
|
122
|
+
pnpm build
|
|
123
|
+
|
|
124
|
+
# Run tests
|
|
125
|
+
pnpm test
|
|
126
|
+
|
|
127
|
+
# Lint
|
|
128
|
+
pnpm lint
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
interface RdapLink {
|
|
2
|
+
value: string;
|
|
3
|
+
rel: string;
|
|
4
|
+
href: string;
|
|
5
|
+
hreflang?: string[];
|
|
6
|
+
type?: string;
|
|
7
|
+
media?: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
}
|
|
10
|
+
interface RdapEvent {
|
|
11
|
+
eventAction: string;
|
|
12
|
+
eventActor?: string;
|
|
13
|
+
eventDate: string;
|
|
14
|
+
links?: RdapLink[];
|
|
15
|
+
}
|
|
16
|
+
interface RdapPublicID {
|
|
17
|
+
type: string;
|
|
18
|
+
identifier: string;
|
|
19
|
+
}
|
|
20
|
+
type RdapStatus = 'validated' | 'renew prohibited' | 'update prohibited' | 'transfer prohibited' | 'delete prohibited' | 'proxy' | 'private' | 'removed' | 'obscured' | 'associated' | 'active' | 'inactive' | 'locked' | 'pending create' | 'pending renew' | 'pending transfer' | 'pending update' | 'pending delete';
|
|
21
|
+
type RdapNoticeAndRemarkTypes = 'result set truncated due to authorization' | 'result set truncated due to excessive load' | 'result set truncated due to unexplainable reasons' | 'object truncated due to authorization' | 'object truncated due to excessive load' | 'object truncated due to unexplainable reasons';
|
|
22
|
+
interface RdapRemark {
|
|
23
|
+
title?: string;
|
|
24
|
+
type?: RdapNoticeAndRemarkTypes;
|
|
25
|
+
description: string[];
|
|
26
|
+
links?: RdapLink[];
|
|
27
|
+
}
|
|
28
|
+
interface RdapDsData {
|
|
29
|
+
keyTag?: number;
|
|
30
|
+
algorithm?: number;
|
|
31
|
+
digest?: string;
|
|
32
|
+
digestType?: string;
|
|
33
|
+
events?: RdapEvent[];
|
|
34
|
+
links?: RdapLink[];
|
|
35
|
+
}
|
|
36
|
+
interface RdapKeyData {
|
|
37
|
+
flags?: number;
|
|
38
|
+
protocol?: number;
|
|
39
|
+
publicKey?: string;
|
|
40
|
+
algorithm?: number;
|
|
41
|
+
events?: RdapEvent[];
|
|
42
|
+
links?: RdapLink[];
|
|
43
|
+
}
|
|
44
|
+
interface RdapSecureDNS {
|
|
45
|
+
zoneSigned?: boolean;
|
|
46
|
+
delegationSigned?: boolean;
|
|
47
|
+
maxSigLife?: number;
|
|
48
|
+
dsData?: RdapDsData[];
|
|
49
|
+
keyData?: RdapKeyData[];
|
|
50
|
+
}
|
|
51
|
+
type RdapNotice = RdapRemark;
|
|
52
|
+
type RdapObjectClass = RdapEntityObjectClass | RdapNameserverObjectClass | RdapDomainObjectClass;
|
|
53
|
+
interface RdapEntityObjectClass {
|
|
54
|
+
objectClassName: 'entity';
|
|
55
|
+
handle?: string;
|
|
56
|
+
vcardArray?: any[];
|
|
57
|
+
roles?: string[];
|
|
58
|
+
publicIds?: RdapPublicID[];
|
|
59
|
+
entities?: RdapEntityObjectClass[];
|
|
60
|
+
remarks?: RdapRemark[];
|
|
61
|
+
links?: RdapLink[];
|
|
62
|
+
events?: RdapEvent[];
|
|
63
|
+
asEventActor?: Omit<RdapEvent, 'eventActor'>[];
|
|
64
|
+
status?: RdapStatus[];
|
|
65
|
+
port43?: string;
|
|
66
|
+
networks?: RdapIPNetworkObjectClass[];
|
|
67
|
+
autnums?: RdapAutonomousSystemNumberObjectClass[];
|
|
68
|
+
}
|
|
69
|
+
interface RdapNameserverObjectClass {
|
|
70
|
+
objectClassName: 'nameserver';
|
|
71
|
+
handle?: string;
|
|
72
|
+
ldhName?: string;
|
|
73
|
+
unicodeName?: string;
|
|
74
|
+
ipAddresses?: {
|
|
75
|
+
v6: string[];
|
|
76
|
+
v4: string[];
|
|
77
|
+
};
|
|
78
|
+
entities?: RdapEntityObjectClass[];
|
|
79
|
+
status?: RdapStatus[];
|
|
80
|
+
remarks?: RdapRemark[];
|
|
81
|
+
links?: RdapLink[];
|
|
82
|
+
port43?: string;
|
|
83
|
+
events?: RdapEvent[];
|
|
84
|
+
}
|
|
85
|
+
interface RdapDomainObjectClass {
|
|
86
|
+
objectClassName: 'domain';
|
|
87
|
+
handle?: string;
|
|
88
|
+
ldhName?: string;
|
|
89
|
+
unicodeName?: string;
|
|
90
|
+
variants: {
|
|
91
|
+
relation: string[];
|
|
92
|
+
idnTable: string;
|
|
93
|
+
variantName: {
|
|
94
|
+
ldhName: string;
|
|
95
|
+
unicodeName: string;
|
|
96
|
+
}[];
|
|
97
|
+
}[];
|
|
98
|
+
nameservers: RdapNameserverObjectClass[];
|
|
99
|
+
secureDNS: RdapSecureDNS;
|
|
100
|
+
entities?: RdapEntityObjectClass[];
|
|
101
|
+
status?: RdapStatus[];
|
|
102
|
+
publicIds?: RdapPublicID[];
|
|
103
|
+
remarks: RdapRemark[];
|
|
104
|
+
links?: RdapLink[];
|
|
105
|
+
port43?: string;
|
|
106
|
+
events?: RdapEvent[];
|
|
107
|
+
network?: RdapIPNetworkObjectClass;
|
|
108
|
+
}
|
|
109
|
+
interface RdapIPNetworkObjectClass {
|
|
110
|
+
objectClassName: 'ip network';
|
|
111
|
+
handle?: string;
|
|
112
|
+
startAddress?: string;
|
|
113
|
+
endAddress?: string;
|
|
114
|
+
ipVersion?: 'v4' | 'v6';
|
|
115
|
+
name?: string;
|
|
116
|
+
type?: string;
|
|
117
|
+
country?: string;
|
|
118
|
+
parentHandle?: string;
|
|
119
|
+
status?: RdapStatus[];
|
|
120
|
+
entities?: RdapEntityObjectClass[];
|
|
121
|
+
remarks: RdapRemark[];
|
|
122
|
+
links?: RdapLink[];
|
|
123
|
+
port43?: string;
|
|
124
|
+
events?: RdapEvent[];
|
|
125
|
+
}
|
|
126
|
+
interface RdapAutonomousSystemNumberObjectClass {
|
|
127
|
+
objectClassName: 'autnum';
|
|
128
|
+
handle?: string;
|
|
129
|
+
startAutnum?: string;
|
|
130
|
+
endAutnum?: string;
|
|
131
|
+
name?: string;
|
|
132
|
+
type?: string;
|
|
133
|
+
status?: RdapStatus[];
|
|
134
|
+
country?: string;
|
|
135
|
+
entities?: RdapEntityObjectClass[];
|
|
136
|
+
remarks: RdapRemark[];
|
|
137
|
+
links?: RdapLink[];
|
|
138
|
+
port43?: string;
|
|
139
|
+
events?: RdapEvent[];
|
|
140
|
+
}
|
|
141
|
+
interface RdapDomainSuccessResponse extends RdapDomainObjectClass {
|
|
142
|
+
rdapConformance: string[];
|
|
143
|
+
}
|
|
144
|
+
interface RdapIpSuccessResponse extends RdapIPNetworkObjectClass {
|
|
145
|
+
rdapConformance: string[];
|
|
146
|
+
}
|
|
147
|
+
interface RdapAutnumSuccessResponse extends RdapAutonomousSystemNumberObjectClass {
|
|
148
|
+
rdapConformance: string[];
|
|
149
|
+
}
|
|
150
|
+
interface RdapHelpSuccessResponse {
|
|
151
|
+
rdapConformance: string[];
|
|
152
|
+
notices?: RdapNotice[];
|
|
153
|
+
}
|
|
154
|
+
interface RdapErrorResponse {
|
|
155
|
+
errorCode: number;
|
|
156
|
+
title?: string;
|
|
157
|
+
description?: string[];
|
|
158
|
+
}
|
|
159
|
+
type RdapDomainResponse = RdapErrorResponse & RdapDomainSuccessResponse;
|
|
160
|
+
type RdapIpResponse = RdapErrorResponse & RdapIpSuccessResponse;
|
|
161
|
+
type RdapAutnumResponse = RdapErrorResponse & RdapAutnumSuccessResponse;
|
|
162
|
+
type RdapHelpResponse = RdapErrorResponse & RdapHelpSuccessResponse;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* HTTP methods supported by the fetcher
|
|
166
|
+
*/
|
|
167
|
+
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
168
|
+
/**
|
|
169
|
+
* Options for the fetch request
|
|
170
|
+
*/
|
|
171
|
+
interface FetchOptions<T = unknown> {
|
|
172
|
+
method: HttpMethod;
|
|
173
|
+
url: string;
|
|
174
|
+
body?: T;
|
|
175
|
+
headers?: Record<string, string>;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Response from the fetch request
|
|
179
|
+
*/
|
|
180
|
+
interface FetchResponse<T = unknown> {
|
|
181
|
+
status: number;
|
|
182
|
+
data: T;
|
|
183
|
+
headers: Headers;
|
|
184
|
+
url: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Interface for the fetcher implementation
|
|
188
|
+
*/
|
|
189
|
+
interface Fetcher {
|
|
190
|
+
fetch<TBody = unknown, TResponse = unknown>(options: FetchOptions<TBody>): Promise<FetchResponse<TResponse>>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Default fetcher implementation using node-fetch
|
|
194
|
+
*/
|
|
195
|
+
declare class DefaultFetcher implements Fetcher {
|
|
196
|
+
fetch<TBody = unknown, TResponse = unknown>({ method, url, body, headers, }: FetchOptions<TBody>): Promise<FetchResponse<TResponse>>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
interface RdapClientOptions {
|
|
200
|
+
fetcher?: Fetcher;
|
|
201
|
+
baseDomain?: string;
|
|
202
|
+
}
|
|
203
|
+
declare class RdapClient {
|
|
204
|
+
private readonly fetcher;
|
|
205
|
+
private readonly baseDomain;
|
|
206
|
+
constructor(options?: RdapClientOptions);
|
|
207
|
+
/**
|
|
208
|
+
* Convert domain to punycode if needed
|
|
209
|
+
*/
|
|
210
|
+
private prepareDomain;
|
|
211
|
+
/**
|
|
212
|
+
* Query domain information
|
|
213
|
+
* @param domain Domain name to query (supports IDN/punycode)
|
|
214
|
+
* @returns Domain information
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* const client = new RdapClient();
|
|
218
|
+
* const domain = await client.domain('example.com');
|
|
219
|
+
* // IDN support
|
|
220
|
+
* const idn = await client.domain('münchen.de');
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
domain(domain: string): Promise<RdapDomainResponse>;
|
|
224
|
+
/**
|
|
225
|
+
* Query IP address or network information
|
|
226
|
+
* @param ip IP address or CIDR notation
|
|
227
|
+
* @returns IP network information
|
|
228
|
+
* @example
|
|
229
|
+
* ```typescript
|
|
230
|
+
* const client = new RdapClient();
|
|
231
|
+
* const ip = await client.ip('8.8.8.8');
|
|
232
|
+
* // or with CIDR notation
|
|
233
|
+
* const network = await client.ip('2001:db8::1/128');
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
ip(ip: string): Promise<RdapIpResponse>;
|
|
237
|
+
/**
|
|
238
|
+
* Query Autonomous System Number information
|
|
239
|
+
* @param asn Autonomous System Number
|
|
240
|
+
* @returns ASN information
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const client = new RdapClient();
|
|
244
|
+
* const asn = await client.autnum(174);
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
autnum(asn: number): Promise<RdapAutnumResponse>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export { DefaultFetcher, type FetchOptions, type FetchResponse, type Fetcher, type HttpMethod, type RdapAutnumResponse, type RdapAutnumSuccessResponse, type RdapAutonomousSystemNumberObjectClass, RdapClient, type RdapClientOptions, type RdapDomainObjectClass, type RdapDomainResponse, type RdapDomainSuccessResponse, type RdapDsData, type RdapEntityObjectClass, type RdapErrorResponse, type RdapEvent, type RdapHelpResponse, type RdapHelpSuccessResponse, type RdapIPNetworkObjectClass, type RdapIpResponse, type RdapIpSuccessResponse, type RdapKeyData, type RdapLink, type RdapNameserverObjectClass, type RdapNotice, type RdapNoticeAndRemarkTypes, type RdapObjectClass, type RdapPublicID, type RdapRemark, type RdapSecureDNS, type RdapStatus };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// src/utils/fetcher.ts
|
|
2
|
+
var DefaultFetcher = class {
|
|
3
|
+
async fetch({
|
|
4
|
+
method,
|
|
5
|
+
url,
|
|
6
|
+
body,
|
|
7
|
+
headers = {}
|
|
8
|
+
}) {
|
|
9
|
+
const requestUrl = new URL(url);
|
|
10
|
+
if (method === "GET" && body) {
|
|
11
|
+
Object.entries(body).forEach(([key, value]) => {
|
|
12
|
+
requestUrl.searchParams.append(key, value);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const requestInit = {
|
|
16
|
+
method,
|
|
17
|
+
headers: {
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
...headers
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
if (method !== "GET" && body) {
|
|
23
|
+
requestInit.body = JSON.stringify(body);
|
|
24
|
+
}
|
|
25
|
+
const response = await fetch(requestUrl, requestInit);
|
|
26
|
+
const data = await response.json();
|
|
27
|
+
return {
|
|
28
|
+
status: response.status,
|
|
29
|
+
data,
|
|
30
|
+
headers: response.headers,
|
|
31
|
+
url: response.url
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// src/utils/throwables.ts
|
|
37
|
+
var RdapNotFoundError = class extends Error {
|
|
38
|
+
constructor(message) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = "RdapNotFoundError";
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/client.ts
|
|
45
|
+
var RdapClient = class {
|
|
46
|
+
constructor(options = {}) {
|
|
47
|
+
this.fetcher = options.fetcher ?? new DefaultFetcher();
|
|
48
|
+
this.baseDomain = options.baseDomain ?? "www.rdap.net";
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Convert domain to punycode if needed
|
|
52
|
+
*/
|
|
53
|
+
prepareDomain(domain) {
|
|
54
|
+
return domain.toLowerCase().split(".").map((part) => {
|
|
55
|
+
try {
|
|
56
|
+
if (part.includes("xn--")) {
|
|
57
|
+
return part;
|
|
58
|
+
}
|
|
59
|
+
const url = new URL(`https://${part}`);
|
|
60
|
+
return url.hostname.startsWith("xn--") ? url.hostname : part;
|
|
61
|
+
} catch {
|
|
62
|
+
return part;
|
|
63
|
+
}
|
|
64
|
+
}).join(".");
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Query domain information
|
|
68
|
+
* @param domain Domain name to query (supports IDN/punycode)
|
|
69
|
+
* @returns Domain information
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const client = new RdapClient();
|
|
73
|
+
* const domain = await client.domain('example.com');
|
|
74
|
+
* // IDN support
|
|
75
|
+
* const idn = await client.domain('münchen.de');
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
async domain(domain) {
|
|
79
|
+
const punyDomain = this.prepareDomain(domain);
|
|
80
|
+
const url = `https://${this.baseDomain}/domain/${encodeURIComponent(punyDomain)}`;
|
|
81
|
+
try {
|
|
82
|
+
const response = await this.fetcher.fetch({
|
|
83
|
+
method: "GET",
|
|
84
|
+
url
|
|
85
|
+
});
|
|
86
|
+
if (response.status === 404 && response.url === url) {
|
|
87
|
+
throw new RdapNotFoundError(`Domain ${domain} has no RDAP server for its TLD`);
|
|
88
|
+
}
|
|
89
|
+
return response.data;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (error instanceof SyntaxError) {
|
|
92
|
+
throw new RdapNotFoundError(`Domain ${domain} has no RDAP server for its TLD`);
|
|
93
|
+
} else {
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Query IP address or network information
|
|
100
|
+
* @param ip IP address or CIDR notation
|
|
101
|
+
* @returns IP network information
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* const client = new RdapClient();
|
|
105
|
+
* const ip = await client.ip('8.8.8.8');
|
|
106
|
+
* // or with CIDR notation
|
|
107
|
+
* const network = await client.ip('2001:db8::1/128');
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
async ip(ip) {
|
|
111
|
+
const response = await this.fetcher.fetch({
|
|
112
|
+
method: "GET",
|
|
113
|
+
url: `https://${this.baseDomain}/ip/${encodeURIComponent(ip)}`
|
|
114
|
+
});
|
|
115
|
+
return response.data;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Query Autonomous System Number information
|
|
119
|
+
* @param asn Autonomous System Number
|
|
120
|
+
* @returns ASN information
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const client = new RdapClient();
|
|
124
|
+
* const asn = await client.autnum(174);
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
async autnum(asn) {
|
|
128
|
+
const response = await this.fetcher.fetch({
|
|
129
|
+
method: "GET",
|
|
130
|
+
url: `https://${this.baseDomain}/autnum/${asn}`
|
|
131
|
+
});
|
|
132
|
+
return response.data;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
export {
|
|
136
|
+
DefaultFetcher,
|
|
137
|
+
RdapClient
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/fetcher.ts","../src/utils/throwables.ts","../src/client.ts"],"sourcesContent":["/**\n * HTTP methods supported by the fetcher\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\n/**\n * Options for the fetch request\n */\nexport interface FetchOptions<T = unknown> {\n method: HttpMethod;\n url: string;\n body?: T;\n headers?: Record<string, string>;\n}\n\n/**\n * Response from the fetch request\n */\nexport interface FetchResponse<T = unknown> {\n status: number;\n data: T;\n headers: Headers;\n url: string;\n}\n\n/**\n * Interface for the fetcher implementation\n */\nexport interface Fetcher {\n fetch<TBody = unknown, TResponse = unknown>(\n options: FetchOptions<TBody>,\n ): Promise<FetchResponse<TResponse>>;\n}\n\n/**\n * Default fetcher implementation using node-fetch\n */\nexport class DefaultFetcher implements Fetcher {\n async fetch<TBody = unknown, TResponse = unknown>({\n method,\n url,\n body,\n headers = {},\n }: FetchOptions<TBody>): Promise<FetchResponse<TResponse>> {\n const requestUrl = new URL(url);\n\n // For GET requests, convert body to query parameters\n if (method === 'GET' && body) {\n Object.entries(body as Record<string, string>).forEach(([key, value]) => {\n requestUrl.searchParams.append(key, value);\n });\n }\n\n const requestInit: RequestInit = {\n method,\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n };\n\n // Add body for non-GET requests\n if (method !== 'GET' && body) {\n requestInit.body = JSON.stringify(body);\n }\n\n const response = await fetch(requestUrl, requestInit);\n const data = (await response.json()) as TResponse;\n\n return {\n status: response.status,\n data,\n headers: response.headers,\n url: response.url,\n };\n }\n}\n","export class RdapNotFoundError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RdapNotFoundError';\n }\n}\n","import { RdapAutnumResponse, RdapDomainResponse, RdapIpResponse } from './types';\nimport { DefaultFetcher, Fetcher } from './utils/fetcher';\nimport { RdapNotFoundError } from './utils/throwables';\n\nexport interface RdapClientOptions {\n fetcher?: Fetcher;\n baseDomain?: string;\n}\n\nexport class RdapClient {\n private readonly fetcher: Fetcher;\n private readonly baseDomain: string;\n\n constructor(options: RdapClientOptions = {}) {\n this.fetcher = options.fetcher ?? new DefaultFetcher();\n this.baseDomain = options.baseDomain ?? 'www.rdap.net';\n }\n\n /**\n * Convert domain to punycode if needed\n */\n private prepareDomain(domain: string): string {\n return domain\n .toLowerCase()\n .split('.')\n .map((part) => {\n try {\n if (part.includes('xn--')) {\n return part;\n }\n // Use URL API to handle IDN conversion\n const url = new URL(`https://${part}`);\n return url.hostname.startsWith('xn--') ? url.hostname : part;\n } catch {\n return part;\n }\n })\n .join('.');\n }\n\n /**\n * Query domain information\n * @param domain Domain name to query (supports IDN/punycode)\n * @returns Domain information\n * @example\n * ```typescript\n * const client = new RdapClient();\n * const domain = await client.domain('example.com');\n * // IDN support\n * const idn = await client.domain('münchen.de');\n * ```\n */\n async domain(domain: string): Promise<RdapDomainResponse> {\n const punyDomain = this.prepareDomain(domain);\n const url = `https://${this.baseDomain}/domain/${encodeURIComponent(punyDomain)}`;\n try {\n const response = await this.fetcher.fetch<never, RdapDomainResponse>({\n method: 'GET',\n url,\n });\n\n if (response.status === 404 && response.url === url) {\n throw new RdapNotFoundError(`Domain ${domain} has no RDAP server for its TLD`);\n }\n\n return response.data;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new RdapNotFoundError(`Domain ${domain} has no RDAP server for its TLD`);\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Query IP address or network information\n * @param ip IP address or CIDR notation\n * @returns IP network information\n * @example\n * ```typescript\n * const client = new RdapClient();\n * const ip = await client.ip('8.8.8.8');\n * // or with CIDR notation\n * const network = await client.ip('2001:db8::1/128');\n * ```\n */\n async ip(ip: string): Promise<RdapIpResponse> {\n const response = await this.fetcher.fetch<never, RdapIpResponse>({\n method: 'GET',\n url: `https://${this.baseDomain}/ip/${encodeURIComponent(ip)}`,\n });\n\n return response.data;\n }\n\n /**\n * Query Autonomous System Number information\n * @param asn Autonomous System Number\n * @returns ASN information\n * @example\n * ```typescript\n * const client = new RdapClient();\n * const asn = await client.autnum(174);\n * ```\n */\n async autnum(asn: number): Promise<RdapAutnumResponse> {\n const response = await this.fetcher.fetch<never, RdapAutnumResponse>({\n method: 'GET',\n url: `https://${this.baseDomain}/autnum/${asn}`,\n });\n\n return response.data;\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@chez14/rdap-sdk",
|
|
3
|
+
"version": "0.1.1-13",
|
|
4
|
+
"description": "A TypeScript SDK for RDAP.net. Directly calls RDAP APIs from RDAP.net as the main RDAP Server Database.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://gitlab.com/chez14/rdap-sdk-ts.git"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"module": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./ts/*": "./src/*"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [],
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=16"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@eslint/compat": "^1.2.4",
|
|
28
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
29
|
+
"@eslint/js": "^9.17.0",
|
|
30
|
+
"@types/node": "^22.10.2",
|
|
31
|
+
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
|
32
|
+
"@typescript-eslint/parser": "^8.18.1",
|
|
33
|
+
"eslint": "^9.17.0",
|
|
34
|
+
"eslint-config-prettier": "^9.1.0",
|
|
35
|
+
"eslint-plugin-import": "^2.31.0",
|
|
36
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
37
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
38
|
+
"globals": "^15.14.0",
|
|
39
|
+
"prettier": "^3.4.2",
|
|
40
|
+
"tsup": "^8.3.5",
|
|
41
|
+
"typescript": "^5.7.2",
|
|
42
|
+
"vitest": "^2.1.8"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"provenance": true,
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"test": "vitest --no-watch",
|
|
52
|
+
"test:watch": "vitest --watch",
|
|
53
|
+
"lint": "eslint .",
|
|
54
|
+
"lint:fix": "eslint . --fix",
|
|
55
|
+
"format": "prettier --write ."
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { RdapAutnumResponse, RdapDomainResponse, RdapIpResponse } from './types';
|
|
2
|
+
import { DefaultFetcher, Fetcher } from './utils/fetcher';
|
|
3
|
+
import { RdapNotFoundError } from './utils/throwables';
|
|
4
|
+
|
|
5
|
+
export interface RdapClientOptions {
|
|
6
|
+
fetcher?: Fetcher;
|
|
7
|
+
baseDomain?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class RdapClient {
|
|
11
|
+
private readonly fetcher: Fetcher;
|
|
12
|
+
private readonly baseDomain: string;
|
|
13
|
+
|
|
14
|
+
constructor(options: RdapClientOptions = {}) {
|
|
15
|
+
this.fetcher = options.fetcher ?? new DefaultFetcher();
|
|
16
|
+
this.baseDomain = options.baseDomain ?? 'www.rdap.net';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Convert domain to punycode if needed
|
|
21
|
+
*/
|
|
22
|
+
private prepareDomain(domain: string): string {
|
|
23
|
+
return domain
|
|
24
|
+
.toLowerCase()
|
|
25
|
+
.split('.')
|
|
26
|
+
.map((part) => {
|
|
27
|
+
try {
|
|
28
|
+
if (part.includes('xn--')) {
|
|
29
|
+
return part;
|
|
30
|
+
}
|
|
31
|
+
// Use URL API to handle IDN conversion
|
|
32
|
+
const url = new URL(`https://${part}`);
|
|
33
|
+
return url.hostname.startsWith('xn--') ? url.hostname : part;
|
|
34
|
+
} catch {
|
|
35
|
+
return part;
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
.join('.');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Query domain information
|
|
43
|
+
* @param domain Domain name to query (supports IDN/punycode)
|
|
44
|
+
* @returns Domain information
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const client = new RdapClient();
|
|
48
|
+
* const domain = await client.domain('example.com');
|
|
49
|
+
* // IDN support
|
|
50
|
+
* const idn = await client.domain('münchen.de');
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
async domain(domain: string): Promise<RdapDomainResponse> {
|
|
54
|
+
const punyDomain = this.prepareDomain(domain);
|
|
55
|
+
const url = `https://${this.baseDomain}/domain/${encodeURIComponent(punyDomain)}`;
|
|
56
|
+
try {
|
|
57
|
+
const response = await this.fetcher.fetch<never, RdapDomainResponse>({
|
|
58
|
+
method: 'GET',
|
|
59
|
+
url,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (response.status === 404 && response.url === url) {
|
|
63
|
+
throw new RdapNotFoundError(`Domain ${domain} has no RDAP server for its TLD`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return response.data;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error instanceof SyntaxError) {
|
|
69
|
+
throw new RdapNotFoundError(`Domain ${domain} has no RDAP server for its TLD`);
|
|
70
|
+
} else {
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Query IP address or network information
|
|
78
|
+
* @param ip IP address or CIDR notation
|
|
79
|
+
* @returns IP network information
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const client = new RdapClient();
|
|
83
|
+
* const ip = await client.ip('8.8.8.8');
|
|
84
|
+
* // or with CIDR notation
|
|
85
|
+
* const network = await client.ip('2001:db8::1/128');
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
async ip(ip: string): Promise<RdapIpResponse> {
|
|
89
|
+
const response = await this.fetcher.fetch<never, RdapIpResponse>({
|
|
90
|
+
method: 'GET',
|
|
91
|
+
url: `https://${this.baseDomain}/ip/${encodeURIComponent(ip)}`,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return response.data;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Query Autonomous System Number information
|
|
99
|
+
* @param asn Autonomous System Number
|
|
100
|
+
* @returns ASN information
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const client = new RdapClient();
|
|
104
|
+
* const asn = await client.autnum(174);
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
async autnum(asn: number): Promise<RdapAutnumResponse> {
|
|
108
|
+
const response = await this.fetcher.fetch<never, RdapAutnumResponse>({
|
|
109
|
+
method: 'GET',
|
|
110
|
+
url: `https://${this.baseDomain}/autnum/${asn}`,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return response.data;
|
|
114
|
+
}
|
|
115
|
+
}
|
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* These files were copied directly from
|
|
3
|
+
* https://github.com/dcoffey-zengenti/node-rdap/blob/aa294812f01730f3ce5f1c384fb92cfbfeaf846f/src/types.ts.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface RdapLink {
|
|
7
|
+
value: string;
|
|
8
|
+
rel: string;
|
|
9
|
+
href: string;
|
|
10
|
+
hreflang?: string[];
|
|
11
|
+
type?: string;
|
|
12
|
+
media?: string;
|
|
13
|
+
title?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface RdapEvent {
|
|
17
|
+
eventAction: string;
|
|
18
|
+
eventActor?: string;
|
|
19
|
+
eventDate: string;
|
|
20
|
+
links?: RdapLink[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface RdapPublicID {
|
|
24
|
+
type: string;
|
|
25
|
+
identifier: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type RdapStatus =
|
|
29
|
+
| 'validated'
|
|
30
|
+
| 'renew prohibited'
|
|
31
|
+
| 'update prohibited'
|
|
32
|
+
| 'transfer prohibited'
|
|
33
|
+
| 'delete prohibited'
|
|
34
|
+
| 'proxy'
|
|
35
|
+
| 'private'
|
|
36
|
+
| 'removed'
|
|
37
|
+
| 'obscured'
|
|
38
|
+
| 'associated'
|
|
39
|
+
| 'active'
|
|
40
|
+
| 'inactive'
|
|
41
|
+
| 'locked'
|
|
42
|
+
| 'pending create'
|
|
43
|
+
| 'pending renew'
|
|
44
|
+
| 'pending transfer'
|
|
45
|
+
| 'pending update'
|
|
46
|
+
| 'pending delete';
|
|
47
|
+
|
|
48
|
+
export type RdapNoticeAndRemarkTypes =
|
|
49
|
+
| 'result set truncated due to authorization'
|
|
50
|
+
| 'result set truncated due to excessive load'
|
|
51
|
+
| 'result set truncated due to unexplainable reasons'
|
|
52
|
+
| 'object truncated due to authorization'
|
|
53
|
+
| 'object truncated due to excessive load'
|
|
54
|
+
| 'object truncated due to unexplainable reasons';
|
|
55
|
+
|
|
56
|
+
export interface RdapRemark {
|
|
57
|
+
title?: string;
|
|
58
|
+
type?: RdapNoticeAndRemarkTypes;
|
|
59
|
+
description: string[];
|
|
60
|
+
links?: RdapLink[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface RdapDsData {
|
|
64
|
+
keyTag?: number;
|
|
65
|
+
algorithm?: number;
|
|
66
|
+
digest?: string;
|
|
67
|
+
digestType?: string;
|
|
68
|
+
events?: RdapEvent[];
|
|
69
|
+
links?: RdapLink[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface RdapKeyData {
|
|
73
|
+
flags?: number;
|
|
74
|
+
protocol?: number;
|
|
75
|
+
publicKey?: string;
|
|
76
|
+
algorithm?: number;
|
|
77
|
+
events?: RdapEvent[];
|
|
78
|
+
links?: RdapLink[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface RdapSecureDNS {
|
|
82
|
+
zoneSigned?: boolean;
|
|
83
|
+
delegationSigned?: boolean;
|
|
84
|
+
maxSigLife?: number;
|
|
85
|
+
dsData?: RdapDsData[];
|
|
86
|
+
keyData?: RdapKeyData[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type RdapNotice = RdapRemark;
|
|
90
|
+
|
|
91
|
+
export type RdapObjectClass =
|
|
92
|
+
| RdapEntityObjectClass
|
|
93
|
+
| RdapNameserverObjectClass
|
|
94
|
+
| RdapDomainObjectClass;
|
|
95
|
+
|
|
96
|
+
export interface RdapEntityObjectClass {
|
|
97
|
+
objectClassName: 'entity';
|
|
98
|
+
handle?: string;
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
100
|
+
vcardArray?: any[];
|
|
101
|
+
roles?: string[];
|
|
102
|
+
publicIds?: RdapPublicID[];
|
|
103
|
+
entities?: RdapEntityObjectClass[];
|
|
104
|
+
remarks?: RdapRemark[];
|
|
105
|
+
links?: RdapLink[];
|
|
106
|
+
events?: RdapEvent[];
|
|
107
|
+
asEventActor?: Omit<RdapEvent, 'eventActor'>[];
|
|
108
|
+
status?: RdapStatus[];
|
|
109
|
+
port43?: string;
|
|
110
|
+
networks?: RdapIPNetworkObjectClass[];
|
|
111
|
+
autnums?: RdapAutonomousSystemNumberObjectClass[];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface RdapNameserverObjectClass {
|
|
115
|
+
objectClassName: 'nameserver';
|
|
116
|
+
handle?: string;
|
|
117
|
+
ldhName?: string;
|
|
118
|
+
unicodeName?: string;
|
|
119
|
+
ipAddresses?: {
|
|
120
|
+
v6: string[];
|
|
121
|
+
v4: string[];
|
|
122
|
+
};
|
|
123
|
+
entities?: RdapEntityObjectClass[];
|
|
124
|
+
status?: RdapStatus[];
|
|
125
|
+
remarks?: RdapRemark[];
|
|
126
|
+
links?: RdapLink[];
|
|
127
|
+
port43?: string;
|
|
128
|
+
events?: RdapEvent[];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface RdapDomainObjectClass {
|
|
132
|
+
objectClassName: 'domain';
|
|
133
|
+
handle?: string;
|
|
134
|
+
ldhName?: string;
|
|
135
|
+
unicodeName?: string;
|
|
136
|
+
variants: {
|
|
137
|
+
relation: string[];
|
|
138
|
+
idnTable: string;
|
|
139
|
+
variantName: {
|
|
140
|
+
ldhName: string;
|
|
141
|
+
unicodeName: string;
|
|
142
|
+
}[];
|
|
143
|
+
}[];
|
|
144
|
+
nameservers: RdapNameserverObjectClass[];
|
|
145
|
+
secureDNS: RdapSecureDNS;
|
|
146
|
+
entities?: RdapEntityObjectClass[];
|
|
147
|
+
status?: RdapStatus[];
|
|
148
|
+
publicIds?: RdapPublicID[];
|
|
149
|
+
remarks: RdapRemark[];
|
|
150
|
+
links?: RdapLink[];
|
|
151
|
+
port43?: string;
|
|
152
|
+
events?: RdapEvent[];
|
|
153
|
+
network?: RdapIPNetworkObjectClass;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface RdapIPNetworkObjectClass {
|
|
157
|
+
objectClassName: 'ip network';
|
|
158
|
+
handle?: string;
|
|
159
|
+
startAddress?: string;
|
|
160
|
+
endAddress?: string;
|
|
161
|
+
ipVersion?: 'v4' | 'v6';
|
|
162
|
+
name?: string;
|
|
163
|
+
type?: string;
|
|
164
|
+
country?: string;
|
|
165
|
+
parentHandle?: string;
|
|
166
|
+
status?: RdapStatus[];
|
|
167
|
+
entities?: RdapEntityObjectClass[];
|
|
168
|
+
remarks: RdapRemark[];
|
|
169
|
+
links?: RdapLink[];
|
|
170
|
+
port43?: string;
|
|
171
|
+
events?: RdapEvent[];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface RdapAutonomousSystemNumberObjectClass {
|
|
175
|
+
objectClassName: 'autnum';
|
|
176
|
+
handle?: string;
|
|
177
|
+
startAutnum?: string;
|
|
178
|
+
endAutnum?: string;
|
|
179
|
+
name?: string;
|
|
180
|
+
type?: string;
|
|
181
|
+
status?: RdapStatus[];
|
|
182
|
+
country?: string;
|
|
183
|
+
entities?: RdapEntityObjectClass[];
|
|
184
|
+
remarks: RdapRemark[];
|
|
185
|
+
links?: RdapLink[];
|
|
186
|
+
port43?: string;
|
|
187
|
+
events?: RdapEvent[];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface RdapDomainSuccessResponse extends RdapDomainObjectClass {
|
|
191
|
+
rdapConformance: string[];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export interface RdapIpSuccessResponse extends RdapIPNetworkObjectClass {
|
|
195
|
+
rdapConformance: string[];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface RdapAutnumSuccessResponse extends RdapAutonomousSystemNumberObjectClass {
|
|
199
|
+
rdapConformance: string[];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface RdapHelpSuccessResponse {
|
|
203
|
+
rdapConformance: string[];
|
|
204
|
+
notices?: RdapNotice[];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface RdapErrorResponse {
|
|
208
|
+
errorCode: number;
|
|
209
|
+
title?: string;
|
|
210
|
+
description?: string[];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export type RdapDomainResponse = RdapErrorResponse & RdapDomainSuccessResponse;
|
|
214
|
+
export type RdapIpResponse = RdapErrorResponse & RdapIpSuccessResponse;
|
|
215
|
+
export type RdapAutnumResponse = RdapErrorResponse & RdapAutnumSuccessResponse;
|
|
216
|
+
export type RdapHelpResponse = RdapErrorResponse & RdapHelpSuccessResponse;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP methods supported by the fetcher
|
|
3
|
+
*/
|
|
4
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for the fetch request
|
|
8
|
+
*/
|
|
9
|
+
export interface FetchOptions<T = unknown> {
|
|
10
|
+
method: HttpMethod;
|
|
11
|
+
url: string;
|
|
12
|
+
body?: T;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Response from the fetch request
|
|
18
|
+
*/
|
|
19
|
+
export interface FetchResponse<T = unknown> {
|
|
20
|
+
status: number;
|
|
21
|
+
data: T;
|
|
22
|
+
headers: Headers;
|
|
23
|
+
url: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Interface for the fetcher implementation
|
|
28
|
+
*/
|
|
29
|
+
export interface Fetcher {
|
|
30
|
+
fetch<TBody = unknown, TResponse = unknown>(
|
|
31
|
+
options: FetchOptions<TBody>,
|
|
32
|
+
): Promise<FetchResponse<TResponse>>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Default fetcher implementation using node-fetch
|
|
37
|
+
*/
|
|
38
|
+
export class DefaultFetcher implements Fetcher {
|
|
39
|
+
async fetch<TBody = unknown, TResponse = unknown>({
|
|
40
|
+
method,
|
|
41
|
+
url,
|
|
42
|
+
body,
|
|
43
|
+
headers = {},
|
|
44
|
+
}: FetchOptions<TBody>): Promise<FetchResponse<TResponse>> {
|
|
45
|
+
const requestUrl = new URL(url);
|
|
46
|
+
|
|
47
|
+
// For GET requests, convert body to query parameters
|
|
48
|
+
if (method === 'GET' && body) {
|
|
49
|
+
Object.entries(body as Record<string, string>).forEach(([key, value]) => {
|
|
50
|
+
requestUrl.searchParams.append(key, value);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const requestInit: RequestInit = {
|
|
55
|
+
method,
|
|
56
|
+
headers: {
|
|
57
|
+
'Content-Type': 'application/json',
|
|
58
|
+
...headers,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Add body for non-GET requests
|
|
63
|
+
if (method !== 'GET' && body) {
|
|
64
|
+
requestInit.body = JSON.stringify(body);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const response = await fetch(requestUrl, requestInit);
|
|
68
|
+
const data = (await response.json()) as TResponse;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
status: response.status,
|
|
72
|
+
data,
|
|
73
|
+
headers: response.headers,
|
|
74
|
+
url: response.url,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|