@chez14/rdap-sdk 0.1.1-5
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 +139 -0
- package/dist/index.js +118 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
- package/src/client.ts +101 -0
- package/src/index.ts +3 -0
- package/src/types.ts +55 -0
- package/src/utils/fetcher.ts +75 -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 RdapOrgClient({
|
|
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 RdapOrgClient({
|
|
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,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base response interface for RDAP queries
|
|
3
|
+
*/
|
|
4
|
+
interface RdapResponse {
|
|
5
|
+
rdapConformance: string[];
|
|
6
|
+
notices?: Array<{
|
|
7
|
+
title?: string;
|
|
8
|
+
description: string[];
|
|
9
|
+
links?: Array<{
|
|
10
|
+
value: string;
|
|
11
|
+
rel: string;
|
|
12
|
+
href: string;
|
|
13
|
+
type?: string;
|
|
14
|
+
}>;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Domain response interface
|
|
19
|
+
*/
|
|
20
|
+
interface DomainResponse extends RdapResponse {
|
|
21
|
+
objectClassName: 'domain';
|
|
22
|
+
handle?: string;
|
|
23
|
+
ldhName: string;
|
|
24
|
+
links: Array<{
|
|
25
|
+
rel: string;
|
|
26
|
+
href: string;
|
|
27
|
+
type?: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* IP Network response interface
|
|
32
|
+
*/
|
|
33
|
+
interface IpNetworkResponse extends RdapResponse {
|
|
34
|
+
objectClassName: 'ip network';
|
|
35
|
+
handle: string;
|
|
36
|
+
startAddress: string;
|
|
37
|
+
endAddress: string;
|
|
38
|
+
ipVersion: string;
|
|
39
|
+
name?: string;
|
|
40
|
+
type?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Autonomous System Number response interface
|
|
44
|
+
*/
|
|
45
|
+
interface AutonomousSystemResponse extends RdapResponse {
|
|
46
|
+
objectClassName: 'autnum';
|
|
47
|
+
handle: string;
|
|
48
|
+
startAutnum: number;
|
|
49
|
+
endAutnum: number;
|
|
50
|
+
name?: string;
|
|
51
|
+
type?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* HTTP methods supported by the fetcher
|
|
56
|
+
*/
|
|
57
|
+
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
58
|
+
/**
|
|
59
|
+
* Options for the fetch request
|
|
60
|
+
*/
|
|
61
|
+
interface FetchOptions<T = unknown> {
|
|
62
|
+
method: HttpMethod;
|
|
63
|
+
url: string;
|
|
64
|
+
body?: T;
|
|
65
|
+
headers?: Record<string, string>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Response from the fetch request
|
|
69
|
+
*/
|
|
70
|
+
interface FetchResponse<T = unknown> {
|
|
71
|
+
status: number;
|
|
72
|
+
data: T;
|
|
73
|
+
headers: Headers;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Interface for the fetcher implementation
|
|
77
|
+
*/
|
|
78
|
+
interface Fetcher {
|
|
79
|
+
fetch<TBody = unknown, TResponse = unknown>(options: FetchOptions<TBody>): Promise<FetchResponse<TResponse>>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Default fetcher implementation using node-fetch
|
|
83
|
+
*/
|
|
84
|
+
declare class DefaultFetcher implements Fetcher {
|
|
85
|
+
fetch<TBody = unknown, TResponse = unknown>({ method, url, body, headers, }: FetchOptions<TBody>): Promise<FetchResponse<TResponse>>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface RdapOrgClientOptions {
|
|
89
|
+
fetcher?: Fetcher;
|
|
90
|
+
baseDomain?: string;
|
|
91
|
+
}
|
|
92
|
+
declare class RdapClient {
|
|
93
|
+
private readonly fetcher;
|
|
94
|
+
private readonly baseDomain;
|
|
95
|
+
constructor(options?: RdapOrgClientOptions);
|
|
96
|
+
/**
|
|
97
|
+
* Convert domain to punycode if needed
|
|
98
|
+
*/
|
|
99
|
+
private prepareDomain;
|
|
100
|
+
/**
|
|
101
|
+
* Query domain information
|
|
102
|
+
* @param domain Domain name to query (supports IDN/punycode)
|
|
103
|
+
* @returns Domain information
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* const client = new RdapOrgClient();
|
|
107
|
+
* const domain = await client.domain('example.com');
|
|
108
|
+
* // IDN support
|
|
109
|
+
* const idn = await client.domain('münchen.de');
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
domain(domain: string): Promise<DomainResponse>;
|
|
113
|
+
/**
|
|
114
|
+
* Query IP address or network information
|
|
115
|
+
* @param ip IP address or CIDR notation
|
|
116
|
+
* @returns IP network information
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* const client = new RdapOrgClient();
|
|
120
|
+
* const ip = await client.ip('8.8.8.8');
|
|
121
|
+
* // or with CIDR notation
|
|
122
|
+
* const network = await client.ip('2001:db8::1/128');
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
ip(ip: string): Promise<IpNetworkResponse>;
|
|
126
|
+
/**
|
|
127
|
+
* Query Autonomous System Number information
|
|
128
|
+
* @param asn Autonomous System Number
|
|
129
|
+
* @returns ASN information
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const client = new RdapOrgClient();
|
|
133
|
+
* const asn = await client.autnum(174);
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
autnum(asn: number): Promise<AutonomousSystemResponse>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export { type AutonomousSystemResponse, DefaultFetcher, type DomainResponse, type FetchOptions, type FetchResponse, type Fetcher, type HttpMethod, type IpNetworkResponse, RdapClient, type RdapOrgClientOptions, type RdapResponse };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
};
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/client.ts
|
|
36
|
+
var RdapClient = class {
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.fetcher = options.fetcher ?? new DefaultFetcher();
|
|
39
|
+
this.baseDomain = options.baseDomain ?? "www.rdap.net";
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Convert domain to punycode if needed
|
|
43
|
+
*/
|
|
44
|
+
prepareDomain(domain) {
|
|
45
|
+
return domain.toLowerCase().split(".").map((part) => {
|
|
46
|
+
try {
|
|
47
|
+
if (part.includes("xn--")) {
|
|
48
|
+
return part;
|
|
49
|
+
}
|
|
50
|
+
const url = new URL(`https://${part}`);
|
|
51
|
+
return url.hostname.startsWith("xn--") ? url.hostname : part;
|
|
52
|
+
} catch {
|
|
53
|
+
return part;
|
|
54
|
+
}
|
|
55
|
+
}).join(".");
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Query domain information
|
|
59
|
+
* @param domain Domain name to query (supports IDN/punycode)
|
|
60
|
+
* @returns Domain information
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const client = new RdapOrgClient();
|
|
64
|
+
* const domain = await client.domain('example.com');
|
|
65
|
+
* // IDN support
|
|
66
|
+
* const idn = await client.domain('münchen.de');
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
async domain(domain) {
|
|
70
|
+
const punyDomain = this.prepareDomain(domain);
|
|
71
|
+
const response = await this.fetcher.fetch({
|
|
72
|
+
method: "GET",
|
|
73
|
+
url: `https://${this.baseDomain}/domain/${encodeURIComponent(punyDomain)}`
|
|
74
|
+
});
|
|
75
|
+
return response.data;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Query IP address or network information
|
|
79
|
+
* @param ip IP address or CIDR notation
|
|
80
|
+
* @returns IP network information
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const client = new RdapOrgClient();
|
|
84
|
+
* const ip = await client.ip('8.8.8.8');
|
|
85
|
+
* // or with CIDR notation
|
|
86
|
+
* const network = await client.ip('2001:db8::1/128');
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
async ip(ip) {
|
|
90
|
+
const response = await this.fetcher.fetch({
|
|
91
|
+
method: "GET",
|
|
92
|
+
url: `https://${this.baseDomain}/ip/${encodeURIComponent(ip)}`
|
|
93
|
+
});
|
|
94
|
+
return response.data;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Query Autonomous System Number information
|
|
98
|
+
* @param asn Autonomous System Number
|
|
99
|
+
* @returns ASN information
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const client = new RdapOrgClient();
|
|
103
|
+
* const asn = await client.autnum(174);
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
async autnum(asn) {
|
|
107
|
+
const response = await this.fetcher.fetch({
|
|
108
|
+
method: "GET",
|
|
109
|
+
url: `https://${this.baseDomain}/autnum/${asn}`
|
|
110
|
+
});
|
|
111
|
+
return response.data;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
export {
|
|
115
|
+
DefaultFetcher,
|
|
116
|
+
RdapClient
|
|
117
|
+
};
|
|
118
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/fetcher.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}\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 };\n }\n}\n","import { AutonomousSystemResponse, DomainResponse, IpNetworkResponse } from './types';\nimport { DefaultFetcher, Fetcher } from './utils/fetcher';\n\nexport interface RdapOrgClientOptions {\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: RdapOrgClientOptions = {}) {\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 RdapOrgClient();\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<DomainResponse> {\n const punyDomain = this.prepareDomain(domain);\n const response = await this.fetcher.fetch<never, DomainResponse>({\n method: 'GET',\n url: `https://${this.baseDomain}/domain/${encodeURIComponent(punyDomain)}`,\n });\n\n return response.data;\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 RdapOrgClient();\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<IpNetworkResponse> {\n const response = await this.fetcher.fetch<never, IpNetworkResponse>({\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 RdapOrgClient();\n * const asn = await client.autnum(174);\n * ```\n */\n async autnum(asn: number): Promise<AutonomousSystemResponse> {\n const response = await this.fetcher.fetch<never, AutonomousSystemResponse>({\n method: 'GET',\n url: `https://${this.baseDomain}/autnum/${asn}`,\n });\n\n return response.data;\n }\n}\n"],"mappings":";AAoCO,IAAM,iBAAN,MAAwC;AAAA,EAC7C,MAAM,MAA4C;AAAA,IAChD;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,CAAC;AAAA,EACb,GAA2D;AACzD,UAAM,aAAa,IAAI,IAAI,GAAG;AAG9B,QAAI,WAAW,SAAS,MAAM;AAC5B,aAAO,QAAQ,IAA8B,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACvE,mBAAW,aAAa,OAAO,KAAK,KAAK;AAAA,MAC3C,CAAC;AAAA,IACH;AAEA,UAAM,cAA2B;AAAA,MAC/B;AAAA,MACA,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG;AAAA,MACL;AAAA,IACF;AAGA,QAAI,WAAW,SAAS,MAAM;AAC5B,kBAAY,OAAO,KAAK,UAAU,IAAI;AAAA,IACxC;AAEA,UAAM,WAAW,MAAM,MAAM,YAAY,WAAW;AACpD,UAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,WAAO;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB;AAAA,MACA,SAAS,SAAS;AAAA,IACpB;AAAA,EACF;AACF;;;AClEO,IAAM,aAAN,MAAiB;AAAA,EAItB,YAAY,UAAgC,CAAC,GAAG;AAC9C,SAAK,UAAU,QAAQ,WAAW,IAAI,eAAe;AACrD,SAAK,aAAa,QAAQ,cAAc;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,QAAwB;AAC5C,WAAO,OACJ,YAAY,EACZ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS;AACb,UAAI;AACF,YAAI,KAAK,SAAS,MAAM,GAAG;AACzB,iBAAO;AAAA,QACT;AAEA,cAAM,MAAM,IAAI,IAAI,WAAW,IAAI,EAAE;AACrC,eAAO,IAAI,SAAS,WAAW,MAAM,IAAI,IAAI,WAAW;AAAA,MAC1D,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,CAAC,EACA,KAAK,GAAG;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,OAAO,QAAyC;AACpD,UAAM,aAAa,KAAK,cAAc,MAAM;AAC5C,UAAM,WAAW,MAAM,KAAK,QAAQ,MAA6B;AAAA,MAC/D,QAAQ;AAAA,MACR,KAAK,WAAW,KAAK,UAAU,WAAW,mBAAmB,UAAU,CAAC;AAAA,IAC1E,CAAC;AAED,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,GAAG,IAAwC;AAC/C,UAAM,WAAW,MAAM,KAAK,QAAQ,MAAgC;AAAA,MAClE,QAAQ;AAAA,MACR,KAAK,WAAW,KAAK,UAAU,OAAO,mBAAmB,EAAE,CAAC;AAAA,IAC9D,CAAC;AAED,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,OAAO,KAAgD;AAC3D,UAAM,WAAW,MAAM,KAAK,QAAQ,MAAuC;AAAA,MACzE,QAAQ;AAAA,MACR,KAAK,WAAW,KAAK,UAAU,WAAW,GAAG;AAAA,IAC/C,CAAC;AAED,WAAO,SAAS;AAAA,EAClB;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@chez14/rdap-sdk",
|
|
3
|
+
"version": "0.1.1-5",
|
|
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.mjs",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"require": "./dist/index.js",
|
|
16
|
+
"import": "./dist/index.mjs",
|
|
17
|
+
"types": "./dist/index.d.ts"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"test": "vitest --no-watch",
|
|
23
|
+
"test:watch": "vitest --watch",
|
|
24
|
+
"lint": "eslint .",
|
|
25
|
+
"lint:fix": "eslint . --fix",
|
|
26
|
+
"format": "prettier --write ."
|
|
27
|
+
},
|
|
28
|
+
"keywords": [],
|
|
29
|
+
"author": "",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=16"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@eslint/compat": "^1.2.4",
|
|
36
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
37
|
+
"@eslint/js": "^9.17.0",
|
|
38
|
+
"@types/node": "^22.10.2",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
|
40
|
+
"@typescript-eslint/parser": "^8.18.1",
|
|
41
|
+
"eslint": "^9.17.0",
|
|
42
|
+
"eslint-config-prettier": "^9.1.0",
|
|
43
|
+
"eslint-plugin-import": "^2.31.0",
|
|
44
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
45
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
46
|
+
"globals": "^15.14.0",
|
|
47
|
+
"prettier": "^3.4.2",
|
|
48
|
+
"tsup": "^8.3.5",
|
|
49
|
+
"typescript": "^5.7.2",
|
|
50
|
+
"vitest": "^2.1.8"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {},
|
|
53
|
+
"packageManager": "pnpm@9.15.1+sha256.9e534e70afef06374f6126b44bda5760947135ce16a30aef1010e965fb7e3e3e"
|
|
54
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { AutonomousSystemResponse, DomainResponse, IpNetworkResponse } from './types';
|
|
2
|
+
import { DefaultFetcher, Fetcher } from './utils/fetcher';
|
|
3
|
+
|
|
4
|
+
export interface RdapOrgClientOptions {
|
|
5
|
+
fetcher?: Fetcher;
|
|
6
|
+
baseDomain?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class RdapClient {
|
|
10
|
+
private readonly fetcher: Fetcher;
|
|
11
|
+
private readonly baseDomain: string;
|
|
12
|
+
|
|
13
|
+
constructor(options: RdapOrgClientOptions = {}) {
|
|
14
|
+
this.fetcher = options.fetcher ?? new DefaultFetcher();
|
|
15
|
+
this.baseDomain = options.baseDomain ?? 'www.rdap.net';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Convert domain to punycode if needed
|
|
20
|
+
*/
|
|
21
|
+
private prepareDomain(domain: string): string {
|
|
22
|
+
return domain
|
|
23
|
+
.toLowerCase()
|
|
24
|
+
.split('.')
|
|
25
|
+
.map((part) => {
|
|
26
|
+
try {
|
|
27
|
+
if (part.includes('xn--')) {
|
|
28
|
+
return part;
|
|
29
|
+
}
|
|
30
|
+
// Use URL API to handle IDN conversion
|
|
31
|
+
const url = new URL(`https://${part}`);
|
|
32
|
+
return url.hostname.startsWith('xn--') ? url.hostname : part;
|
|
33
|
+
} catch {
|
|
34
|
+
return part;
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
.join('.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Query domain information
|
|
42
|
+
* @param domain Domain name to query (supports IDN/punycode)
|
|
43
|
+
* @returns Domain information
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const client = new RdapOrgClient();
|
|
47
|
+
* const domain = await client.domain('example.com');
|
|
48
|
+
* // IDN support
|
|
49
|
+
* const idn = await client.domain('münchen.de');
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
async domain(domain: string): Promise<DomainResponse> {
|
|
53
|
+
const punyDomain = this.prepareDomain(domain);
|
|
54
|
+
const response = await this.fetcher.fetch<never, DomainResponse>({
|
|
55
|
+
method: 'GET',
|
|
56
|
+
url: `https://${this.baseDomain}/domain/${encodeURIComponent(punyDomain)}`,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return response.data;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Query IP address or network information
|
|
64
|
+
* @param ip IP address or CIDR notation
|
|
65
|
+
* @returns IP network information
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const client = new RdapOrgClient();
|
|
69
|
+
* const ip = await client.ip('8.8.8.8');
|
|
70
|
+
* // or with CIDR notation
|
|
71
|
+
* const network = await client.ip('2001:db8::1/128');
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
async ip(ip: string): Promise<IpNetworkResponse> {
|
|
75
|
+
const response = await this.fetcher.fetch<never, IpNetworkResponse>({
|
|
76
|
+
method: 'GET',
|
|
77
|
+
url: `https://${this.baseDomain}/ip/${encodeURIComponent(ip)}`,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return response.data;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Query Autonomous System Number information
|
|
85
|
+
* @param asn Autonomous System Number
|
|
86
|
+
* @returns ASN information
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const client = new RdapOrgClient();
|
|
90
|
+
* const asn = await client.autnum(174);
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
async autnum(asn: number): Promise<AutonomousSystemResponse> {
|
|
94
|
+
const response = await this.fetcher.fetch<never, AutonomousSystemResponse>({
|
|
95
|
+
method: 'GET',
|
|
96
|
+
url: `https://${this.baseDomain}/autnum/${asn}`,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return response.data;
|
|
100
|
+
}
|
|
101
|
+
}
|
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base response interface for RDAP queries
|
|
3
|
+
*/
|
|
4
|
+
export interface RdapResponse {
|
|
5
|
+
rdapConformance: string[];
|
|
6
|
+
notices?: Array<{
|
|
7
|
+
title?: string;
|
|
8
|
+
description: string[];
|
|
9
|
+
links?: Array<{
|
|
10
|
+
value: string;
|
|
11
|
+
rel: string;
|
|
12
|
+
href: string;
|
|
13
|
+
type?: string;
|
|
14
|
+
}>;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Domain response interface
|
|
20
|
+
*/
|
|
21
|
+
export interface DomainResponse extends RdapResponse {
|
|
22
|
+
objectClassName: 'domain';
|
|
23
|
+
handle?: string;
|
|
24
|
+
ldhName: string;
|
|
25
|
+
links: Array<{
|
|
26
|
+
rel: string;
|
|
27
|
+
href: string;
|
|
28
|
+
type?: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* IP Network response interface
|
|
34
|
+
*/
|
|
35
|
+
export interface IpNetworkResponse extends RdapResponse {
|
|
36
|
+
objectClassName: 'ip network';
|
|
37
|
+
handle: string;
|
|
38
|
+
startAddress: string;
|
|
39
|
+
endAddress: string;
|
|
40
|
+
ipVersion: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
type?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Autonomous System Number response interface
|
|
47
|
+
*/
|
|
48
|
+
export interface AutonomousSystemResponse extends RdapResponse {
|
|
49
|
+
objectClassName: 'autnum';
|
|
50
|
+
handle: string;
|
|
51
|
+
startAutnum: number;
|
|
52
|
+
endAutnum: number;
|
|
53
|
+
name?: string;
|
|
54
|
+
type?: string;
|
|
55
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Interface for the fetcher implementation
|
|
27
|
+
*/
|
|
28
|
+
export interface Fetcher {
|
|
29
|
+
fetch<TBody = unknown, TResponse = unknown>(
|
|
30
|
+
options: FetchOptions<TBody>,
|
|
31
|
+
): Promise<FetchResponse<TResponse>>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Default fetcher implementation using node-fetch
|
|
36
|
+
*/
|
|
37
|
+
export class DefaultFetcher implements Fetcher {
|
|
38
|
+
async fetch<TBody = unknown, TResponse = unknown>({
|
|
39
|
+
method,
|
|
40
|
+
url,
|
|
41
|
+
body,
|
|
42
|
+
headers = {},
|
|
43
|
+
}: FetchOptions<TBody>): Promise<FetchResponse<TResponse>> {
|
|
44
|
+
const requestUrl = new URL(url);
|
|
45
|
+
|
|
46
|
+
// For GET requests, convert body to query parameters
|
|
47
|
+
if (method === 'GET' && body) {
|
|
48
|
+
Object.entries(body as Record<string, string>).forEach(([key, value]) => {
|
|
49
|
+
requestUrl.searchParams.append(key, value);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const requestInit: RequestInit = {
|
|
54
|
+
method,
|
|
55
|
+
headers: {
|
|
56
|
+
'Content-Type': 'application/json',
|
|
57
|
+
...headers,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Add body for non-GET requests
|
|
62
|
+
if (method !== 'GET' && body) {
|
|
63
|
+
requestInit.body = JSON.stringify(body);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const response = await fetch(requestUrl, requestInit);
|
|
67
|
+
const data = (await response.json()) as TResponse;
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
status: response.status,
|
|
71
|
+
data,
|
|
72
|
+
headers: response.headers,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|