@ensnode/ensrainbow-sdk 0.0.0-next-20260102143513
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 +82 -0
- package/dist/client.d.ts +290 -0
- package/dist/client.js +216 -0
- package/dist/client.js.map +1 -0
- package/dist/consts.d.ts +12 -0
- package/dist/consts.js +17 -0
- package/dist/consts.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +223 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 NameHash
|
|
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,82 @@
|
|
|
1
|
+
# ENSRainbow SDK
|
|
2
|
+
|
|
3
|
+
TypeScript library for interacting with the [ENSRainbow API](https://github.com/namehash/ensnode/tree/main/apps/ensrainbow).
|
|
4
|
+
|
|
5
|
+
Learn more about [ENSRainbow](https://ensrainbow.io) and [ENSNode](https://ensnode.io).
|
|
6
|
+
|
|
7
|
+
## API Reference
|
|
8
|
+
|
|
9
|
+
### Heal Label
|
|
10
|
+
Attempt to heal a labelhash to its original label.
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
const response = await client.heal(
|
|
14
|
+
"0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc"
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
console.log(response);
|
|
18
|
+
|
|
19
|
+
// Output:
|
|
20
|
+
// {
|
|
21
|
+
// status: "success",
|
|
22
|
+
// label: "vitalik"
|
|
23
|
+
// }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Label Count
|
|
27
|
+
Get Count of Healable Labels
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
const response = await client.count();
|
|
31
|
+
|
|
32
|
+
console.log(response);
|
|
33
|
+
|
|
34
|
+
// {
|
|
35
|
+
// "status": "success",
|
|
36
|
+
// "count": 133856894,
|
|
37
|
+
// "timestamp": "2024-01-30T11:18:56Z"
|
|
38
|
+
// }
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Health Check
|
|
42
|
+
Simple verification that the service is running, either in your local setup or for the provided hosted instance
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const response = await client.health();
|
|
46
|
+
|
|
47
|
+
console.log(response);
|
|
48
|
+
|
|
49
|
+
// {
|
|
50
|
+
// "status": "ok",
|
|
51
|
+
// }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Response Types & Error Handling
|
|
55
|
+
Each API endpoint has a designated response type that includes a successful and an erroneous response to account for possible mishaps that could occur during a request.
|
|
56
|
+
|
|
57
|
+
Below is an example of a failed `heal` operation, that shows the resulting error returned by the SDK
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const notFoundResponse = await client.heal(
|
|
61
|
+
"0xf64dc17ae2e2b9b16dbcb8cb05f35a2e6080a5ff1dc53ac0bc48f0e79111f264"
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
console.log(notFoundResponse);
|
|
65
|
+
|
|
66
|
+
// Output:
|
|
67
|
+
// {
|
|
68
|
+
// status: "error",
|
|
69
|
+
// error: "Label not found",
|
|
70
|
+
// errorCode: 404
|
|
71
|
+
// }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Contact Us
|
|
75
|
+
|
|
76
|
+
Visit our [website](https://namehashlabs.org/) to get in contact.
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
Licensed under the MIT License, Copyright © 2025-present [NameHash Labs](https://namehashlabs.org).
|
|
81
|
+
|
|
82
|
+
See [LICENSE](./LICENSE) for more information.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { EnsRainbowClientLabelSet, LabelHash, Label, EnsRainbowServerLabelSet } from '@ensnode/ensnode-sdk';
|
|
2
|
+
|
|
3
|
+
declare namespace EnsRainbow {
|
|
4
|
+
export type ApiClientOptions = EnsRainbowApiClientOptions;
|
|
5
|
+
export interface ApiClient {
|
|
6
|
+
count(): Promise<CountResponse>;
|
|
7
|
+
/**
|
|
8
|
+
* Heal a labelhash to its original label
|
|
9
|
+
* @param labelHash The labelhash to heal
|
|
10
|
+
*/
|
|
11
|
+
heal(labelHash: LabelHash): Promise<HealResponse>;
|
|
12
|
+
health(): Promise<HealthResponse>;
|
|
13
|
+
version(): Promise<VersionResponse>;
|
|
14
|
+
getOptions(): Readonly<EnsRainbowApiClientOptions>;
|
|
15
|
+
}
|
|
16
|
+
type StatusCode = (typeof StatusCode)[keyof typeof StatusCode];
|
|
17
|
+
type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
18
|
+
export interface HealthResponse {
|
|
19
|
+
status: "ok";
|
|
20
|
+
}
|
|
21
|
+
export interface BaseHealResponse<Status extends StatusCode, Error extends ErrorCode> {
|
|
22
|
+
status: Status;
|
|
23
|
+
label?: Label | never;
|
|
24
|
+
error?: string | never;
|
|
25
|
+
errorCode?: Error | never;
|
|
26
|
+
}
|
|
27
|
+
export interface HealSuccess extends BaseHealResponse<typeof StatusCode.Success, never> {
|
|
28
|
+
status: typeof StatusCode.Success;
|
|
29
|
+
label: Label;
|
|
30
|
+
error?: never;
|
|
31
|
+
errorCode?: never;
|
|
32
|
+
}
|
|
33
|
+
export interface HealNotFoundError extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.NotFound> {
|
|
34
|
+
status: typeof StatusCode.Error;
|
|
35
|
+
label?: never;
|
|
36
|
+
error: string;
|
|
37
|
+
errorCode: typeof ErrorCode.NotFound;
|
|
38
|
+
}
|
|
39
|
+
export interface HealServerError extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.ServerError> {
|
|
40
|
+
status: typeof StatusCode.Error;
|
|
41
|
+
label?: never;
|
|
42
|
+
error: string;
|
|
43
|
+
errorCode: typeof ErrorCode.ServerError;
|
|
44
|
+
}
|
|
45
|
+
export interface HealBadRequestError extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.BadRequest> {
|
|
46
|
+
status: typeof StatusCode.Error;
|
|
47
|
+
label?: never;
|
|
48
|
+
error: string;
|
|
49
|
+
errorCode: typeof ErrorCode.BadRequest;
|
|
50
|
+
}
|
|
51
|
+
export type HealResponse = HealSuccess | HealNotFoundError | HealServerError | HealBadRequestError;
|
|
52
|
+
export type HealError = Exclude<HealResponse, HealSuccess>;
|
|
53
|
+
/**
|
|
54
|
+
* Server errors should not be cached.
|
|
55
|
+
*/
|
|
56
|
+
export type CacheableHealResponse = Exclude<HealResponse, HealServerError>;
|
|
57
|
+
export interface BaseCountResponse<Status extends StatusCode, Error extends ErrorCode> {
|
|
58
|
+
status: Status;
|
|
59
|
+
count?: number | never;
|
|
60
|
+
timestamp?: string | never;
|
|
61
|
+
error?: string | never;
|
|
62
|
+
errorCode?: Error | never;
|
|
63
|
+
}
|
|
64
|
+
export interface CountSuccess extends BaseCountResponse<typeof StatusCode.Success, never> {
|
|
65
|
+
status: typeof StatusCode.Success;
|
|
66
|
+
/** The total count of labels that can be healed by the ENSRainbow instance. Always a
|
|
67
|
+
* non-negative integer. */
|
|
68
|
+
count: number;
|
|
69
|
+
timestamp: string;
|
|
70
|
+
error?: never;
|
|
71
|
+
errorCode?: never;
|
|
72
|
+
}
|
|
73
|
+
export interface CountServerError extends BaseCountResponse<typeof StatusCode.Error, typeof ErrorCode.ServerError> {
|
|
74
|
+
status: typeof StatusCode.Error;
|
|
75
|
+
count?: never;
|
|
76
|
+
timestamp?: never;
|
|
77
|
+
error: string;
|
|
78
|
+
errorCode: typeof ErrorCode.ServerError;
|
|
79
|
+
}
|
|
80
|
+
export type CountResponse = CountSuccess | CountServerError;
|
|
81
|
+
/**
|
|
82
|
+
* ENSRainbow version information.
|
|
83
|
+
*/
|
|
84
|
+
export interface VersionInfo {
|
|
85
|
+
/**
|
|
86
|
+
* ENSRainbow version.
|
|
87
|
+
*/
|
|
88
|
+
version: string;
|
|
89
|
+
/**
|
|
90
|
+
* ENSRainbow database schema version.
|
|
91
|
+
*/
|
|
92
|
+
dbSchemaVersion: number;
|
|
93
|
+
/**
|
|
94
|
+
* The EnsRainbowServerLabelSet managed by the ENSRainbow server.
|
|
95
|
+
*/
|
|
96
|
+
labelSet: EnsRainbowServerLabelSet;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Interface for the version endpoint response
|
|
100
|
+
*/
|
|
101
|
+
export interface VersionResponse {
|
|
102
|
+
status: typeof StatusCode.Success;
|
|
103
|
+
versionInfo: VersionInfo;
|
|
104
|
+
}
|
|
105
|
+
export { };
|
|
106
|
+
}
|
|
107
|
+
interface EnsRainbowApiClientOptions {
|
|
108
|
+
/**
|
|
109
|
+
* The maximum number of `HealResponse` values to cache.
|
|
110
|
+
* Must be a non-negative integer.
|
|
111
|
+
* Setting to 0 will disable caching.
|
|
112
|
+
*/
|
|
113
|
+
cacheCapacity: number;
|
|
114
|
+
/**
|
|
115
|
+
* The URL of an ENSRainbow API endpoint.
|
|
116
|
+
*/
|
|
117
|
+
endpointUrl: URL;
|
|
118
|
+
/**
|
|
119
|
+
* Optional label set preferences that the ENSRainbow server at endpointUrl is expected to
|
|
120
|
+
* support. If provided, enables deterministic heal results across time, such that only
|
|
121
|
+
* labels from label sets with versions less than or equal to this value will be returned.
|
|
122
|
+
* Therefore, even if the ENSRainbow server later ingests label sets with greater versions
|
|
123
|
+
* than this value, the results returned across time can be deterministic. If
|
|
124
|
+
* provided, heal operations with this EnsRainbowApiClient will validate the ENSRainbow
|
|
125
|
+
* server manages a compatible label set. If not provided no specific labelSetId validation
|
|
126
|
+
* will be performed during heal operations.
|
|
127
|
+
* If `labelSetId` is provided without `labelSetVersion`, the server will use the latest
|
|
128
|
+
* available version.
|
|
129
|
+
* If `labelSetVersion` is defined, only labels from sets less than or equal to this value
|
|
130
|
+
* will be returned.
|
|
131
|
+
* When `labelSetVersion` is defined, `labelSetId` must also be defined.
|
|
132
|
+
*/
|
|
133
|
+
labelSet?: EnsRainbowClientLabelSet;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* ENSRainbow API client
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* // default options
|
|
141
|
+
* const client = new EnsRainbowApiClient();
|
|
142
|
+
* // custom options
|
|
143
|
+
* const client = new EnsRainbowApiClient({
|
|
144
|
+
* endpointUrl: new URL("https://api.ensrainbow.io"),
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
declare class EnsRainbowApiClient implements EnsRainbow.ApiClient {
|
|
149
|
+
private readonly options;
|
|
150
|
+
private readonly cache;
|
|
151
|
+
private readonly labelSetSearchParams;
|
|
152
|
+
static readonly DEFAULT_CACHE_CAPACITY = 1000;
|
|
153
|
+
/**
|
|
154
|
+
* Create default client options.
|
|
155
|
+
*
|
|
156
|
+
* @returns default options
|
|
157
|
+
*/
|
|
158
|
+
static defaultOptions(): EnsRainbow.ApiClientOptions;
|
|
159
|
+
constructor(options?: Partial<EnsRainbow.ApiClientOptions>);
|
|
160
|
+
/**
|
|
161
|
+
* Attempt to heal a labelHash to its original label.
|
|
162
|
+
*
|
|
163
|
+
* Note on returned labels: ENSRainbow returns labels exactly as they are
|
|
164
|
+
* represented in source rainbow table data. This means:
|
|
165
|
+
*
|
|
166
|
+
* - Labels may or may not be ENS-normalized
|
|
167
|
+
* - Labels can contain any valid string, including dots, null bytes, or be empty
|
|
168
|
+
* - Clients should handle all possible string values appropriately
|
|
169
|
+
*
|
|
170
|
+
* @param labelHash all lowercase 64-digit hex string with 0x prefix (total length of 66 characters)
|
|
171
|
+
* @returns a `HealResponse` indicating the result of the request and the healed label if successful
|
|
172
|
+
* @throws if the request fails due to network failures, DNS lookup failures, request timeouts,
|
|
173
|
+
* CORS violations, or Invalid URLs
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const response = await client.heal(
|
|
177
|
+
* "0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc"
|
|
178
|
+
* );
|
|
179
|
+
*
|
|
180
|
+
* console.log(response);
|
|
181
|
+
*
|
|
182
|
+
* // Output:
|
|
183
|
+
* // {
|
|
184
|
+
* // status: "success",
|
|
185
|
+
* // label: "vitalik"
|
|
186
|
+
* // }
|
|
187
|
+
*
|
|
188
|
+
* const notFoundResponse = await client.heal(
|
|
189
|
+
* "0xf64dc17ae2e2b9b16dbcb8cb05f35a2e6080a5ff1dc53ac0bc48f0e79111f264"
|
|
190
|
+
* );
|
|
191
|
+
*
|
|
192
|
+
* console.log(notFoundResponse);
|
|
193
|
+
*
|
|
194
|
+
* // Output:
|
|
195
|
+
* // {
|
|
196
|
+
* // status: "error",
|
|
197
|
+
* // error: "Label not found",
|
|
198
|
+
* // errorCode: 404
|
|
199
|
+
* // }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
heal(labelHash: LabelHash): Promise<EnsRainbow.HealResponse>;
|
|
203
|
+
/**
|
|
204
|
+
* Get Count of Healable Labels
|
|
205
|
+
*
|
|
206
|
+
* @returns a `CountResponse` indicating the result and the timestamp of the request and the
|
|
207
|
+
* number of healable labels if successful
|
|
208
|
+
* @throws if the request fails due to network failures, DNS lookup failures, request timeouts,
|
|
209
|
+
* CORS violations, or Invalid URLs
|
|
210
|
+
* @example
|
|
211
|
+
*
|
|
212
|
+
* const response = await client.count();
|
|
213
|
+
*
|
|
214
|
+
* console.log(response);
|
|
215
|
+
*
|
|
216
|
+
* // {
|
|
217
|
+
* // "status": "success",
|
|
218
|
+
* // "count": 133856894,
|
|
219
|
+
* // "timestamp": "2024-01-30T11:18:56Z"
|
|
220
|
+
* // }
|
|
221
|
+
*
|
|
222
|
+
*/
|
|
223
|
+
count(): Promise<EnsRainbow.CountResponse>;
|
|
224
|
+
/**
|
|
225
|
+
*
|
|
226
|
+
* Simple verification that the service is running, either in your local setup or for the
|
|
227
|
+
* provided hosted instance.
|
|
228
|
+
* @returns a status of ENS Rainbow service
|
|
229
|
+
* @example
|
|
230
|
+
*
|
|
231
|
+
* const response = await client.health();
|
|
232
|
+
*
|
|
233
|
+
* console.log(response);
|
|
234
|
+
*
|
|
235
|
+
* // {
|
|
236
|
+
* // "status": "ok",
|
|
237
|
+
* // }
|
|
238
|
+
*/
|
|
239
|
+
health(): Promise<EnsRainbow.HealthResponse>;
|
|
240
|
+
/**
|
|
241
|
+
* Get the version information of the ENSRainbow service
|
|
242
|
+
*
|
|
243
|
+
* @returns the version information of the ENSRainbow service
|
|
244
|
+
* @throws if the request fails due to network failures, DNS lookup failures, request
|
|
245
|
+
* timeouts, CORS violations, or invalid URLs
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* const response = await client.version();
|
|
249
|
+
*
|
|
250
|
+
* console.log(response);
|
|
251
|
+
*
|
|
252
|
+
* // {
|
|
253
|
+
* // "status": "success",
|
|
254
|
+
* // "versionInfo": {
|
|
255
|
+
* // "version": "0.1.0",
|
|
256
|
+
* // "dbSchemaVersion": 2,
|
|
257
|
+
* // "labelSet": {
|
|
258
|
+
* // "labelSetId": "subgraph",
|
|
259
|
+
* // "labelSetVersion": 0
|
|
260
|
+
* // }
|
|
261
|
+
* // }
|
|
262
|
+
* // }
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
version(): Promise<EnsRainbow.VersionResponse>;
|
|
266
|
+
/**
|
|
267
|
+
* Get a copy of the current client options.
|
|
268
|
+
*
|
|
269
|
+
* @returns a copy of the current client options.
|
|
270
|
+
*/
|
|
271
|
+
getOptions(): Readonly<EnsRainbowApiClientOptions>;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Determine if a heal response is an error.
|
|
275
|
+
*
|
|
276
|
+
* @param response the heal response to check
|
|
277
|
+
* @returns true if the response is an error, false otherwise
|
|
278
|
+
*/
|
|
279
|
+
declare const isHealError: (response: EnsRainbow.HealResponse) => response is EnsRainbow.HealError;
|
|
280
|
+
/**
|
|
281
|
+
* Determine if a heal response is cacheable.
|
|
282
|
+
*
|
|
283
|
+
* Server errors at not cachable and should be retried.
|
|
284
|
+
*
|
|
285
|
+
* @param response the heal response to check
|
|
286
|
+
* @returns true if the response is cacheable, false otherwise
|
|
287
|
+
*/
|
|
288
|
+
declare const isCacheableHealResponse: (response: EnsRainbow.HealResponse) => response is EnsRainbow.CacheableHealResponse;
|
|
289
|
+
|
|
290
|
+
export { EnsRainbow, EnsRainbowApiClient, type EnsRainbowApiClientOptions, isCacheableHealResponse, isHealError };
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
import {
|
|
3
|
+
buildEnsRainbowClientLabelSet,
|
|
4
|
+
LruCache
|
|
5
|
+
} from "@ensnode/ensnode-sdk";
|
|
6
|
+
|
|
7
|
+
// src/consts.ts
|
|
8
|
+
var DEFAULT_ENSRAINBOW_URL = "https://api.ensrainbow.io";
|
|
9
|
+
var StatusCode = {
|
|
10
|
+
Success: "success",
|
|
11
|
+
Error: "error"
|
|
12
|
+
};
|
|
13
|
+
var ErrorCode = {
|
|
14
|
+
BadRequest: 400,
|
|
15
|
+
NotFound: 404,
|
|
16
|
+
ServerError: 500
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// src/client.ts
|
|
20
|
+
var EnsRainbowApiClient = class _EnsRainbowApiClient {
|
|
21
|
+
options;
|
|
22
|
+
cache;
|
|
23
|
+
labelSetSearchParams;
|
|
24
|
+
static DEFAULT_CACHE_CAPACITY = 1e3;
|
|
25
|
+
/**
|
|
26
|
+
* Create default client options.
|
|
27
|
+
*
|
|
28
|
+
* @returns default options
|
|
29
|
+
*/
|
|
30
|
+
static defaultOptions() {
|
|
31
|
+
return {
|
|
32
|
+
endpointUrl: new URL(DEFAULT_ENSRAINBOW_URL),
|
|
33
|
+
cacheCapacity: _EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY,
|
|
34
|
+
labelSet: buildEnsRainbowClientLabelSet()
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
const { labelSet: optionsLabelSet, ...rest } = options;
|
|
39
|
+
const defaultOptions = _EnsRainbowApiClient.defaultOptions();
|
|
40
|
+
const copiedLabelSet = buildEnsRainbowClientLabelSet(
|
|
41
|
+
optionsLabelSet?.labelSetId,
|
|
42
|
+
optionsLabelSet?.labelSetVersion
|
|
43
|
+
);
|
|
44
|
+
this.options = {
|
|
45
|
+
...defaultOptions,
|
|
46
|
+
...rest,
|
|
47
|
+
labelSet: copiedLabelSet
|
|
48
|
+
};
|
|
49
|
+
this.cache = new LruCache(
|
|
50
|
+
this.options.cacheCapacity
|
|
51
|
+
);
|
|
52
|
+
this.labelSetSearchParams = new URLSearchParams();
|
|
53
|
+
if (this.options.labelSet?.labelSetId !== void 0) {
|
|
54
|
+
this.labelSetSearchParams.append("label_set_id", this.options.labelSet.labelSetId);
|
|
55
|
+
}
|
|
56
|
+
if (this.options.labelSet?.labelSetVersion !== void 0) {
|
|
57
|
+
this.labelSetSearchParams.append(
|
|
58
|
+
"label_set_version",
|
|
59
|
+
this.options.labelSet.labelSetVersion.toString()
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Attempt to heal a labelHash to its original label.
|
|
65
|
+
*
|
|
66
|
+
* Note on returned labels: ENSRainbow returns labels exactly as they are
|
|
67
|
+
* represented in source rainbow table data. This means:
|
|
68
|
+
*
|
|
69
|
+
* - Labels may or may not be ENS-normalized
|
|
70
|
+
* - Labels can contain any valid string, including dots, null bytes, or be empty
|
|
71
|
+
* - Clients should handle all possible string values appropriately
|
|
72
|
+
*
|
|
73
|
+
* @param labelHash all lowercase 64-digit hex string with 0x prefix (total length of 66 characters)
|
|
74
|
+
* @returns a `HealResponse` indicating the result of the request and the healed label if successful
|
|
75
|
+
* @throws if the request fails due to network failures, DNS lookup failures, request timeouts,
|
|
76
|
+
* CORS violations, or Invalid URLs
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const response = await client.heal(
|
|
80
|
+
* "0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc"
|
|
81
|
+
* );
|
|
82
|
+
*
|
|
83
|
+
* console.log(response);
|
|
84
|
+
*
|
|
85
|
+
* // Output:
|
|
86
|
+
* // {
|
|
87
|
+
* // status: "success",
|
|
88
|
+
* // label: "vitalik"
|
|
89
|
+
* // }
|
|
90
|
+
*
|
|
91
|
+
* const notFoundResponse = await client.heal(
|
|
92
|
+
* "0xf64dc17ae2e2b9b16dbcb8cb05f35a2e6080a5ff1dc53ac0bc48f0e79111f264"
|
|
93
|
+
* );
|
|
94
|
+
*
|
|
95
|
+
* console.log(notFoundResponse);
|
|
96
|
+
*
|
|
97
|
+
* // Output:
|
|
98
|
+
* // {
|
|
99
|
+
* // status: "error",
|
|
100
|
+
* // error: "Label not found",
|
|
101
|
+
* // errorCode: 404
|
|
102
|
+
* // }
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
async heal(labelHash) {
|
|
106
|
+
const cachedResult = this.cache.get(labelHash);
|
|
107
|
+
if (cachedResult) return cachedResult;
|
|
108
|
+
const url = new URL(`/v1/heal/${labelHash}`, this.options.endpointUrl);
|
|
109
|
+
this.labelSetSearchParams.forEach((value, key) => {
|
|
110
|
+
url.searchParams.append(key, value);
|
|
111
|
+
});
|
|
112
|
+
const response = await fetch(url);
|
|
113
|
+
const healResponse = await response.json();
|
|
114
|
+
if (isCacheableHealResponse(healResponse)) {
|
|
115
|
+
this.cache.set(labelHash, healResponse);
|
|
116
|
+
}
|
|
117
|
+
return healResponse;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get Count of Healable Labels
|
|
121
|
+
*
|
|
122
|
+
* @returns a `CountResponse` indicating the result and the timestamp of the request and the
|
|
123
|
+
* number of healable labels if successful
|
|
124
|
+
* @throws if the request fails due to network failures, DNS lookup failures, request timeouts,
|
|
125
|
+
* CORS violations, or Invalid URLs
|
|
126
|
+
* @example
|
|
127
|
+
*
|
|
128
|
+
* const response = await client.count();
|
|
129
|
+
*
|
|
130
|
+
* console.log(response);
|
|
131
|
+
*
|
|
132
|
+
* // {
|
|
133
|
+
* // "status": "success",
|
|
134
|
+
* // "count": 133856894,
|
|
135
|
+
* // "timestamp": "2024-01-30T11:18:56Z"
|
|
136
|
+
* // }
|
|
137
|
+
*
|
|
138
|
+
*/
|
|
139
|
+
async count() {
|
|
140
|
+
const response = await fetch(new URL("/v1/labels/count", this.options.endpointUrl));
|
|
141
|
+
return response.json();
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
*
|
|
145
|
+
* Simple verification that the service is running, either in your local setup or for the
|
|
146
|
+
* provided hosted instance.
|
|
147
|
+
* @returns a status of ENS Rainbow service
|
|
148
|
+
* @example
|
|
149
|
+
*
|
|
150
|
+
* const response = await client.health();
|
|
151
|
+
*
|
|
152
|
+
* console.log(response);
|
|
153
|
+
*
|
|
154
|
+
* // {
|
|
155
|
+
* // "status": "ok",
|
|
156
|
+
* // }
|
|
157
|
+
*/
|
|
158
|
+
async health() {
|
|
159
|
+
const response = await fetch(new URL("/health", this.options.endpointUrl));
|
|
160
|
+
return response.json();
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get the version information of the ENSRainbow service
|
|
164
|
+
*
|
|
165
|
+
* @returns the version information of the ENSRainbow service
|
|
166
|
+
* @throws if the request fails due to network failures, DNS lookup failures, request
|
|
167
|
+
* timeouts, CORS violations, or invalid URLs
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* const response = await client.version();
|
|
171
|
+
*
|
|
172
|
+
* console.log(response);
|
|
173
|
+
*
|
|
174
|
+
* // {
|
|
175
|
+
* // "status": "success",
|
|
176
|
+
* // "versionInfo": {
|
|
177
|
+
* // "version": "0.1.0",
|
|
178
|
+
* // "dbSchemaVersion": 2,
|
|
179
|
+
* // "labelSet": {
|
|
180
|
+
* // "labelSetId": "subgraph",
|
|
181
|
+
* // "labelSetVersion": 0
|
|
182
|
+
* // }
|
|
183
|
+
* // }
|
|
184
|
+
* // }
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
async version() {
|
|
188
|
+
const response = await fetch(new URL("/v1/version", this.options.endpointUrl));
|
|
189
|
+
return response.json();
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get a copy of the current client options.
|
|
193
|
+
*
|
|
194
|
+
* @returns a copy of the current client options.
|
|
195
|
+
*/
|
|
196
|
+
getOptions() {
|
|
197
|
+
const deepCopy = {
|
|
198
|
+
cacheCapacity: this.options.cacheCapacity,
|
|
199
|
+
endpointUrl: new URL(this.options.endpointUrl.href),
|
|
200
|
+
labelSet: this.options.labelSet ? { ...this.options.labelSet } : void 0
|
|
201
|
+
};
|
|
202
|
+
return Object.freeze(deepCopy);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
var isHealError = (response) => {
|
|
206
|
+
return response.status === StatusCode.Error;
|
|
207
|
+
};
|
|
208
|
+
var isCacheableHealResponse = (response) => {
|
|
209
|
+
return response.status === StatusCode.Success || response.errorCode !== ErrorCode.ServerError;
|
|
210
|
+
};
|
|
211
|
+
export {
|
|
212
|
+
EnsRainbowApiClient,
|
|
213
|
+
isCacheableHealResponse,
|
|
214
|
+
isHealError
|
|
215
|
+
};
|
|
216
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/consts.ts"],"sourcesContent":["import {\n buildEnsRainbowClientLabelSet,\n type Cache,\n type EnsRainbowClientLabelSet,\n type EnsRainbowServerLabelSet,\n type Label,\n type LabelHash,\n LruCache,\n} from \"@ensnode/ensnode-sdk\";\n\nimport { DEFAULT_ENSRAINBOW_URL, ErrorCode, StatusCode } from \"./consts\";\n\nexport namespace EnsRainbow {\n export type ApiClientOptions = EnsRainbowApiClientOptions;\n\n export interface ApiClient {\n count(): Promise<CountResponse>;\n\n /**\n * Heal a labelhash to its original label\n * @param labelHash The labelhash to heal\n */\n heal(labelHash: LabelHash): Promise<HealResponse>;\n\n health(): Promise<HealthResponse>;\n\n version(): Promise<VersionResponse>;\n\n getOptions(): Readonly<EnsRainbowApiClientOptions>;\n }\n\n type StatusCode = (typeof StatusCode)[keyof typeof StatusCode];\n\n type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n export interface HealthResponse {\n status: \"ok\";\n }\n\n export interface BaseHealResponse<Status extends StatusCode, Error extends ErrorCode> {\n status: Status;\n label?: Label | never;\n error?: string | never;\n errorCode?: Error | never;\n }\n\n export interface HealSuccess extends BaseHealResponse<typeof StatusCode.Success, never> {\n status: typeof StatusCode.Success;\n label: Label;\n error?: never;\n errorCode?: never;\n }\n\n export interface HealNotFoundError\n extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.NotFound> {\n status: typeof StatusCode.Error;\n label?: never;\n error: string;\n errorCode: typeof ErrorCode.NotFound;\n }\n\n export interface HealServerError\n extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.ServerError> {\n status: typeof StatusCode.Error;\n label?: never;\n error: string;\n errorCode: typeof ErrorCode.ServerError;\n }\n\n export interface HealBadRequestError\n extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.BadRequest> {\n status: typeof StatusCode.Error;\n label?: never;\n error: string;\n errorCode: typeof ErrorCode.BadRequest;\n }\n\n export type HealResponse =\n | HealSuccess\n | HealNotFoundError\n | HealServerError\n | HealBadRequestError;\n export type HealError = Exclude<HealResponse, HealSuccess>;\n\n /**\n * Server errors should not be cached.\n */\n export type CacheableHealResponse = Exclude<HealResponse, HealServerError>;\n\n export interface BaseCountResponse<Status extends StatusCode, Error extends ErrorCode> {\n status: Status;\n count?: number | never;\n timestamp?: string | never;\n error?: string | never;\n errorCode?: Error | never;\n }\n\n export interface CountSuccess extends BaseCountResponse<typeof StatusCode.Success, never> {\n status: typeof StatusCode.Success;\n /** The total count of labels that can be healed by the ENSRainbow instance. Always a\n * non-negative integer. */\n count: number;\n timestamp: string;\n error?: never;\n errorCode?: never;\n }\n\n export interface CountServerError\n extends BaseCountResponse<typeof StatusCode.Error, typeof ErrorCode.ServerError> {\n status: typeof StatusCode.Error;\n count?: never;\n timestamp?: never;\n error: string;\n errorCode: typeof ErrorCode.ServerError;\n }\n\n export type CountResponse = CountSuccess | CountServerError;\n\n /**\n * ENSRainbow version information.\n */\n export interface VersionInfo {\n /**\n * ENSRainbow version.\n */\n version: string;\n\n /**\n * ENSRainbow database schema version.\n */\n dbSchemaVersion: number;\n\n /**\n * The EnsRainbowServerLabelSet managed by the ENSRainbow server.\n */\n labelSet: EnsRainbowServerLabelSet;\n }\n\n /**\n * Interface for the version endpoint response\n */\n export interface VersionResponse {\n status: typeof StatusCode.Success;\n versionInfo: VersionInfo;\n }\n}\n\nexport interface EnsRainbowApiClientOptions {\n /**\n * The maximum number of `HealResponse` values to cache.\n * Must be a non-negative integer.\n * Setting to 0 will disable caching.\n */\n cacheCapacity: number;\n\n /**\n * The URL of an ENSRainbow API endpoint.\n */\n endpointUrl: URL;\n\n /**\n * Optional label set preferences that the ENSRainbow server at endpointUrl is expected to\n * support. If provided, enables deterministic heal results across time, such that only\n * labels from label sets with versions less than or equal to this value will be returned.\n * Therefore, even if the ENSRainbow server later ingests label sets with greater versions\n * than this value, the results returned across time can be deterministic. If\n * provided, heal operations with this EnsRainbowApiClient will validate the ENSRainbow\n * server manages a compatible label set. If not provided no specific labelSetId validation\n * will be performed during heal operations.\n * If `labelSetId` is provided without `labelSetVersion`, the server will use the latest\n * available version.\n * If `labelSetVersion` is defined, only labels from sets less than or equal to this value\n * will be returned.\n * When `labelSetVersion` is defined, `labelSetId` must also be defined.\n */\n labelSet?: EnsRainbowClientLabelSet;\n}\n\n/**\n * ENSRainbow API client\n *\n * @example\n * ```typescript\n * // default options\n * const client = new EnsRainbowApiClient();\n * // custom options\n * const client = new EnsRainbowApiClient({\n * endpointUrl: new URL(\"https://api.ensrainbow.io\"),\n * });\n * ```\n */\nexport class EnsRainbowApiClient implements EnsRainbow.ApiClient {\n private readonly options: EnsRainbowApiClientOptions;\n private readonly cache: Cache<LabelHash, EnsRainbow.CacheableHealResponse>;\n private readonly labelSetSearchParams: URLSearchParams;\n\n public static readonly DEFAULT_CACHE_CAPACITY = 1000;\n\n /**\n * Create default client options.\n *\n * @returns default options\n */\n static defaultOptions(): EnsRainbow.ApiClientOptions {\n return {\n endpointUrl: new URL(DEFAULT_ENSRAINBOW_URL),\n cacheCapacity: EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY,\n labelSet: buildEnsRainbowClientLabelSet(),\n };\n }\n\n constructor(options: Partial<EnsRainbow.ApiClientOptions> = {}) {\n const { labelSet: optionsLabelSet, ...rest } = options;\n const defaultOptions = EnsRainbowApiClient.defaultOptions();\n\n const copiedLabelSet = buildEnsRainbowClientLabelSet(\n optionsLabelSet?.labelSetId,\n optionsLabelSet?.labelSetVersion,\n );\n\n this.options = {\n ...defaultOptions,\n ...rest,\n labelSet: copiedLabelSet,\n };\n\n this.cache = new LruCache<LabelHash, EnsRainbow.CacheableHealResponse>(\n this.options.cacheCapacity,\n );\n\n // Pre-compute query parameters for label set options\n this.labelSetSearchParams = new URLSearchParams();\n if (this.options.labelSet?.labelSetId !== undefined) {\n this.labelSetSearchParams.append(\"label_set_id\", this.options.labelSet.labelSetId);\n }\n if (this.options.labelSet?.labelSetVersion !== undefined) {\n this.labelSetSearchParams.append(\n \"label_set_version\",\n this.options.labelSet.labelSetVersion.toString(),\n );\n }\n }\n\n /**\n * Attempt to heal a labelHash to its original label.\n *\n * Note on returned labels: ENSRainbow returns labels exactly as they are\n * represented in source rainbow table data. This means:\n *\n * - Labels may or may not be ENS-normalized\n * - Labels can contain any valid string, including dots, null bytes, or be empty\n * - Clients should handle all possible string values appropriately\n *\n * @param labelHash all lowercase 64-digit hex string with 0x prefix (total length of 66 characters)\n * @returns a `HealResponse` indicating the result of the request and the healed label if successful\n * @throws if the request fails due to network failures, DNS lookup failures, request timeouts,\n * CORS violations, or Invalid URLs\n * @example\n * ```typescript\n * const response = await client.heal(\n * \"0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc\"\n * );\n *\n * console.log(response);\n *\n * // Output:\n * // {\n * // status: \"success\",\n * // label: \"vitalik\"\n * // }\n *\n * const notFoundResponse = await client.heal(\n * \"0xf64dc17ae2e2b9b16dbcb8cb05f35a2e6080a5ff1dc53ac0bc48f0e79111f264\"\n * );\n *\n * console.log(notFoundResponse);\n *\n * // Output:\n * // {\n * // status: \"error\",\n * // error: \"Label not found\",\n * // errorCode: 404\n * // }\n * ```\n */\n async heal(labelHash: LabelHash): Promise<EnsRainbow.HealResponse> {\n const cachedResult = this.cache.get(labelHash);\n if (cachedResult) return cachedResult;\n\n const url = new URL(`/v1/heal/${labelHash}`, this.options.endpointUrl);\n\n // Apply pre-computed label set query parameters\n this.labelSetSearchParams.forEach((value, key) => {\n url.searchParams.append(key, value);\n });\n\n const response = await fetch(url);\n const healResponse = (await response.json()) as EnsRainbow.HealResponse;\n\n if (isCacheableHealResponse(healResponse)) {\n this.cache.set(labelHash, healResponse);\n }\n\n return healResponse;\n }\n\n /**\n * Get Count of Healable Labels\n *\n * @returns a `CountResponse` indicating the result and the timestamp of the request and the\n * number of healable labels if successful\n * @throws if the request fails due to network failures, DNS lookup failures, request timeouts,\n * CORS violations, or Invalid URLs\n * @example\n *\n * const response = await client.count();\n *\n * console.log(response);\n *\n * // {\n * // \"status\": \"success\",\n * // \"count\": 133856894,\n * // \"timestamp\": \"2024-01-30T11:18:56Z\"\n * // }\n *\n */\n async count(): Promise<EnsRainbow.CountResponse> {\n const response = await fetch(new URL(\"/v1/labels/count\", this.options.endpointUrl));\n\n return response.json() as Promise<EnsRainbow.CountResponse>;\n }\n\n /**\n *\n * Simple verification that the service is running, either in your local setup or for the\n * provided hosted instance.\n * @returns a status of ENS Rainbow service\n * @example\n *\n * const response = await client.health();\n *\n * console.log(response);\n *\n * // {\n * // \"status\": \"ok\",\n * // }\n */\n async health(): Promise<EnsRainbow.HealthResponse> {\n const response = await fetch(new URL(\"/health\", this.options.endpointUrl));\n\n return response.json() as Promise<EnsRainbow.HealthResponse>;\n }\n\n /**\n * Get the version information of the ENSRainbow service\n *\n * @returns the version information of the ENSRainbow service\n * @throws if the request fails due to network failures, DNS lookup failures, request\n * timeouts, CORS violations, or invalid URLs\n * @example\n * ```typescript\n * const response = await client.version();\n *\n * console.log(response);\n *\n * // {\n * // \"status\": \"success\",\n * // \"versionInfo\": {\n * // \"version\": \"0.1.0\",\n * // \"dbSchemaVersion\": 2,\n * // \"labelSet\": {\n * // \"labelSetId\": \"subgraph\",\n * // \"labelSetVersion\": 0\n * // }\n * // }\n * // }\n * ```\n */\n async version(): Promise<EnsRainbow.VersionResponse> {\n const response = await fetch(new URL(\"/v1/version\", this.options.endpointUrl));\n\n return response.json() as Promise<EnsRainbow.VersionResponse>;\n }\n\n /**\n * Get a copy of the current client options.\n *\n * @returns a copy of the current client options.\n */\n getOptions(): Readonly<EnsRainbowApiClientOptions> {\n // build a deep copy to prevent modification\n const deepCopy = {\n cacheCapacity: this.options.cacheCapacity,\n endpointUrl: new URL(this.options.endpointUrl.href),\n labelSet: this.options.labelSet ? { ...this.options.labelSet } : undefined,\n } satisfies EnsRainbowApiClientOptions;\n\n return Object.freeze(deepCopy);\n }\n}\n\n/**\n * Determine if a heal response is an error.\n *\n * @param response the heal response to check\n * @returns true if the response is an error, false otherwise\n */\nexport const isHealError = (\n response: EnsRainbow.HealResponse,\n): response is EnsRainbow.HealError => {\n return response.status === StatusCode.Error;\n};\n\n/**\n * Determine if a heal response is cacheable.\n *\n * Server errors at not cachable and should be retried.\n *\n * @param response the heal response to check\n * @returns true if the response is cacheable, false otherwise\n */\nexport const isCacheableHealResponse = (\n response: EnsRainbow.HealResponse,\n): response is EnsRainbow.CacheableHealResponse => {\n return response.status === StatusCode.Success || response.errorCode !== ErrorCode.ServerError;\n};\n","export const DEFAULT_ENSRAINBOW_URL = \"https://api.ensrainbow.io\" as const;\n\nexport const StatusCode = {\n Success: \"success\",\n Error: \"error\",\n} as const;\n\nexport const ErrorCode = {\n BadRequest: 400,\n NotFound: 404,\n ServerError: 500,\n} as const;\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EAMA;AAAA,OACK;;;ACRA,IAAM,yBAAyB;AAE/B,IAAM,aAAa;AAAA,EACxB,SAAS;AAAA,EACT,OAAO;AACT;AAEO,IAAM,YAAY;AAAA,EACvB,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,aAAa;AACf;;;ADoLO,IAAM,sBAAN,MAAM,qBAAoD;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,OAAuB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhD,OAAO,iBAA8C;AACnD,WAAO;AAAA,MACL,aAAa,IAAI,IAAI,sBAAsB;AAAA,MAC3C,eAAe,qBAAoB;AAAA,MACnC,UAAU,8BAA8B;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,YAAY,UAAgD,CAAC,GAAG;AAC9D,UAAM,EAAE,UAAU,iBAAiB,GAAG,KAAK,IAAI;AAC/C,UAAM,iBAAiB,qBAAoB,eAAe;AAE1D,UAAM,iBAAiB;AAAA,MACrB,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,IACnB;AAEA,SAAK,UAAU;AAAA,MACb,GAAG;AAAA,MACH,GAAG;AAAA,MACH,UAAU;AAAA,IACZ;AAEA,SAAK,QAAQ,IAAI;AAAA,MACf,KAAK,QAAQ;AAAA,IACf;AAGA,SAAK,uBAAuB,IAAI,gBAAgB;AAChD,QAAI,KAAK,QAAQ,UAAU,eAAe,QAAW;AACnD,WAAK,qBAAqB,OAAO,gBAAgB,KAAK,QAAQ,SAAS,UAAU;AAAA,IACnF;AACA,QAAI,KAAK,QAAQ,UAAU,oBAAoB,QAAW;AACxD,WAAK,qBAAqB;AAAA,QACxB;AAAA,QACA,KAAK,QAAQ,SAAS,gBAAgB,SAAS;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4CA,MAAM,KAAK,WAAwD;AACjE,UAAM,eAAe,KAAK,MAAM,IAAI,SAAS;AAC7C,QAAI,aAAc,QAAO;AAEzB,UAAM,MAAM,IAAI,IAAI,YAAY,SAAS,IAAI,KAAK,QAAQ,WAAW;AAGrE,SAAK,qBAAqB,QAAQ,CAAC,OAAO,QAAQ;AAChD,UAAI,aAAa,OAAO,KAAK,KAAK;AAAA,IACpC,CAAC;AAED,UAAM,WAAW,MAAM,MAAM,GAAG;AAChC,UAAM,eAAgB,MAAM,SAAS,KAAK;AAE1C,QAAI,wBAAwB,YAAY,GAAG;AACzC,WAAK,MAAM,IAAI,WAAW,YAAY;AAAA,IACxC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,MAAM,QAA2C;AAC/C,UAAM,WAAW,MAAM,MAAM,IAAI,IAAI,oBAAoB,KAAK,QAAQ,WAAW,CAAC;AAElF,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,SAA6C;AACjD,UAAM,WAAW,MAAM,MAAM,IAAI,IAAI,WAAW,KAAK,QAAQ,WAAW,CAAC;AAEzE,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2BA,MAAM,UAA+C;AACnD,UAAM,WAAW,MAAM,MAAM,IAAI,IAAI,eAAe,KAAK,QAAQ,WAAW,CAAC;AAE7E,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAmD;AAEjD,UAAM,WAAW;AAAA,MACf,eAAe,KAAK,QAAQ;AAAA,MAC5B,aAAa,IAAI,IAAI,KAAK,QAAQ,YAAY,IAAI;AAAA,MAClD,UAAU,KAAK,QAAQ,WAAW,EAAE,GAAG,KAAK,QAAQ,SAAS,IAAI;AAAA,IACnE;AAEA,WAAO,OAAO,OAAO,QAAQ;AAAA,EAC/B;AACF;AAQO,IAAM,cAAc,CACzB,aACqC;AACrC,SAAO,SAAS,WAAW,WAAW;AACxC;AAUO,IAAM,0BAA0B,CACrC,aACiD;AACjD,SAAO,SAAS,WAAW,WAAW,WAAW,SAAS,cAAc,UAAU;AACpF;","names":[]}
|
package/dist/consts.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const DEFAULT_ENSRAINBOW_URL: "https://api.ensrainbow.io";
|
|
2
|
+
declare const StatusCode: {
|
|
3
|
+
readonly Success: "success";
|
|
4
|
+
readonly Error: "error";
|
|
5
|
+
};
|
|
6
|
+
declare const ErrorCode: {
|
|
7
|
+
readonly BadRequest: 400;
|
|
8
|
+
readonly NotFound: 404;
|
|
9
|
+
readonly ServerError: 500;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { DEFAULT_ENSRAINBOW_URL, ErrorCode, StatusCode };
|
package/dist/consts.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/consts.ts
|
|
2
|
+
var DEFAULT_ENSRAINBOW_URL = "https://api.ensrainbow.io";
|
|
3
|
+
var StatusCode = {
|
|
4
|
+
Success: "success",
|
|
5
|
+
Error: "error"
|
|
6
|
+
};
|
|
7
|
+
var ErrorCode = {
|
|
8
|
+
BadRequest: 400,
|
|
9
|
+
NotFound: 404,
|
|
10
|
+
ServerError: 500
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
DEFAULT_ENSRAINBOW_URL,
|
|
14
|
+
ErrorCode,
|
|
15
|
+
StatusCode
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=consts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/consts.ts"],"sourcesContent":["export const DEFAULT_ENSRAINBOW_URL = \"https://api.ensrainbow.io\" as const;\n\nexport const StatusCode = {\n Success: \"success\",\n Error: \"error\",\n} as const;\n\nexport const ErrorCode = {\n BadRequest: 400,\n NotFound: 404,\n ServerError: 500,\n} as const;\n"],"mappings":";AAAO,IAAM,yBAAyB;AAE/B,IAAM,aAAa;AAAA,EACxB,SAAS;AAAA,EACT,OAAO;AACT;AAEO,IAAM,YAAY;AAAA,EACvB,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,aAAa;AACf;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { EnsRainbowClientLabelSet, EnsRainbowServerLabelSet, LabelSetId, LabelSetVersion, buildEnsRainbowClientLabelSet } from '@ensnode/ensnode-sdk';
|
|
2
|
+
export { EnsRainbow, EnsRainbowApiClient, EnsRainbowApiClientOptions, isCacheableHealResponse, isHealError } from './client.js';
|
|
3
|
+
export { DEFAULT_ENSRAINBOW_URL, ErrorCode, StatusCode } from './consts.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { buildEnsRainbowClientLabelSet as buildEnsRainbowClientLabelSet2 } from "@ensnode/ensnode-sdk";
|
|
3
|
+
|
|
4
|
+
// src/client.ts
|
|
5
|
+
import {
|
|
6
|
+
buildEnsRainbowClientLabelSet,
|
|
7
|
+
LruCache
|
|
8
|
+
} from "@ensnode/ensnode-sdk";
|
|
9
|
+
|
|
10
|
+
// src/consts.ts
|
|
11
|
+
var DEFAULT_ENSRAINBOW_URL = "https://api.ensrainbow.io";
|
|
12
|
+
var StatusCode = {
|
|
13
|
+
Success: "success",
|
|
14
|
+
Error: "error"
|
|
15
|
+
};
|
|
16
|
+
var ErrorCode = {
|
|
17
|
+
BadRequest: 400,
|
|
18
|
+
NotFound: 404,
|
|
19
|
+
ServerError: 500
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// src/client.ts
|
|
23
|
+
var EnsRainbowApiClient = class _EnsRainbowApiClient {
|
|
24
|
+
options;
|
|
25
|
+
cache;
|
|
26
|
+
labelSetSearchParams;
|
|
27
|
+
static DEFAULT_CACHE_CAPACITY = 1e3;
|
|
28
|
+
/**
|
|
29
|
+
* Create default client options.
|
|
30
|
+
*
|
|
31
|
+
* @returns default options
|
|
32
|
+
*/
|
|
33
|
+
static defaultOptions() {
|
|
34
|
+
return {
|
|
35
|
+
endpointUrl: new URL(DEFAULT_ENSRAINBOW_URL),
|
|
36
|
+
cacheCapacity: _EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY,
|
|
37
|
+
labelSet: buildEnsRainbowClientLabelSet()
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
constructor(options = {}) {
|
|
41
|
+
const { labelSet: optionsLabelSet, ...rest } = options;
|
|
42
|
+
const defaultOptions = _EnsRainbowApiClient.defaultOptions();
|
|
43
|
+
const copiedLabelSet = buildEnsRainbowClientLabelSet(
|
|
44
|
+
optionsLabelSet?.labelSetId,
|
|
45
|
+
optionsLabelSet?.labelSetVersion
|
|
46
|
+
);
|
|
47
|
+
this.options = {
|
|
48
|
+
...defaultOptions,
|
|
49
|
+
...rest,
|
|
50
|
+
labelSet: copiedLabelSet
|
|
51
|
+
};
|
|
52
|
+
this.cache = new LruCache(
|
|
53
|
+
this.options.cacheCapacity
|
|
54
|
+
);
|
|
55
|
+
this.labelSetSearchParams = new URLSearchParams();
|
|
56
|
+
if (this.options.labelSet?.labelSetId !== void 0) {
|
|
57
|
+
this.labelSetSearchParams.append("label_set_id", this.options.labelSet.labelSetId);
|
|
58
|
+
}
|
|
59
|
+
if (this.options.labelSet?.labelSetVersion !== void 0) {
|
|
60
|
+
this.labelSetSearchParams.append(
|
|
61
|
+
"label_set_version",
|
|
62
|
+
this.options.labelSet.labelSetVersion.toString()
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Attempt to heal a labelHash to its original label.
|
|
68
|
+
*
|
|
69
|
+
* Note on returned labels: ENSRainbow returns labels exactly as they are
|
|
70
|
+
* represented in source rainbow table data. This means:
|
|
71
|
+
*
|
|
72
|
+
* - Labels may or may not be ENS-normalized
|
|
73
|
+
* - Labels can contain any valid string, including dots, null bytes, or be empty
|
|
74
|
+
* - Clients should handle all possible string values appropriately
|
|
75
|
+
*
|
|
76
|
+
* @param labelHash all lowercase 64-digit hex string with 0x prefix (total length of 66 characters)
|
|
77
|
+
* @returns a `HealResponse` indicating the result of the request and the healed label if successful
|
|
78
|
+
* @throws if the request fails due to network failures, DNS lookup failures, request timeouts,
|
|
79
|
+
* CORS violations, or Invalid URLs
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const response = await client.heal(
|
|
83
|
+
* "0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc"
|
|
84
|
+
* );
|
|
85
|
+
*
|
|
86
|
+
* console.log(response);
|
|
87
|
+
*
|
|
88
|
+
* // Output:
|
|
89
|
+
* // {
|
|
90
|
+
* // status: "success",
|
|
91
|
+
* // label: "vitalik"
|
|
92
|
+
* // }
|
|
93
|
+
*
|
|
94
|
+
* const notFoundResponse = await client.heal(
|
|
95
|
+
* "0xf64dc17ae2e2b9b16dbcb8cb05f35a2e6080a5ff1dc53ac0bc48f0e79111f264"
|
|
96
|
+
* );
|
|
97
|
+
*
|
|
98
|
+
* console.log(notFoundResponse);
|
|
99
|
+
*
|
|
100
|
+
* // Output:
|
|
101
|
+
* // {
|
|
102
|
+
* // status: "error",
|
|
103
|
+
* // error: "Label not found",
|
|
104
|
+
* // errorCode: 404
|
|
105
|
+
* // }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
async heal(labelHash) {
|
|
109
|
+
const cachedResult = this.cache.get(labelHash);
|
|
110
|
+
if (cachedResult) return cachedResult;
|
|
111
|
+
const url = new URL(`/v1/heal/${labelHash}`, this.options.endpointUrl);
|
|
112
|
+
this.labelSetSearchParams.forEach((value, key) => {
|
|
113
|
+
url.searchParams.append(key, value);
|
|
114
|
+
});
|
|
115
|
+
const response = await fetch(url);
|
|
116
|
+
const healResponse = await response.json();
|
|
117
|
+
if (isCacheableHealResponse(healResponse)) {
|
|
118
|
+
this.cache.set(labelHash, healResponse);
|
|
119
|
+
}
|
|
120
|
+
return healResponse;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get Count of Healable Labels
|
|
124
|
+
*
|
|
125
|
+
* @returns a `CountResponse` indicating the result and the timestamp of the request and the
|
|
126
|
+
* number of healable labels if successful
|
|
127
|
+
* @throws if the request fails due to network failures, DNS lookup failures, request timeouts,
|
|
128
|
+
* CORS violations, or Invalid URLs
|
|
129
|
+
* @example
|
|
130
|
+
*
|
|
131
|
+
* const response = await client.count();
|
|
132
|
+
*
|
|
133
|
+
* console.log(response);
|
|
134
|
+
*
|
|
135
|
+
* // {
|
|
136
|
+
* // "status": "success",
|
|
137
|
+
* // "count": 133856894,
|
|
138
|
+
* // "timestamp": "2024-01-30T11:18:56Z"
|
|
139
|
+
* // }
|
|
140
|
+
*
|
|
141
|
+
*/
|
|
142
|
+
async count() {
|
|
143
|
+
const response = await fetch(new URL("/v1/labels/count", this.options.endpointUrl));
|
|
144
|
+
return response.json();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
*
|
|
148
|
+
* Simple verification that the service is running, either in your local setup or for the
|
|
149
|
+
* provided hosted instance.
|
|
150
|
+
* @returns a status of ENS Rainbow service
|
|
151
|
+
* @example
|
|
152
|
+
*
|
|
153
|
+
* const response = await client.health();
|
|
154
|
+
*
|
|
155
|
+
* console.log(response);
|
|
156
|
+
*
|
|
157
|
+
* // {
|
|
158
|
+
* // "status": "ok",
|
|
159
|
+
* // }
|
|
160
|
+
*/
|
|
161
|
+
async health() {
|
|
162
|
+
const response = await fetch(new URL("/health", this.options.endpointUrl));
|
|
163
|
+
return response.json();
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get the version information of the ENSRainbow service
|
|
167
|
+
*
|
|
168
|
+
* @returns the version information of the ENSRainbow service
|
|
169
|
+
* @throws if the request fails due to network failures, DNS lookup failures, request
|
|
170
|
+
* timeouts, CORS violations, or invalid URLs
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const response = await client.version();
|
|
174
|
+
*
|
|
175
|
+
* console.log(response);
|
|
176
|
+
*
|
|
177
|
+
* // {
|
|
178
|
+
* // "status": "success",
|
|
179
|
+
* // "versionInfo": {
|
|
180
|
+
* // "version": "0.1.0",
|
|
181
|
+
* // "dbSchemaVersion": 2,
|
|
182
|
+
* // "labelSet": {
|
|
183
|
+
* // "labelSetId": "subgraph",
|
|
184
|
+
* // "labelSetVersion": 0
|
|
185
|
+
* // }
|
|
186
|
+
* // }
|
|
187
|
+
* // }
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
async version() {
|
|
191
|
+
const response = await fetch(new URL("/v1/version", this.options.endpointUrl));
|
|
192
|
+
return response.json();
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get a copy of the current client options.
|
|
196
|
+
*
|
|
197
|
+
* @returns a copy of the current client options.
|
|
198
|
+
*/
|
|
199
|
+
getOptions() {
|
|
200
|
+
const deepCopy = {
|
|
201
|
+
cacheCapacity: this.options.cacheCapacity,
|
|
202
|
+
endpointUrl: new URL(this.options.endpointUrl.href),
|
|
203
|
+
labelSet: this.options.labelSet ? { ...this.options.labelSet } : void 0
|
|
204
|
+
};
|
|
205
|
+
return Object.freeze(deepCopy);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
var isHealError = (response) => {
|
|
209
|
+
return response.status === StatusCode.Error;
|
|
210
|
+
};
|
|
211
|
+
var isCacheableHealResponse = (response) => {
|
|
212
|
+
return response.status === StatusCode.Success || response.errorCode !== ErrorCode.ServerError;
|
|
213
|
+
};
|
|
214
|
+
export {
|
|
215
|
+
DEFAULT_ENSRAINBOW_URL,
|
|
216
|
+
EnsRainbowApiClient,
|
|
217
|
+
ErrorCode,
|
|
218
|
+
StatusCode,
|
|
219
|
+
buildEnsRainbowClientLabelSet2 as buildEnsRainbowClientLabelSet,
|
|
220
|
+
isCacheableHealResponse,
|
|
221
|
+
isHealError
|
|
222
|
+
};
|
|
223
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/consts.ts"],"sourcesContent":["// Re-export types from ensnode-sdk that are needed by consumers\nexport type {\n EnsRainbowClientLabelSet,\n EnsRainbowServerLabelSet,\n LabelSetId,\n LabelSetVersion,\n} from \"@ensnode/ensnode-sdk\";\n// Re-export utility functions and classes from ensnode-sdk that are needed by consumers\nexport { buildEnsRainbowClientLabelSet } from \"@ensnode/ensnode-sdk\";\n\nexport * from \"./client\";\nexport * from \"./consts\";\n","import {\n buildEnsRainbowClientLabelSet,\n type Cache,\n type EnsRainbowClientLabelSet,\n type EnsRainbowServerLabelSet,\n type Label,\n type LabelHash,\n LruCache,\n} from \"@ensnode/ensnode-sdk\";\n\nimport { DEFAULT_ENSRAINBOW_URL, ErrorCode, StatusCode } from \"./consts\";\n\nexport namespace EnsRainbow {\n export type ApiClientOptions = EnsRainbowApiClientOptions;\n\n export interface ApiClient {\n count(): Promise<CountResponse>;\n\n /**\n * Heal a labelhash to its original label\n * @param labelHash The labelhash to heal\n */\n heal(labelHash: LabelHash): Promise<HealResponse>;\n\n health(): Promise<HealthResponse>;\n\n version(): Promise<VersionResponse>;\n\n getOptions(): Readonly<EnsRainbowApiClientOptions>;\n }\n\n type StatusCode = (typeof StatusCode)[keyof typeof StatusCode];\n\n type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n export interface HealthResponse {\n status: \"ok\";\n }\n\n export interface BaseHealResponse<Status extends StatusCode, Error extends ErrorCode> {\n status: Status;\n label?: Label | never;\n error?: string | never;\n errorCode?: Error | never;\n }\n\n export interface HealSuccess extends BaseHealResponse<typeof StatusCode.Success, never> {\n status: typeof StatusCode.Success;\n label: Label;\n error?: never;\n errorCode?: never;\n }\n\n export interface HealNotFoundError\n extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.NotFound> {\n status: typeof StatusCode.Error;\n label?: never;\n error: string;\n errorCode: typeof ErrorCode.NotFound;\n }\n\n export interface HealServerError\n extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.ServerError> {\n status: typeof StatusCode.Error;\n label?: never;\n error: string;\n errorCode: typeof ErrorCode.ServerError;\n }\n\n export interface HealBadRequestError\n extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.BadRequest> {\n status: typeof StatusCode.Error;\n label?: never;\n error: string;\n errorCode: typeof ErrorCode.BadRequest;\n }\n\n export type HealResponse =\n | HealSuccess\n | HealNotFoundError\n | HealServerError\n | HealBadRequestError;\n export type HealError = Exclude<HealResponse, HealSuccess>;\n\n /**\n * Server errors should not be cached.\n */\n export type CacheableHealResponse = Exclude<HealResponse, HealServerError>;\n\n export interface BaseCountResponse<Status extends StatusCode, Error extends ErrorCode> {\n status: Status;\n count?: number | never;\n timestamp?: string | never;\n error?: string | never;\n errorCode?: Error | never;\n }\n\n export interface CountSuccess extends BaseCountResponse<typeof StatusCode.Success, never> {\n status: typeof StatusCode.Success;\n /** The total count of labels that can be healed by the ENSRainbow instance. Always a\n * non-negative integer. */\n count: number;\n timestamp: string;\n error?: never;\n errorCode?: never;\n }\n\n export interface CountServerError\n extends BaseCountResponse<typeof StatusCode.Error, typeof ErrorCode.ServerError> {\n status: typeof StatusCode.Error;\n count?: never;\n timestamp?: never;\n error: string;\n errorCode: typeof ErrorCode.ServerError;\n }\n\n export type CountResponse = CountSuccess | CountServerError;\n\n /**\n * ENSRainbow version information.\n */\n export interface VersionInfo {\n /**\n * ENSRainbow version.\n */\n version: string;\n\n /**\n * ENSRainbow database schema version.\n */\n dbSchemaVersion: number;\n\n /**\n * The EnsRainbowServerLabelSet managed by the ENSRainbow server.\n */\n labelSet: EnsRainbowServerLabelSet;\n }\n\n /**\n * Interface for the version endpoint response\n */\n export interface VersionResponse {\n status: typeof StatusCode.Success;\n versionInfo: VersionInfo;\n }\n}\n\nexport interface EnsRainbowApiClientOptions {\n /**\n * The maximum number of `HealResponse` values to cache.\n * Must be a non-negative integer.\n * Setting to 0 will disable caching.\n */\n cacheCapacity: number;\n\n /**\n * The URL of an ENSRainbow API endpoint.\n */\n endpointUrl: URL;\n\n /**\n * Optional label set preferences that the ENSRainbow server at endpointUrl is expected to\n * support. If provided, enables deterministic heal results across time, such that only\n * labels from label sets with versions less than or equal to this value will be returned.\n * Therefore, even if the ENSRainbow server later ingests label sets with greater versions\n * than this value, the results returned across time can be deterministic. If\n * provided, heal operations with this EnsRainbowApiClient will validate the ENSRainbow\n * server manages a compatible label set. If not provided no specific labelSetId validation\n * will be performed during heal operations.\n * If `labelSetId` is provided without `labelSetVersion`, the server will use the latest\n * available version.\n * If `labelSetVersion` is defined, only labels from sets less than or equal to this value\n * will be returned.\n * When `labelSetVersion` is defined, `labelSetId` must also be defined.\n */\n labelSet?: EnsRainbowClientLabelSet;\n}\n\n/**\n * ENSRainbow API client\n *\n * @example\n * ```typescript\n * // default options\n * const client = new EnsRainbowApiClient();\n * // custom options\n * const client = new EnsRainbowApiClient({\n * endpointUrl: new URL(\"https://api.ensrainbow.io\"),\n * });\n * ```\n */\nexport class EnsRainbowApiClient implements EnsRainbow.ApiClient {\n private readonly options: EnsRainbowApiClientOptions;\n private readonly cache: Cache<LabelHash, EnsRainbow.CacheableHealResponse>;\n private readonly labelSetSearchParams: URLSearchParams;\n\n public static readonly DEFAULT_CACHE_CAPACITY = 1000;\n\n /**\n * Create default client options.\n *\n * @returns default options\n */\n static defaultOptions(): EnsRainbow.ApiClientOptions {\n return {\n endpointUrl: new URL(DEFAULT_ENSRAINBOW_URL),\n cacheCapacity: EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY,\n labelSet: buildEnsRainbowClientLabelSet(),\n };\n }\n\n constructor(options: Partial<EnsRainbow.ApiClientOptions> = {}) {\n const { labelSet: optionsLabelSet, ...rest } = options;\n const defaultOptions = EnsRainbowApiClient.defaultOptions();\n\n const copiedLabelSet = buildEnsRainbowClientLabelSet(\n optionsLabelSet?.labelSetId,\n optionsLabelSet?.labelSetVersion,\n );\n\n this.options = {\n ...defaultOptions,\n ...rest,\n labelSet: copiedLabelSet,\n };\n\n this.cache = new LruCache<LabelHash, EnsRainbow.CacheableHealResponse>(\n this.options.cacheCapacity,\n );\n\n // Pre-compute query parameters for label set options\n this.labelSetSearchParams = new URLSearchParams();\n if (this.options.labelSet?.labelSetId !== undefined) {\n this.labelSetSearchParams.append(\"label_set_id\", this.options.labelSet.labelSetId);\n }\n if (this.options.labelSet?.labelSetVersion !== undefined) {\n this.labelSetSearchParams.append(\n \"label_set_version\",\n this.options.labelSet.labelSetVersion.toString(),\n );\n }\n }\n\n /**\n * Attempt to heal a labelHash to its original label.\n *\n * Note on returned labels: ENSRainbow returns labels exactly as they are\n * represented in source rainbow table data. This means:\n *\n * - Labels may or may not be ENS-normalized\n * - Labels can contain any valid string, including dots, null bytes, or be empty\n * - Clients should handle all possible string values appropriately\n *\n * @param labelHash all lowercase 64-digit hex string with 0x prefix (total length of 66 characters)\n * @returns a `HealResponse` indicating the result of the request and the healed label if successful\n * @throws if the request fails due to network failures, DNS lookup failures, request timeouts,\n * CORS violations, or Invalid URLs\n * @example\n * ```typescript\n * const response = await client.heal(\n * \"0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc\"\n * );\n *\n * console.log(response);\n *\n * // Output:\n * // {\n * // status: \"success\",\n * // label: \"vitalik\"\n * // }\n *\n * const notFoundResponse = await client.heal(\n * \"0xf64dc17ae2e2b9b16dbcb8cb05f35a2e6080a5ff1dc53ac0bc48f0e79111f264\"\n * );\n *\n * console.log(notFoundResponse);\n *\n * // Output:\n * // {\n * // status: \"error\",\n * // error: \"Label not found\",\n * // errorCode: 404\n * // }\n * ```\n */\n async heal(labelHash: LabelHash): Promise<EnsRainbow.HealResponse> {\n const cachedResult = this.cache.get(labelHash);\n if (cachedResult) return cachedResult;\n\n const url = new URL(`/v1/heal/${labelHash}`, this.options.endpointUrl);\n\n // Apply pre-computed label set query parameters\n this.labelSetSearchParams.forEach((value, key) => {\n url.searchParams.append(key, value);\n });\n\n const response = await fetch(url);\n const healResponse = (await response.json()) as EnsRainbow.HealResponse;\n\n if (isCacheableHealResponse(healResponse)) {\n this.cache.set(labelHash, healResponse);\n }\n\n return healResponse;\n }\n\n /**\n * Get Count of Healable Labels\n *\n * @returns a `CountResponse` indicating the result and the timestamp of the request and the\n * number of healable labels if successful\n * @throws if the request fails due to network failures, DNS lookup failures, request timeouts,\n * CORS violations, or Invalid URLs\n * @example\n *\n * const response = await client.count();\n *\n * console.log(response);\n *\n * // {\n * // \"status\": \"success\",\n * // \"count\": 133856894,\n * // \"timestamp\": \"2024-01-30T11:18:56Z\"\n * // }\n *\n */\n async count(): Promise<EnsRainbow.CountResponse> {\n const response = await fetch(new URL(\"/v1/labels/count\", this.options.endpointUrl));\n\n return response.json() as Promise<EnsRainbow.CountResponse>;\n }\n\n /**\n *\n * Simple verification that the service is running, either in your local setup or for the\n * provided hosted instance.\n * @returns a status of ENS Rainbow service\n * @example\n *\n * const response = await client.health();\n *\n * console.log(response);\n *\n * // {\n * // \"status\": \"ok\",\n * // }\n */\n async health(): Promise<EnsRainbow.HealthResponse> {\n const response = await fetch(new URL(\"/health\", this.options.endpointUrl));\n\n return response.json() as Promise<EnsRainbow.HealthResponse>;\n }\n\n /**\n * Get the version information of the ENSRainbow service\n *\n * @returns the version information of the ENSRainbow service\n * @throws if the request fails due to network failures, DNS lookup failures, request\n * timeouts, CORS violations, or invalid URLs\n * @example\n * ```typescript\n * const response = await client.version();\n *\n * console.log(response);\n *\n * // {\n * // \"status\": \"success\",\n * // \"versionInfo\": {\n * // \"version\": \"0.1.0\",\n * // \"dbSchemaVersion\": 2,\n * // \"labelSet\": {\n * // \"labelSetId\": \"subgraph\",\n * // \"labelSetVersion\": 0\n * // }\n * // }\n * // }\n * ```\n */\n async version(): Promise<EnsRainbow.VersionResponse> {\n const response = await fetch(new URL(\"/v1/version\", this.options.endpointUrl));\n\n return response.json() as Promise<EnsRainbow.VersionResponse>;\n }\n\n /**\n * Get a copy of the current client options.\n *\n * @returns a copy of the current client options.\n */\n getOptions(): Readonly<EnsRainbowApiClientOptions> {\n // build a deep copy to prevent modification\n const deepCopy = {\n cacheCapacity: this.options.cacheCapacity,\n endpointUrl: new URL(this.options.endpointUrl.href),\n labelSet: this.options.labelSet ? { ...this.options.labelSet } : undefined,\n } satisfies EnsRainbowApiClientOptions;\n\n return Object.freeze(deepCopy);\n }\n}\n\n/**\n * Determine if a heal response is an error.\n *\n * @param response the heal response to check\n * @returns true if the response is an error, false otherwise\n */\nexport const isHealError = (\n response: EnsRainbow.HealResponse,\n): response is EnsRainbow.HealError => {\n return response.status === StatusCode.Error;\n};\n\n/**\n * Determine if a heal response is cacheable.\n *\n * Server errors at not cachable and should be retried.\n *\n * @param response the heal response to check\n * @returns true if the response is cacheable, false otherwise\n */\nexport const isCacheableHealResponse = (\n response: EnsRainbow.HealResponse,\n): response is EnsRainbow.CacheableHealResponse => {\n return response.status === StatusCode.Success || response.errorCode !== ErrorCode.ServerError;\n};\n","export const DEFAULT_ENSRAINBOW_URL = \"https://api.ensrainbow.io\" as const;\n\nexport const StatusCode = {\n Success: \"success\",\n Error: \"error\",\n} as const;\n\nexport const ErrorCode = {\n BadRequest: 400,\n NotFound: 404,\n ServerError: 500,\n} as const;\n"],"mappings":"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","names":["buildEnsRainbowClientLabelSet"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ensnode/ensrainbow-sdk",
|
|
3
|
+
"version": "0.0.0-next-20260102143513",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "ENSRainbow SDK for interacting with the ENSRainbow API.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/namehash/ensnode.git",
|
|
10
|
+
"directory": "packages/ensrainbow-sdk"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/namehash/ensnode/tree/main/packages/ensrainbow-sdk",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"ENS",
|
|
15
|
+
"ENSNode",
|
|
16
|
+
"ENSRainbow"
|
|
17
|
+
],
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./client": {
|
|
27
|
+
"types": "./dist/client.d.ts",
|
|
28
|
+
"default": "./dist/client.js"
|
|
29
|
+
},
|
|
30
|
+
"./consts": {
|
|
31
|
+
"types": "./dist/consts.d.ts",
|
|
32
|
+
"default": "./dist/consts.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"viem": "^2.22.13"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"tsup": "^8.3.6",
|
|
43
|
+
"typescript": "^5.7.3",
|
|
44
|
+
"vitest": "^4.0.2",
|
|
45
|
+
"@ensnode/shared-configs": "0.0.0-next-20260102143513",
|
|
46
|
+
"@ensnode/ensnode-sdk": "0.0.0-next-20260102143513"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"prepublish": "tsup",
|
|
50
|
+
"test": "vitest",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"lint": "biome check --write .",
|
|
53
|
+
"lint:ci": "biome ci"
|
|
54
|
+
},
|
|
55
|
+
"main": "./dist/index.js",
|
|
56
|
+
"module": "./dist/index.mjs",
|
|
57
|
+
"types": "./dist/index.d.ts"
|
|
58
|
+
}
|