@ensnode/ensrainbow-sdk 0.33.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -1,9 +1,13 @@
1
- import { LabelHash, Label } from '@ensnode/ensnode-sdk';
1
+ import { EnsRainbowClientLabelSet, LabelHash, Label, EnsRainbowServerLabelSet } from '@ensnode/ensnode-sdk';
2
2
 
3
3
  declare namespace EnsRainbow {
4
4
  export type ApiClientOptions = EnsRainbowApiClientOptions;
5
5
  export interface ApiClient {
6
6
  count(): Promise<CountResponse>;
7
+ /**
8
+ * Heal a labelhash to its original label
9
+ * @param labelHash The labelhash to heal
10
+ */
7
11
  heal(labelHash: LabelHash): Promise<HealResponse>;
8
12
  health(): Promise<HealthResponse>;
9
13
  version(): Promise<VersionResponse>;
@@ -59,7 +63,8 @@ declare namespace EnsRainbow {
59
63
  }
60
64
  export interface CountSuccess extends BaseCountResponse<typeof StatusCode.Success, never> {
61
65
  status: typeof StatusCode.Success;
62
- /** The total count of labels that can be healed by the ENSRainbow instance. Always a non-negative integer. */
66
+ /** The total count of labels that can be healed by the ENSRainbow instance. Always a
67
+ * non-negative integer. */
63
68
  count: number;
64
69
  timestamp: string;
65
70
  error?: never;
@@ -82,9 +87,13 @@ declare namespace EnsRainbow {
82
87
  */
83
88
  version: string;
84
89
  /**
85
- * ENSRainbow schema version.
90
+ * ENSRainbow database schema version.
86
91
  */
87
- schema_version: number;
92
+ dbSchemaVersion: number;
93
+ /**
94
+ * The EnsRainbowServerLabelSet managed by the ENSRainbow server.
95
+ */
96
+ labelSet: EnsRainbowServerLabelSet;
88
97
  }
89
98
  /**
90
99
  * Interface for the version endpoint response
@@ -106,6 +115,22 @@ interface EnsRainbowApiClientOptions {
106
115
  * The URL of an ENSRainbow API endpoint.
107
116
  */
108
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;
109
134
  }
110
135
  /**
111
136
  * ENSRainbow API client
@@ -123,6 +148,7 @@ interface EnsRainbowApiClientOptions {
123
148
  declare class EnsRainbowApiClient implements EnsRainbow.ApiClient {
124
149
  private readonly options;
125
150
  private readonly cache;
151
+ private readonly labelSetSearchParams;
126
152
  static readonly DEFAULT_CACHE_CAPACITY = 1000;
127
153
  /**
128
154
  * Create default client options.
@@ -143,8 +169,8 @@ declare class EnsRainbowApiClient implements EnsRainbow.ApiClient {
143
169
  *
144
170
  * @param labelHash all lowercase 64-digit hex string with 0x prefix (total length of 66 characters)
145
171
  * @returns a `HealResponse` indicating the result of the request and the healed label if successful
146
- * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs
147
- *
172
+ * @throws if the request fails due to network failures, DNS lookup failures, request timeouts,
173
+ * CORS violations, or Invalid URLs
148
174
  * @example
149
175
  * ```typescript
150
176
  * const response = await client.heal(
@@ -177,9 +203,10 @@ declare class EnsRainbowApiClient implements EnsRainbow.ApiClient {
177
203
  /**
178
204
  * Get Count of Healable Labels
179
205
  *
180
- * @returns a `CountResponse` indicating the result and the timestamp of the request and the number of healable labels if successful
181
- * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs
182
- *
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
183
210
  * @example
184
211
  *
185
212
  * const response = await client.count();
@@ -196,8 +223,8 @@ declare class EnsRainbowApiClient implements EnsRainbow.ApiClient {
196
223
  count(): Promise<EnsRainbow.CountResponse>;
197
224
  /**
198
225
  *
199
- * Simple verification that the service is running, either in your local setup or for the provided hosted instance
200
- *
226
+ * Simple verification that the service is running, either in your local setup or for the
227
+ * provided hosted instance.
201
228
  * @returns a status of ENS Rainbow service
202
229
  * @example
203
230
  *
@@ -214,8 +241,8 @@ declare class EnsRainbowApiClient implements EnsRainbow.ApiClient {
214
241
  * Get the version information of the ENSRainbow service
215
242
  *
216
243
  * @returns the version information of the ENSRainbow service
217
- * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs
218
- *
244
+ * @throws if the request fails due to network failures, DNS lookup failures, request
245
+ * timeouts, CORS violations, or invalid URLs
219
246
  * @example
220
247
  * ```typescript
221
248
  * const response = await client.version();
@@ -224,8 +251,14 @@ declare class EnsRainbowApiClient implements EnsRainbow.ApiClient {
224
251
  *
225
252
  * // {
226
253
  * // "status": "success",
227
- * // "version": "0.1.0",
228
- * // "schema_version": 2
254
+ * // "versionInfo": {
255
+ * // "version": "0.1.0",
256
+ * // "dbSchemaVersion": 2,
257
+ * // "labelSet": {
258
+ * // "labelSetId": "subgraph",
259
+ * // "labelSetVersion": 0
260
+ * // }
261
+ * // }
229
262
  * // }
230
263
  * ```
231
264
  */
package/dist/client.js CHANGED
@@ -1,5 +1,8 @@
1
1
  // src/client.ts
2
2
  import { LruCache } from "@ensnode/ensnode-sdk";
3
+ import {
4
+ buildEnsRainbowClientLabelSet
5
+ } from "@ensnode/ensnode-sdk";
3
6
 
4
7
  // src/consts.ts
5
8
  var DEFAULT_ENSRAINBOW_URL = "https://api.ensrainbow.io";
@@ -17,6 +20,7 @@ var ErrorCode = {
17
20
  var EnsRainbowApiClient = class _EnsRainbowApiClient {
18
21
  options;
19
22
  cache;
23
+ labelSetSearchParams;
20
24
  static DEFAULT_CACHE_CAPACITY = 1e3;
21
25
  /**
22
26
  * Create default client options.
@@ -26,17 +30,35 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
26
30
  static defaultOptions() {
27
31
  return {
28
32
  endpointUrl: new URL(DEFAULT_ENSRAINBOW_URL),
29
- cacheCapacity: _EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY
33
+ cacheCapacity: _EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY,
34
+ labelSet: buildEnsRainbowClientLabelSet()
30
35
  };
31
36
  }
32
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
+ );
33
44
  this.options = {
34
- ..._EnsRainbowApiClient.defaultOptions(),
35
- ...options
45
+ ...defaultOptions,
46
+ ...rest,
47
+ labelSet: copiedLabelSet
36
48
  };
37
49
  this.cache = new LruCache(
38
50
  this.options.cacheCapacity
39
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
+ }
40
62
  }
41
63
  /**
42
64
  * Attempt to heal a labelHash to its original label.
@@ -50,8 +72,8 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
50
72
  *
51
73
  * @param labelHash all lowercase 64-digit hex string with 0x prefix (total length of 66 characters)
52
74
  * @returns a `HealResponse` indicating the result of the request and the healed label if successful
53
- * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs
54
- *
75
+ * @throws if the request fails due to network failures, DNS lookup failures, request timeouts,
76
+ * CORS violations, or Invalid URLs
55
77
  * @example
56
78
  * ```typescript
57
79
  * const response = await client.heal(
@@ -82,10 +104,12 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
82
104
  */
83
105
  async heal(labelHash) {
84
106
  const cachedResult = this.cache.get(labelHash);
85
- if (cachedResult) {
86
- return cachedResult;
87
- }
88
- const response = await fetch(new URL(`/v1/heal/${labelHash}`, this.options.endpointUrl));
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);
89
113
  const healResponse = await response.json();
90
114
  if (isCacheableHealResponse(healResponse)) {
91
115
  this.cache.set(labelHash, healResponse);
@@ -95,9 +119,10 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
95
119
  /**
96
120
  * Get Count of Healable Labels
97
121
  *
98
- * @returns a `CountResponse` indicating the result and the timestamp of the request and the number of healable labels if successful
99
- * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs
100
- *
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
101
126
  * @example
102
127
  *
103
128
  * const response = await client.count();
@@ -117,8 +142,8 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
117
142
  }
118
143
  /**
119
144
  *
120
- * Simple verification that the service is running, either in your local setup or for the provided hosted instance
121
- *
145
+ * Simple verification that the service is running, either in your local setup or for the
146
+ * provided hosted instance.
122
147
  * @returns a status of ENS Rainbow service
123
148
  * @example
124
149
  *
@@ -138,8 +163,8 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
138
163
  * Get the version information of the ENSRainbow service
139
164
  *
140
165
  * @returns the version information of the ENSRainbow service
141
- * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs
142
- *
166
+ * @throws if the request fails due to network failures, DNS lookup failures, request
167
+ * timeouts, CORS violations, or invalid URLs
143
168
  * @example
144
169
  * ```typescript
145
170
  * const response = await client.version();
@@ -148,8 +173,14 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
148
173
  *
149
174
  * // {
150
175
  * // "status": "success",
151
- * // "version": "0.1.0",
152
- * // "schema_version": 2
176
+ * // "versionInfo": {
177
+ * // "version": "0.1.0",
178
+ * // "dbSchemaVersion": 2,
179
+ * // "labelSet": {
180
+ * // "labelSetId": "subgraph",
181
+ * // "labelSetVersion": 0
182
+ * // }
183
+ * // }
153
184
  * // }
154
185
  * ```
155
186
  */
@@ -165,7 +196,8 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
165
196
  getOptions() {
166
197
  const deepCopy = {
167
198
  cacheCapacity: this.options.cacheCapacity,
168
- endpointUrl: new URL(this.options.endpointUrl.href)
199
+ endpointUrl: new URL(this.options.endpointUrl.href),
200
+ labelSet: this.options.labelSet ? { ...this.options.labelSet } : void 0
169
201
  };
170
202
  return Object.freeze(deepCopy);
171
203
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/consts.ts"],"sourcesContent":["import { type Cache, Label, type LabelHash, LruCache } from \"@ensnode/ensnode-sdk\";\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 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 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 schema version.\n */\n schema_version: number;\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/**\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\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 };\n }\n\n constructor(options: Partial<EnsRainbow.ApiClientOptions> = {}) {\n this.options = {\n ...EnsRainbowApiClient.defaultOptions(),\n ...options,\n };\n\n this.cache = new LruCache<LabelHash, EnsRainbow.CacheableHealResponse>(\n this.options.cacheCapacity,\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, CORS violations, or Invalid URLs\n *\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\n if (cachedResult) {\n return cachedResult;\n }\n\n const response = await fetch(new URL(`/v1/heal/${labelHash}`, this.options.endpointUrl));\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 number of healable labels if successful\n * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs\n *\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 provided hosted instance\n *\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 timeouts, CORS violations, or Invalid URLs\n *\n * @example\n * ```typescript\n * const response = await client.version();\n *\n * console.log(response);\n *\n * // {\n * // \"status\": \"success\",\n * // \"version\": \"0.1.0\",\n * // \"schema_version\": 2\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 } 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,SAA4C,gBAAgB;;;ACArD,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;;;ADgJO,IAAM,sBAAN,MAAM,qBAAoD;AAAA,EAC9C;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,IACrC;AAAA,EACF;AAAA,EAEA,YAAY,UAAgD,CAAC,GAAG;AAC9D,SAAK,UAAU;AAAA,MACb,GAAG,qBAAoB,eAAe;AAAA,MACtC,GAAG;AAAA,IACL;AAEA,SAAK,QAAQ,IAAI;AAAA,MACf,KAAK,QAAQ;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;AAE7C,QAAI,cAAc;AAChB,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,MAAM,MAAM,IAAI,IAAI,YAAY,SAAS,IAAI,KAAK,QAAQ,WAAW,CAAC;AACvF,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,EAqBA,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,EAqBA,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,IACpD;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":[]}
1
+ {"version":3,"sources":["../src/client.ts","../src/consts.ts"],"sourcesContent":["import { type Cache, Label, type LabelHash, LruCache } from \"@ensnode/ensnode-sdk\";\nimport {\n type EnsRainbowClientLabelSet,\n type EnsRainbowServerLabelSet,\n buildEnsRainbowClientLabelSet,\n} from \"@ensnode/ensnode-sdk\";\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":[]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
1
  export { EnsRainbow, EnsRainbowApiClient, EnsRainbowApiClientOptions, isCacheableHealResponse, isHealError } from './client.js';
2
2
  export { DEFAULT_ENSRAINBOW_URL, ErrorCode, StatusCode } from './consts.js';
3
- export { labelHashToBytes } from './labelUtils.js';
4
- import '@ensnode/ensnode-sdk';
5
- import 'viem';
3
+ export { EnsRainbowClientLabelSet, EnsRainbowServerLabelSet, LabelSetId, LabelSetVersion, buildEnsRainbowClientLabelSet } from '@ensnode/ensnode-sdk';
package/dist/index.js CHANGED
@@ -1,5 +1,8 @@
1
1
  // src/client.ts
2
2
  import { LruCache } from "@ensnode/ensnode-sdk";
3
+ import {
4
+ buildEnsRainbowClientLabelSet
5
+ } from "@ensnode/ensnode-sdk";
3
6
 
4
7
  // src/consts.ts
5
8
  var DEFAULT_ENSRAINBOW_URL = "https://api.ensrainbow.io";
@@ -17,6 +20,7 @@ var ErrorCode = {
17
20
  var EnsRainbowApiClient = class _EnsRainbowApiClient {
18
21
  options;
19
22
  cache;
23
+ labelSetSearchParams;
20
24
  static DEFAULT_CACHE_CAPACITY = 1e3;
21
25
  /**
22
26
  * Create default client options.
@@ -26,17 +30,35 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
26
30
  static defaultOptions() {
27
31
  return {
28
32
  endpointUrl: new URL(DEFAULT_ENSRAINBOW_URL),
29
- cacheCapacity: _EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY
33
+ cacheCapacity: _EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY,
34
+ labelSet: buildEnsRainbowClientLabelSet()
30
35
  };
31
36
  }
32
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
+ );
33
44
  this.options = {
34
- ..._EnsRainbowApiClient.defaultOptions(),
35
- ...options
45
+ ...defaultOptions,
46
+ ...rest,
47
+ labelSet: copiedLabelSet
36
48
  };
37
49
  this.cache = new LruCache(
38
50
  this.options.cacheCapacity
39
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
+ }
40
62
  }
41
63
  /**
42
64
  * Attempt to heal a labelHash to its original label.
@@ -50,8 +72,8 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
50
72
  *
51
73
  * @param labelHash all lowercase 64-digit hex string with 0x prefix (total length of 66 characters)
52
74
  * @returns a `HealResponse` indicating the result of the request and the healed label if successful
53
- * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs
54
- *
75
+ * @throws if the request fails due to network failures, DNS lookup failures, request timeouts,
76
+ * CORS violations, or Invalid URLs
55
77
  * @example
56
78
  * ```typescript
57
79
  * const response = await client.heal(
@@ -82,10 +104,12 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
82
104
  */
83
105
  async heal(labelHash) {
84
106
  const cachedResult = this.cache.get(labelHash);
85
- if (cachedResult) {
86
- return cachedResult;
87
- }
88
- const response = await fetch(new URL(`/v1/heal/${labelHash}`, this.options.endpointUrl));
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);
89
113
  const healResponse = await response.json();
90
114
  if (isCacheableHealResponse(healResponse)) {
91
115
  this.cache.set(labelHash, healResponse);
@@ -95,9 +119,10 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
95
119
  /**
96
120
  * Get Count of Healable Labels
97
121
  *
98
- * @returns a `CountResponse` indicating the result and the timestamp of the request and the number of healable labels if successful
99
- * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs
100
- *
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
101
126
  * @example
102
127
  *
103
128
  * const response = await client.count();
@@ -117,8 +142,8 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
117
142
  }
118
143
  /**
119
144
  *
120
- * Simple verification that the service is running, either in your local setup or for the provided hosted instance
121
- *
145
+ * Simple verification that the service is running, either in your local setup or for the
146
+ * provided hosted instance.
122
147
  * @returns a status of ENS Rainbow service
123
148
  * @example
124
149
  *
@@ -138,8 +163,8 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
138
163
  * Get the version information of the ENSRainbow service
139
164
  *
140
165
  * @returns the version information of the ENSRainbow service
141
- * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs
142
- *
166
+ * @throws if the request fails due to network failures, DNS lookup failures, request
167
+ * timeouts, CORS violations, or invalid URLs
143
168
  * @example
144
169
  * ```typescript
145
170
  * const response = await client.version();
@@ -148,8 +173,14 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
148
173
  *
149
174
  * // {
150
175
  * // "status": "success",
151
- * // "version": "0.1.0",
152
- * // "schema_version": 2
176
+ * // "versionInfo": {
177
+ * // "version": "0.1.0",
178
+ * // "dbSchemaVersion": 2,
179
+ * // "labelSet": {
180
+ * // "labelSetId": "subgraph",
181
+ * // "labelSetVersion": 0
182
+ * // }
183
+ * // }
153
184
  * // }
154
185
  * ```
155
186
  */
@@ -165,7 +196,8 @@ var EnsRainbowApiClient = class _EnsRainbowApiClient {
165
196
  getOptions() {
166
197
  const deepCopy = {
167
198
  cacheCapacity: this.options.cacheCapacity,
168
- endpointUrl: new URL(this.options.endpointUrl.href)
199
+ endpointUrl: new URL(this.options.endpointUrl.href),
200
+ labelSet: this.options.labelSet ? { ...this.options.labelSet } : void 0
169
201
  };
170
202
  return Object.freeze(deepCopy);
171
203
  }
@@ -177,38 +209,15 @@ var isCacheableHealResponse = (response) => {
177
209
  return response.status === StatusCode.Success || response.errorCode !== ErrorCode.ServerError;
178
210
  };
179
211
 
180
- // src/label-utils.ts
181
- import { hexToBytes } from "viem";
182
- function labelHashToBytes(labelHash) {
183
- try {
184
- if (labelHash.length !== 66) {
185
- throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);
186
- }
187
- if (labelHash !== labelHash.toLowerCase()) {
188
- throw new Error("Labelhash must be in lowercase");
189
- }
190
- if (!labelHash.startsWith("0x")) {
191
- throw new Error("Labelhash must be 0x-prefixed");
192
- }
193
- const bytes = hexToBytes(labelHash);
194
- if (bytes.length !== 32) {
195
- throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);
196
- }
197
- return bytes;
198
- } catch (e) {
199
- if (e instanceof Error) {
200
- throw e;
201
- }
202
- throw new Error("Invalid hex format");
203
- }
204
- }
212
+ // src/index.ts
213
+ import { buildEnsRainbowClientLabelSet as buildEnsRainbowClientLabelSet2 } from "@ensnode/ensnode-sdk";
205
214
  export {
206
215
  DEFAULT_ENSRAINBOW_URL,
207
216
  EnsRainbowApiClient,
208
217
  ErrorCode,
209
218
  StatusCode,
219
+ buildEnsRainbowClientLabelSet2 as buildEnsRainbowClientLabelSet,
210
220
  isCacheableHealResponse,
211
- isHealError,
212
- labelHashToBytes
221
+ isHealError
213
222
  };
214
223
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/consts.ts","../src/label-utils.ts"],"sourcesContent":["import { type Cache, Label, type LabelHash, LruCache } from \"@ensnode/ensnode-sdk\";\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 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 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 schema version.\n */\n schema_version: number;\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/**\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\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 };\n }\n\n constructor(options: Partial<EnsRainbow.ApiClientOptions> = {}) {\n this.options = {\n ...EnsRainbowApiClient.defaultOptions(),\n ...options,\n };\n\n this.cache = new LruCache<LabelHash, EnsRainbow.CacheableHealResponse>(\n this.options.cacheCapacity,\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, CORS violations, or Invalid URLs\n *\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\n if (cachedResult) {\n return cachedResult;\n }\n\n const response = await fetch(new URL(`/v1/heal/${labelHash}`, this.options.endpointUrl));\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 number of healable labels if successful\n * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, CORS violations, or Invalid URLs\n *\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 provided hosted instance\n *\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 timeouts, CORS violations, or Invalid URLs\n *\n * @example\n * ```typescript\n * const response = await client.version();\n *\n * console.log(response);\n *\n * // {\n * // \"status\": \"success\",\n * // \"version\": \"0.1.0\",\n * // \"schema_version\": 2\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 } 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","import type { LabelHash } from \"@ensnode/ensnode-sdk\";\nimport { ByteArray, hexToBytes } from \"viem\";\n\n/**\n * Converts a Labelhash to bytes, with validation\n * @param labelHash The Labelhash to convert\n * @returns A ByteArray containing the bytes\n * @throws Error if `labelHash` is not a valid 32-byte hex string\n */\nexport function labelHashToBytes(labelHash: LabelHash): ByteArray {\n try {\n if (labelHash.length !== 66) {\n throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);\n }\n if (labelHash !== labelHash.toLowerCase()) {\n throw new Error(\"Labelhash must be in lowercase\");\n }\n if (!labelHash.startsWith(\"0x\")) {\n throw new Error(\"Labelhash must be 0x-prefixed\");\n }\n const bytes = hexToBytes(labelHash);\n if (bytes.length !== 32) {\n // should be redundant but keeping it for the principle of defensive programming\n throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);\n }\n return bytes;\n } catch (e) {\n if (e instanceof Error) {\n throw e;\n }\n throw new Error(\"Invalid hex format\");\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/client.ts","../src/consts.ts","../src/index.ts"],"sourcesContent":["import { type Cache, Label, type LabelHash, LruCache } from \"@ensnode/ensnode-sdk\";\nimport {\n type EnsRainbowClientLabelSet,\n type EnsRainbowServerLabelSet,\n buildEnsRainbowClientLabelSet,\n} from \"@ensnode/ensnode-sdk\";\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","export * from \"./client\";\nexport * from \"./consts\";\n\n// 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\n// Re-export utility functions and classes from ensnode-sdk that are needed by consumers\nexport { buildEnsRainbowClientLabelSet } from \"@ensnode/ensnode-sdk\";\n"],"mappings":"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","names":["buildEnsRainbowClientLabelSet"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensnode/ensrainbow-sdk",
3
- "version": "0.33.0",
3
+ "version": "0.34.0",
4
4
  "type": "module",
5
5
  "description": "ENSRainbow SDK for interacting with the ENSRainbow API.",
6
6
  "license": "MIT",
@@ -30,10 +30,6 @@
30
30
  "./consts": {
31
31
  "types": "./dist/consts.d.ts",
32
32
  "default": "./dist/consts.js"
33
- },
34
- "./label-utils": {
35
- "types": "./dist/label-utils.d.ts",
36
- "default": "./dist/label-utils.js"
37
33
  }
38
34
  },
39
35
  "publishConfig": {
@@ -47,14 +43,14 @@
47
43
  "tsup": "^8.3.6",
48
44
  "typescript": "^5.7.3",
49
45
  "vitest": "^3.1.1",
50
- "@ensnode/shared-configs": "0.33.0",
51
- "@ensnode/ensnode-sdk": "0.33.0"
46
+ "@ensnode/shared-configs": "0.34.0",
47
+ "@ensnode/ensnode-sdk": "0.34.0"
52
48
  },
53
49
  "scripts": {
54
50
  "prepublish": "tsup",
55
51
  "test": "vitest",
56
52
  "typecheck": "tsc --noEmit",
57
- "lint": "biome check --write",
53
+ "lint": "biome check --write .",
58
54
  "lint:ci": "biome ci"
59
55
  },
60
56
  "main": "./dist/index.js",
@@ -1,3 +0,0 @@
1
- import '@ensnode/ensnode-sdk';
2
- import 'viem';
3
- export { labelHashToBytes } from './labelUtils.js';
@@ -1,29 +0,0 @@
1
- // src/label-utils.ts
2
- import { hexToBytes } from "viem";
3
- function labelHashToBytes(labelHash) {
4
- try {
5
- if (labelHash.length !== 66) {
6
- throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);
7
- }
8
- if (labelHash !== labelHash.toLowerCase()) {
9
- throw new Error("Labelhash must be in lowercase");
10
- }
11
- if (!labelHash.startsWith("0x")) {
12
- throw new Error("Labelhash must be 0x-prefixed");
13
- }
14
- const bytes = hexToBytes(labelHash);
15
- if (bytes.length !== 32) {
16
- throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);
17
- }
18
- return bytes;
19
- } catch (e) {
20
- if (e instanceof Error) {
21
- throw e;
22
- }
23
- throw new Error("Invalid hex format");
24
- }
25
- }
26
- export {
27
- labelHashToBytes
28
- };
29
- //# sourceMappingURL=label-utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/label-utils.ts"],"sourcesContent":["import type { LabelHash } from \"@ensnode/ensnode-sdk\";\nimport { ByteArray, hexToBytes } from \"viem\";\n\n/**\n * Converts a Labelhash to bytes, with validation\n * @param labelHash The Labelhash to convert\n * @returns A ByteArray containing the bytes\n * @throws Error if `labelHash` is not a valid 32-byte hex string\n */\nexport function labelHashToBytes(labelHash: LabelHash): ByteArray {\n try {\n if (labelHash.length !== 66) {\n throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);\n }\n if (labelHash !== labelHash.toLowerCase()) {\n throw new Error(\"Labelhash must be in lowercase\");\n }\n if (!labelHash.startsWith(\"0x\")) {\n throw new Error(\"Labelhash must be 0x-prefixed\");\n }\n const bytes = hexToBytes(labelHash);\n if (bytes.length !== 32) {\n // should be redundant but keeping it for the principle of defensive programming\n throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);\n }\n return bytes;\n } catch (e) {\n if (e instanceof Error) {\n throw e;\n }\n throw new Error(\"Invalid hex format\");\n }\n}\n"],"mappings":";AACA,SAAoB,kBAAkB;AAQ/B,SAAS,iBAAiB,WAAiC;AAChE,MAAI;AACF,QAAI,UAAU,WAAW,IAAI;AAC3B,YAAM,IAAI,MAAM,4BAA4B,UAAU,MAAM,2BAA2B;AAAA,IACzF;AACA,QAAI,cAAc,UAAU,YAAY,GAAG;AACzC,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,QAAI,CAAC,UAAU,WAAW,IAAI,GAAG;AAC/B,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AACA,UAAM,QAAQ,WAAW,SAAS;AAClC,QAAI,MAAM,WAAW,IAAI;AAEvB,YAAM,IAAI,MAAM,4BAA4B,MAAM,MAAM,sBAAsB;AAAA,IAChF;AACA,WAAO;AAAA,EACT,SAAS,GAAG;AACV,QAAI,aAAa,OAAO;AACtB,YAAM;AAAA,IACR;AACA,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AACF;","names":[]}
@@ -1,12 +0,0 @@
1
- import { LabelHash } from '@ensnode/ensnode-sdk';
2
- import { ByteArray } from 'viem';
3
-
4
- /**
5
- * Converts a Labelhash to bytes, with validation
6
- * @param labelHash The Labelhash to convert
7
- * @returns A ByteArray containing the bytes
8
- * @throws Error if `labelHash` is not a valid 32-byte hex string
9
- */
10
- declare function labelHashToBytes(labelHash: LabelHash): ByteArray;
11
-
12
- export { labelHashToBytes };
@@ -1,29 +0,0 @@
1
- // src/label-utils.ts
2
- import { hexToBytes } from "viem";
3
- function labelHashToBytes(labelHash) {
4
- try {
5
- if (labelHash.length !== 66) {
6
- throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);
7
- }
8
- if (labelHash !== labelHash.toLowerCase()) {
9
- throw new Error("Labelhash must be in lowercase");
10
- }
11
- if (!labelHash.startsWith("0x")) {
12
- throw new Error("Labelhash must be 0x-prefixed");
13
- }
14
- const bytes = hexToBytes(labelHash);
15
- if (bytes.length !== 32) {
16
- throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);
17
- }
18
- return bytes;
19
- } catch (e) {
20
- if (e instanceof Error) {
21
- throw e;
22
- }
23
- throw new Error("Invalid hex format");
24
- }
25
- }
26
- export {
27
- labelHashToBytes
28
- };
29
- //# sourceMappingURL=labelUtils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/label-utils.ts"],"sourcesContent":["import type { LabelHash } from \"@ensnode/ensnode-sdk\";\nimport { ByteArray, hexToBytes } from \"viem\";\n\n/**\n * Converts a Labelhash to bytes, with validation\n * @param labelHash The Labelhash to convert\n * @returns A ByteArray containing the bytes\n * @throws Error if `labelHash` is not a valid 32-byte hex string\n */\nexport function labelHashToBytes(labelHash: LabelHash): ByteArray {\n try {\n if (labelHash.length !== 66) {\n throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);\n }\n if (labelHash !== labelHash.toLowerCase()) {\n throw new Error(\"Labelhash must be in lowercase\");\n }\n if (!labelHash.startsWith(\"0x\")) {\n throw new Error(\"Labelhash must be 0x-prefixed\");\n }\n const bytes = hexToBytes(labelHash);\n if (bytes.length !== 32) {\n // should be redundant but keeping it for the principle of defensive programming\n throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);\n }\n return bytes;\n } catch (e) {\n if (e instanceof Error) {\n throw e;\n }\n throw new Error(\"Invalid hex format\");\n }\n}\n"],"mappings":";AACA,SAAoB,kBAAkB;AAQ/B,SAAS,iBAAiB,WAAiC;AAChE,MAAI;AACF,QAAI,UAAU,WAAW,IAAI;AAC3B,YAAM,IAAI,MAAM,4BAA4B,UAAU,MAAM,2BAA2B;AAAA,IACzF;AACA,QAAI,cAAc,UAAU,YAAY,GAAG;AACzC,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,QAAI,CAAC,UAAU,WAAW,IAAI,GAAG;AAC/B,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AACA,UAAM,QAAQ,WAAW,SAAS;AAClC,QAAI,MAAM,WAAW,IAAI;AAEvB,YAAM,IAAI,MAAM,4BAA4B,MAAM,MAAM,sBAAsB;AAAA,IAChF;AACA,WAAO;AAAA,EACT,SAAS,GAAG;AACV,QAAI,aAAa,OAAO;AACtB,YAAM;AAAA,IACR;AACA,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AACF;","names":[]}