@namehash/ens-referrals 1.5.1 → 1.6.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/index.js CHANGED
@@ -122,49 +122,469 @@ var buildAggregatedReferrerMetrics = (referrers, rules) => {
122
122
  return result;
123
123
  };
124
124
 
125
- // src/currency.ts
126
- function isValidUSDQuantity(value) {
127
- return isFiniteNonNegativeNumber(value);
125
+ // src/api/deserialize.ts
126
+ import { prettifyError } from "zod/v4";
127
+
128
+ // src/api/zod-schemas.ts
129
+ import { z as z2 } from "zod/v4";
130
+
131
+ // ../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/dist/index.mjs
132
+ function _extends() {
133
+ _extends = Object.assign || function(target) {
134
+ for (var i = 1; i < arguments.length; i++) {
135
+ var source = arguments[i];
136
+ for (var key in source) {
137
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
138
+ target[key] = source[key];
139
+ }
140
+ }
141
+ }
142
+ return target;
143
+ };
144
+ return _extends.apply(this, arguments);
128
145
  }
129
- function validateUSDQuantity(value) {
130
- if (!isValidUSDQuantity(value)) {
131
- throw new Error(`Invalid USD quantity: ${value}.`);
146
+ var CAIP2 = {
147
+ name: "chainId",
148
+ regex: "[-:a-zA-Z0-9]{5,41}",
149
+ parameters: {
150
+ delimiter: ":",
151
+ values: {
152
+ 0: {
153
+ name: "namespace",
154
+ regex: "[-a-z0-9]{3,8}"
155
+ },
156
+ 1: {
157
+ name: "reference",
158
+ regex: "[-a-zA-Z0-9]{1,32}"
159
+ }
160
+ }
161
+ }
162
+ };
163
+ var CAIP10 = {
164
+ name: "accountId",
165
+ regex: "[-:a-zA-Z0-9]{7,106}",
166
+ parameters: {
167
+ delimiter: ":",
168
+ values: {
169
+ 0: {
170
+ name: "namespace",
171
+ regex: "[-a-z0-9]{3,8}"
172
+ },
173
+ 1: {
174
+ name: "reference",
175
+ regex: "[-a-zA-Z0-9]{1,32}"
176
+ },
177
+ 2: {
178
+ name: "address",
179
+ regex: "[a-zA-Z0-9]{1,64}"
180
+ }
181
+ }
182
+ }
183
+ };
184
+ var AssetName$1 = {
185
+ name: "assetName",
186
+ regex: "[-:a-zA-Z0-9]{5,73}",
187
+ parameters: {
188
+ delimiter: ":",
189
+ values: {
190
+ 0: {
191
+ name: "namespace",
192
+ regex: "[-a-z0-9]{3,8}"
193
+ },
194
+ 1: {
195
+ name: "reference",
196
+ regex: "[-a-zA-Z0-9]{1,64}"
197
+ }
198
+ }
199
+ }
200
+ };
201
+ var CAIP19AssetType = {
202
+ name: "assetType",
203
+ regex: "[-:a-zA-Z0-9]{11,115}",
204
+ parameters: {
205
+ delimiter: "/",
206
+ values: {
207
+ 0: CAIP2,
208
+ 1: AssetName$1
209
+ }
210
+ }
211
+ };
212
+ var CAIP19AssetId = {
213
+ name: "assetId",
214
+ regex: "[-:a-zA-Z0-9]{13,148}",
215
+ parameters: {
216
+ delimiter: "/",
217
+ values: {
218
+ 0: CAIP2,
219
+ 1: AssetName$1,
220
+ 2: {
221
+ name: "tokenId",
222
+ regex: "[-a-zA-Z0-9]{1,32}"
223
+ }
224
+ }
225
+ }
226
+ };
227
+ var CAIP = {
228
+ "2": CAIP2,
229
+ "10": CAIP10,
230
+ "19": {
231
+ assetName: AssetName$1,
232
+ assetType: CAIP19AssetType,
233
+ assetId: CAIP19AssetId
234
+ }
235
+ };
236
+ function splitParams(id, spec) {
237
+ return id.split(spec.parameters.delimiter);
238
+ }
239
+ function getParams(id, spec) {
240
+ var arr = splitParams(id, spec);
241
+ var params = {};
242
+ arr.forEach(function(value, index) {
243
+ params[spec.parameters.values[index].name] = value;
244
+ });
245
+ return params;
246
+ }
247
+ function joinParams(params, spec) {
248
+ return Object.values(spec.parameters.values).map(function(parameter) {
249
+ var param = params[parameter.name];
250
+ return typeof param === "string" ? param : joinParams(param, parameter);
251
+ }).join(spec.parameters.delimiter);
252
+ }
253
+ function isValidId(id, spec) {
254
+ if (!new RegExp(spec.regex).test(id)) return false;
255
+ var params = splitParams(id, spec);
256
+ if (params.length !== Object.keys(spec.parameters.values).length) return false;
257
+ var matches = params.map(function(param, index) {
258
+ return new RegExp(spec.parameters.values[index].regex).test(param);
259
+ }).filter(function(x) {
260
+ return !!x;
261
+ });
262
+ if (matches.length !== params.length) return false;
263
+ return true;
264
+ }
265
+ var ChainId = /* @__PURE__ */ (function() {
266
+ function ChainId2(params) {
267
+ if (typeof params === "string") {
268
+ params = ChainId2.parse(params);
269
+ }
270
+ this.namespace = params.namespace;
271
+ this.reference = params.reference;
272
+ }
273
+ ChainId2.parse = function parse(id) {
274
+ if (!isValidId(id, this.spec)) {
275
+ throw new Error("Invalid " + this.spec.name + " provided: " + id);
276
+ }
277
+ return new ChainId2(getParams(id, this.spec)).toJSON();
278
+ };
279
+ ChainId2.format = function format(params) {
280
+ return joinParams(params, this.spec);
281
+ };
282
+ var _proto = ChainId2.prototype;
283
+ _proto.toString = function toString() {
284
+ return ChainId2.format(this.toJSON());
285
+ };
286
+ _proto.toJSON = function toJSON() {
287
+ return {
288
+ namespace: this.namespace,
289
+ reference: this.reference
290
+ };
291
+ };
292
+ return ChainId2;
293
+ })();
294
+ ChainId.spec = CAIP["2"];
295
+ var AccountId = /* @__PURE__ */ (function() {
296
+ function AccountId2(params) {
297
+ if (typeof params === "string") {
298
+ params = AccountId2.parse(params);
299
+ }
300
+ this.chainId = new ChainId(params.chainId);
301
+ this.address = params.address;
302
+ }
303
+ AccountId2.parse = function parse(id) {
304
+ if (!isValidId(id, this.spec)) {
305
+ throw new Error("Invalid " + this.spec.name + " provided: " + id);
306
+ }
307
+ var _getParams = getParams(id, this.spec), namespace = _getParams.namespace, reference = _getParams.reference, address = _getParams.address;
308
+ var chainId = new ChainId({
309
+ namespace,
310
+ reference
311
+ });
312
+ return new AccountId2({
313
+ chainId,
314
+ address
315
+ }).toJSON();
316
+ };
317
+ AccountId2.format = function format(params) {
318
+ var chainId = new ChainId(params.chainId);
319
+ var splitParams2 = _extends({}, chainId.toJSON(), {
320
+ address: params.address
321
+ });
322
+ return joinParams(splitParams2, this.spec);
323
+ };
324
+ var _proto = AccountId2.prototype;
325
+ _proto.toString = function toString() {
326
+ return AccountId2.format(this.toJSON());
327
+ };
328
+ _proto.toJSON = function toJSON() {
329
+ return {
330
+ chainId: this.chainId.toJSON(),
331
+ address: this.address
332
+ };
333
+ };
334
+ return AccountId2;
335
+ })();
336
+ AccountId.spec = CAIP["10"];
337
+ var AssetName = /* @__PURE__ */ (function() {
338
+ function AssetName2(params) {
339
+ if (typeof params === "string") {
340
+ params = AssetName2.parse(params);
341
+ }
342
+ this.namespace = params.namespace;
343
+ this.reference = params.reference;
344
+ }
345
+ AssetName2.parse = function parse(id) {
346
+ if (!isValidId(id, this.spec)) {
347
+ throw new Error("Invalid " + this.spec.name + " provided: " + id);
348
+ }
349
+ return new AssetName2(getParams(id, this.spec)).toJSON();
350
+ };
351
+ AssetName2.format = function format(params) {
352
+ return joinParams(params, this.spec);
353
+ };
354
+ var _proto = AssetName2.prototype;
355
+ _proto.toString = function toString() {
356
+ return AssetName2.format(this.toJSON());
357
+ };
358
+ _proto.toJSON = function toJSON() {
359
+ return {
360
+ namespace: this.namespace,
361
+ reference: this.reference
362
+ };
363
+ };
364
+ return AssetName2;
365
+ })();
366
+ AssetName.spec = CAIP["19"].assetName;
367
+ var AssetType = /* @__PURE__ */ (function() {
368
+ function AssetType2(params) {
369
+ if (typeof params === "string") {
370
+ params = AssetType2.parse(params);
371
+ }
372
+ this.chainId = new ChainId(params.chainId);
373
+ this.assetName = new AssetName(params.assetName);
374
+ }
375
+ AssetType2.parse = function parse(id) {
376
+ if (!isValidId(id, this.spec)) {
377
+ throw new Error("Invalid " + this.spec.name + " provided: " + id);
378
+ }
379
+ return new AssetType2(getParams(id, this.spec)).toJSON();
380
+ };
381
+ AssetType2.format = function format(params) {
382
+ return joinParams(params, this.spec);
383
+ };
384
+ var _proto = AssetType2.prototype;
385
+ _proto.toString = function toString() {
386
+ return AssetType2.format(this.toJSON());
387
+ };
388
+ _proto.toJSON = function toJSON() {
389
+ return {
390
+ chainId: this.chainId.toJSON(),
391
+ assetName: this.assetName
392
+ };
393
+ };
394
+ return AssetType2;
395
+ })();
396
+ AssetType.spec = CAIP["19"].assetType;
397
+ var AssetId = /* @__PURE__ */ (function() {
398
+ function AssetId2(params) {
399
+ if (typeof params === "string") {
400
+ params = AssetId2.parse(params);
401
+ }
402
+ this.chainId = new ChainId(params.chainId);
403
+ this.assetName = new AssetName(params.assetName);
404
+ this.tokenId = params.tokenId;
132
405
  }
406
+ AssetId2.parse = function parse(id) {
407
+ if (!isValidId(id, this.spec)) {
408
+ throw new Error("Invalid " + this.spec.name + " provided: " + id);
409
+ }
410
+ return new AssetId2(getParams(id, this.spec)).toJSON();
411
+ };
412
+ AssetId2.format = function format(params) {
413
+ return joinParams(params, this.spec);
414
+ };
415
+ var _proto = AssetId2.prototype;
416
+ _proto.toString = function toString() {
417
+ return AssetId2.format(this.toJSON());
418
+ };
419
+ _proto.toJSON = function toJSON() {
420
+ return {
421
+ chainId: this.chainId.toJSON(),
422
+ assetName: this.assetName.toJSON(),
423
+ tokenId: this.tokenId
424
+ };
425
+ };
426
+ return AssetId2;
427
+ })();
428
+ AssetId.spec = CAIP["19"].assetId;
429
+
430
+ // ../ensnode-sdk/src/shared/zod-schemas.ts
431
+ import { isAddress as isAddress2, isHex, size } from "viem";
432
+ import { z } from "zod/v4";
433
+
434
+ // ../ensnode-sdk/src/shared/address.ts
435
+ function asLowerCaseAddress(address) {
436
+ return address.toLowerCase();
133
437
  }
134
438
 
135
- // src/encoding.ts
136
- import { getAddress, pad, size, slice, zeroAddress } from "viem";
137
- var ENCODED_REFERRER_BYTE_OFFSET = 12;
138
- var ENCODED_REFERRER_BYTE_LENGTH = 32;
139
- var EXPECTED_ENCODED_REFERRER_PADDING = pad("0x", {
140
- size: ENCODED_REFERRER_BYTE_OFFSET,
141
- dir: "left"
439
+ // ../ensnode-sdk/src/shared/zod-schemas.ts
440
+ var makeFiniteNonNegativeNumberSchema = (valueLabel = "Value") => z.number({
441
+ // NOTE: Zod's implementation of `number` automatically rejects NaN and Infinity values.
442
+ // and therefore the finite check is implicit.
443
+ error: `${valueLabel} must be a finite number.`
444
+ }).nonnegative({
445
+ error: `${valueLabel} must be a non-negative number (>=0).`
142
446
  });
143
- var ZERO_ENCODED_REFERRER = pad("0x", {
144
- size: ENCODED_REFERRER_BYTE_LENGTH,
145
- dir: "left"
447
+ var makeIntegerSchema = (valueLabel = "Value") => z.int({
448
+ error: `${valueLabel} must be an integer.`
146
449
  });
147
- function buildEncodedReferrer(address) {
148
- const lowercaseAddress = address.toLowerCase();
149
- return pad(lowercaseAddress, { size: ENCODED_REFERRER_BYTE_LENGTH, dir: "left" });
150
- }
151
- function decodeEncodedReferrer(encodedReferrer) {
152
- if (size(encodedReferrer) !== ENCODED_REFERRER_BYTE_LENGTH) {
450
+ var makePositiveIntegerSchema = (valueLabel = "Value") => makeIntegerSchema(valueLabel).positive({
451
+ error: `${valueLabel} must be a positive integer (>0).`
452
+ });
453
+ var makeNonNegativeIntegerSchema = (valueLabel = "Value") => makeIntegerSchema(valueLabel).nonnegative({
454
+ error: `${valueLabel} must be a non-negative integer (>=0).`
455
+ });
456
+ var makeDurationSchema = (valueLabel = "Value") => z.number({
457
+ error: `${valueLabel} must be a number.`
458
+ }).pipe(makeNonNegativeIntegerSchema(valueLabel));
459
+ var makeChainIdSchema = (valueLabel = "Chain ID") => makePositiveIntegerSchema(valueLabel).transform((val) => val);
460
+ var makeLowercaseAddressSchema = (valueLabel = "EVM address") => z.string().check((ctx) => {
461
+ if (!isAddress2(ctx.value)) {
462
+ ctx.issues.push({
463
+ code: "custom",
464
+ message: `${valueLabel} must be a valid EVM address`,
465
+ input: ctx.value
466
+ });
467
+ }
468
+ }).transform((val) => asLowerCaseAddress(val));
469
+ var makeUnixTimestampSchema = (valueLabel = "Timestamp") => makeIntegerSchema(valueLabel);
470
+ var makeAccountIdSchema = (valueLabel = "AccountId") => z.strictObject({
471
+ chainId: makeChainIdSchema(`${valueLabel} chain ID`),
472
+ address: makeLowercaseAddressSchema(`${valueLabel} address`)
473
+ });
474
+
475
+ // src/leaderboard-page.ts
476
+ var REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT = 25;
477
+ var REFERRERS_PER_LEADERBOARD_PAGE_MAX = 100;
478
+ var validateReferrerLeaderboardPageParams = (params) => {
479
+ if (params.page !== void 0 && !isPositiveInteger(params.page)) {
153
480
  throw new Error(
154
- `Encoded referrer value must be represented by ${ENCODED_REFERRER_BYTE_LENGTH} bytes.`
481
+ `Invalid ReferrerLeaderboardPageParams: ${params.page}. page must be a positive integer.`
155
482
  );
156
483
  }
157
- const padding = slice(encodedReferrer, 0, ENCODED_REFERRER_BYTE_OFFSET);
158
- if (padding !== EXPECTED_ENCODED_REFERRER_PADDING) {
159
- return zeroAddress;
484
+ if (params.recordsPerPage !== void 0 && !isPositiveInteger(params.recordsPerPage)) {
485
+ throw new Error(
486
+ `Invalid ReferrerLeaderboardPageParams: ${params.recordsPerPage}. recordsPerPage must be a positive integer.`
487
+ );
160
488
  }
161
- const decodedReferrer = slice(encodedReferrer, ENCODED_REFERRER_BYTE_OFFSET);
162
- try {
163
- return getAddress(decodedReferrer);
164
- } catch {
165
- throw new Error(`Decoded referrer value must be a valid EVM address.`);
489
+ if (params.recordsPerPage !== void 0 && params.recordsPerPage > REFERRERS_PER_LEADERBOARD_PAGE_MAX) {
490
+ throw new Error(
491
+ `Invalid ReferrerLeaderboardPageParams: ${params.recordsPerPage}. recordsPerPage must be less than or equal to ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}.`
492
+ );
166
493
  }
167
- }
494
+ };
495
+ var buildReferrerLeaderboardPageParams = (params) => {
496
+ const result = {
497
+ page: params.page ?? 1,
498
+ recordsPerPage: params.recordsPerPage ?? REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT
499
+ };
500
+ validateReferrerLeaderboardPageParams(result);
501
+ return result;
502
+ };
503
+ var validateReferrerLeaderboardPageContext = (context) => {
504
+ validateReferrerLeaderboardPageParams(context);
505
+ if (!isNonNegativeInteger(context.totalRecords)) {
506
+ throw new Error(
507
+ `Invalid ReferrerLeaderboardPageContext: total must be a non-negative integer but is ${context.totalRecords}.`
508
+ );
509
+ }
510
+ const startIndex = (context.page - 1) * context.recordsPerPage;
511
+ const endIndex = startIndex + context.recordsPerPage;
512
+ if (!context.hasNext && endIndex < context.totalRecords) {
513
+ throw new Error(
514
+ `Invalid ReferrerLeaderboardPageContext: if hasNext is false, endIndex (${endIndex}) must be greater than or equal to total (${context.totalRecords}).`
515
+ );
516
+ } else if (context.hasNext && context.page * context.recordsPerPage >= context.totalRecords) {
517
+ throw new Error(
518
+ `Invalid ReferrerLeaderboardPageContext: if hasNext is true, endIndex (${endIndex}) must be less than total (${context.totalRecords}).`
519
+ );
520
+ }
521
+ if (!context.hasPrev && context.page !== 1) {
522
+ throw new Error(
523
+ `Invalid ReferrerLeaderboardPageContext: if hasPrev is false, page must be the first page (1) but is ${context.page}.`
524
+ );
525
+ } else if (context.hasPrev && context.page === 1) {
526
+ throw new Error(
527
+ `Invalid ReferrerLeaderboardPageContext: if hasPrev is true, page must not be the first page (1) but is ${context.page}.`
528
+ );
529
+ }
530
+ };
531
+ var buildReferrerLeaderboardPageContext = (optionalParams, leaderboard) => {
532
+ const materializedParams = buildReferrerLeaderboardPageParams(optionalParams);
533
+ const totalRecords = leaderboard.referrers.size;
534
+ const totalPages = Math.max(1, Math.ceil(totalRecords / materializedParams.recordsPerPage));
535
+ if (materializedParams.page > totalPages) {
536
+ throw new Error(
537
+ `Invalid ReferrerLeaderboardPageContext: page ${materializedParams.page} exceeds total pages ${totalPages}.`
538
+ );
539
+ }
540
+ if (totalRecords === 0) {
541
+ return {
542
+ ...materializedParams,
543
+ totalRecords: 0,
544
+ totalPages: 1,
545
+ hasNext: false,
546
+ hasPrev: false,
547
+ startIndex: void 0,
548
+ endIndex: void 0
549
+ };
550
+ }
551
+ const startIndex = (materializedParams.page - 1) * materializedParams.recordsPerPage;
552
+ const maxTheoreticalIndexOnPage = startIndex + (materializedParams.recordsPerPage - 1);
553
+ const endIndex = Math.min(maxTheoreticalIndexOnPage, totalRecords - 1);
554
+ const hasNext = maxTheoreticalIndexOnPage < totalRecords - 1;
555
+ const hasPrev = materializedParams.page > 1;
556
+ const result = {
557
+ ...materializedParams,
558
+ totalRecords,
559
+ totalPages,
560
+ hasNext,
561
+ hasPrev,
562
+ startIndex,
563
+ endIndex
564
+ };
565
+ validateReferrerLeaderboardPageContext(result);
566
+ return result;
567
+ };
568
+ var getReferrerLeaderboardPage = (pageParams, leaderboard) => {
569
+ const pageContext = buildReferrerLeaderboardPageContext(pageParams, leaderboard);
570
+ let referrers;
571
+ if (pageContext.totalRecords > 0 && typeof pageContext.startIndex !== "undefined" && typeof pageContext.endIndex !== "undefined") {
572
+ referrers = Array.from(leaderboard.referrers.values()).slice(
573
+ pageContext.startIndex,
574
+ pageContext.endIndex + 1
575
+ // For `slice`, this is exclusive of the element at the index 'end'. We need it to be inclusive, hence plus one.
576
+ );
577
+ } else {
578
+ referrers = [];
579
+ }
580
+ return {
581
+ rules: leaderboard.rules,
582
+ referrers,
583
+ aggregatedMetrics: leaderboard.aggregatedMetrics,
584
+ pageContext,
585
+ accurateAsOf: leaderboard.accurateAsOf
586
+ };
587
+ };
168
588
 
169
589
  // src/rank.ts
170
590
  var validateReferrerRank = (rank) => {
@@ -366,6 +786,624 @@ var buildUnrankedReferrerMetrics = (referrer) => {
366
786
  return result;
367
787
  };
368
788
 
789
+ // src/referrer-detail.ts
790
+ var ReferrerDetailTypeIds = {
791
+ /**
792
+ * Represents a referrer who is ranked on the leaderboard.
793
+ */
794
+ Ranked: "ranked",
795
+ /**
796
+ * Represents a referrer who is not ranked on the leaderboard.
797
+ */
798
+ Unranked: "unranked"
799
+ };
800
+ var getReferrerDetail = (referrer, leaderboard) => {
801
+ const awardedReferrerMetrics = leaderboard.referrers.get(referrer);
802
+ if (awardedReferrerMetrics) {
803
+ return {
804
+ type: ReferrerDetailTypeIds.Ranked,
805
+ rules: leaderboard.rules,
806
+ referrer: awardedReferrerMetrics,
807
+ aggregatedMetrics: leaderboard.aggregatedMetrics,
808
+ accurateAsOf: leaderboard.accurateAsOf
809
+ };
810
+ }
811
+ return {
812
+ type: ReferrerDetailTypeIds.Unranked,
813
+ rules: leaderboard.rules,
814
+ referrer: buildUnrankedReferrerMetrics(referrer),
815
+ aggregatedMetrics: leaderboard.aggregatedMetrics,
816
+ accurateAsOf: leaderboard.accurateAsOf
817
+ };
818
+ };
819
+
820
+ // src/api/types.ts
821
+ var ReferrerLeaderboardPageResponseCodes = {
822
+ /**
823
+ * Represents that the requested referrer leaderboard page is available.
824
+ */
825
+ Ok: "ok",
826
+ /**
827
+ * Represents that the referrer leaderboard data is not available.
828
+ */
829
+ Error: "error"
830
+ };
831
+ var ReferrerDetailResponseCodes = {
832
+ /**
833
+ * Represents that the referrer detail data is available.
834
+ */
835
+ Ok: "ok",
836
+ /**
837
+ * Represents that an error occurred while fetching the data.
838
+ */
839
+ Error: "error"
840
+ };
841
+
842
+ // src/api/zod-schemas.ts
843
+ var makeRevenueContributionSchema = (valueLabel = "RevenueContribution") => z2.coerce.bigint({
844
+ error: `${valueLabel} must represent a bigint.`
845
+ }).nonnegative({
846
+ error: `${valueLabel} must not be negative.`
847
+ });
848
+ var makeReferralProgramRulesSchema = (valueLabel = "ReferralProgramRules") => z2.object({
849
+ totalAwardPoolValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.totalAwardPoolValue`),
850
+ maxQualifiedReferrers: makeNonNegativeIntegerSchema(`${valueLabel}.maxQualifiedReferrers`),
851
+ startTime: makeUnixTimestampSchema(`${valueLabel}.startTime`),
852
+ endTime: makeUnixTimestampSchema(`${valueLabel}.endTime`),
853
+ subregistryId: makeAccountIdSchema(`${valueLabel}.subregistryId`)
854
+ });
855
+ var makeAwardedReferrerMetricsSchema = (valueLabel = "AwardedReferrerMetrics") => z2.object({
856
+ referrer: makeLowercaseAddressSchema(`${valueLabel}.referrer`),
857
+ totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),
858
+ totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),
859
+ totalRevenueContribution: makeRevenueContributionSchema(
860
+ `${valueLabel}.totalRevenueContribution`
861
+ ),
862
+ score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),
863
+ rank: makePositiveIntegerSchema(`${valueLabel}.rank`),
864
+ isQualified: z2.boolean(),
865
+ finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(
866
+ 1,
867
+ `${valueLabel}.finalScoreBoost must be <= 1`
868
+ ),
869
+ finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),
870
+ awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(
871
+ 1,
872
+ `${valueLabel}.awardPoolShare must be <= 1`
873
+ ),
874
+ awardPoolApproxValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolApproxValue`)
875
+ });
876
+ var makeUnrankedReferrerMetricsSchema = (valueLabel = "UnrankedReferrerMetrics") => z2.object({
877
+ referrer: makeLowercaseAddressSchema(`${valueLabel}.referrer`),
878
+ totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),
879
+ totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),
880
+ totalRevenueContribution: makeRevenueContributionSchema(
881
+ `${valueLabel}.totalRevenueContribution`
882
+ ),
883
+ score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),
884
+ rank: z2.null(),
885
+ isQualified: z2.literal(false),
886
+ finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(
887
+ 1,
888
+ `${valueLabel}.finalScoreBoost must be <= 1`
889
+ ),
890
+ finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),
891
+ awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(
892
+ 1,
893
+ `${valueLabel}.awardPoolShare must be <= 1`
894
+ ),
895
+ awardPoolApproxValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolApproxValue`)
896
+ });
897
+ var makeAggregatedReferrerMetricsSchema = (valueLabel = "AggregatedReferrerMetrics") => z2.object({
898
+ grandTotalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.grandTotalReferrals`),
899
+ grandTotalIncrementalDuration: makeDurationSchema(
900
+ `${valueLabel}.grandTotalIncrementalDuration`
901
+ ),
902
+ grandTotalRevenueContribution: makeRevenueContributionSchema(
903
+ `${valueLabel}.grandTotalRevenueContribution`
904
+ ),
905
+ grandTotalQualifiedReferrersFinalScore: makeFiniteNonNegativeNumberSchema(
906
+ `${valueLabel}.grandTotalQualifiedReferrersFinalScore`
907
+ ),
908
+ minFinalScoreToQualify: makeFiniteNonNegativeNumberSchema(
909
+ `${valueLabel}.minFinalScoreToQualify`
910
+ )
911
+ });
912
+ var makeReferrerLeaderboardPageContextSchema = (valueLabel = "ReferrerLeaderboardPageContext") => z2.object({
913
+ page: makePositiveIntegerSchema(`${valueLabel}.page`),
914
+ recordsPerPage: makePositiveIntegerSchema(`${valueLabel}.recordsPerPage`).max(
915
+ REFERRERS_PER_LEADERBOARD_PAGE_MAX,
916
+ `${valueLabel}.recordsPerPage must not exceed ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}`
917
+ ),
918
+ totalRecords: makeNonNegativeIntegerSchema(`${valueLabel}.totalRecords`),
919
+ totalPages: makePositiveIntegerSchema(`${valueLabel}.totalPages`),
920
+ hasNext: z2.boolean(),
921
+ hasPrev: z2.boolean(),
922
+ startIndex: z2.optional(makeNonNegativeIntegerSchema(`${valueLabel}.startIndex`)),
923
+ endIndex: z2.optional(makeNonNegativeIntegerSchema(`${valueLabel}.endIndex`))
924
+ });
925
+ var makeReferrerLeaderboardPageSchema = (valueLabel = "ReferrerLeaderboardPage") => z2.object({
926
+ rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),
927
+ referrers: z2.array(makeAwardedReferrerMetricsSchema(`${valueLabel}.referrers[record]`)),
928
+ aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),
929
+ pageContext: makeReferrerLeaderboardPageContextSchema(`${valueLabel}.pageContext`),
930
+ accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
931
+ });
932
+ var makeReferrerLeaderboardPageResponseOkSchema = (valueLabel = "ReferrerLeaderboardPageResponseOk") => z2.object({
933
+ responseCode: z2.literal(ReferrerLeaderboardPageResponseCodes.Ok),
934
+ data: makeReferrerLeaderboardPageSchema(`${valueLabel}.data`)
935
+ });
936
+ var makeReferrerLeaderboardPageResponseErrorSchema = (_valueLabel = "ReferrerLeaderboardPageResponseError") => z2.object({
937
+ responseCode: z2.literal(ReferrerLeaderboardPageResponseCodes.Error),
938
+ error: z2.string(),
939
+ errorMessage: z2.string()
940
+ });
941
+ var makeReferrerLeaderboardPageResponseSchema = (valueLabel = "ReferrerLeaderboardPageResponse") => z2.union([
942
+ makeReferrerLeaderboardPageResponseOkSchema(valueLabel),
943
+ makeReferrerLeaderboardPageResponseErrorSchema(valueLabel)
944
+ ]);
945
+ var makeReferrerDetailRankedSchema = (valueLabel = "ReferrerDetailRanked") => z2.object({
946
+ type: z2.literal(ReferrerDetailTypeIds.Ranked),
947
+ rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),
948
+ referrer: makeAwardedReferrerMetricsSchema(`${valueLabel}.referrer`),
949
+ aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),
950
+ accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
951
+ });
952
+ var makeReferrerDetailUnrankedSchema = (valueLabel = "ReferrerDetailUnranked") => z2.object({
953
+ type: z2.literal(ReferrerDetailTypeIds.Unranked),
954
+ rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),
955
+ referrer: makeUnrankedReferrerMetricsSchema(`${valueLabel}.referrer`),
956
+ aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),
957
+ accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
958
+ });
959
+ var makeReferrerDetailResponseOkSchema = (valueLabel = "ReferrerDetailResponse") => z2.object({
960
+ responseCode: z2.literal(ReferrerDetailResponseCodes.Ok),
961
+ data: z2.union([
962
+ makeReferrerDetailRankedSchema(`${valueLabel}.data`),
963
+ makeReferrerDetailUnrankedSchema(`${valueLabel}.data`)
964
+ ])
965
+ });
966
+ var makeReferrerDetailResponseErrorSchema = (_valueLabel = "ReferrerDetailResponse") => z2.object({
967
+ responseCode: z2.literal(ReferrerDetailResponseCodes.Error),
968
+ error: z2.string(),
969
+ errorMessage: z2.string()
970
+ });
971
+ var makeReferrerDetailResponseSchema = (valueLabel = "ReferrerDetailResponse") => z2.union([
972
+ makeReferrerDetailResponseOkSchema(valueLabel),
973
+ makeReferrerDetailResponseErrorSchema(valueLabel)
974
+ ]);
975
+
976
+ // src/api/deserialize.ts
977
+ function deserializeRevenueContribution(value) {
978
+ return BigInt(value);
979
+ }
980
+ function deserializeReferralProgramRules(rules) {
981
+ return rules;
982
+ }
983
+ function deserializeAwardedReferrerMetrics(metrics) {
984
+ return {
985
+ referrer: metrics.referrer,
986
+ totalReferrals: metrics.totalReferrals,
987
+ totalIncrementalDuration: metrics.totalIncrementalDuration,
988
+ totalRevenueContribution: deserializeRevenueContribution(metrics.totalRevenueContribution),
989
+ score: metrics.score,
990
+ rank: metrics.rank,
991
+ isQualified: metrics.isQualified,
992
+ finalScoreBoost: metrics.finalScoreBoost,
993
+ finalScore: metrics.finalScore,
994
+ awardPoolShare: metrics.awardPoolShare,
995
+ awardPoolApproxValue: metrics.awardPoolApproxValue
996
+ };
997
+ }
998
+ function deserializeUnrankedReferrerMetrics(metrics) {
999
+ return {
1000
+ referrer: metrics.referrer,
1001
+ totalReferrals: metrics.totalReferrals,
1002
+ totalIncrementalDuration: metrics.totalIncrementalDuration,
1003
+ totalRevenueContribution: deserializeRevenueContribution(metrics.totalRevenueContribution),
1004
+ score: metrics.score,
1005
+ rank: metrics.rank,
1006
+ isQualified: metrics.isQualified,
1007
+ finalScoreBoost: metrics.finalScoreBoost,
1008
+ finalScore: metrics.finalScore,
1009
+ awardPoolShare: metrics.awardPoolShare,
1010
+ awardPoolApproxValue: metrics.awardPoolApproxValue
1011
+ };
1012
+ }
1013
+ function deserializeAggregatedReferrerMetrics(metrics) {
1014
+ return {
1015
+ grandTotalReferrals: metrics.grandTotalReferrals,
1016
+ grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,
1017
+ grandTotalRevenueContribution: deserializeRevenueContribution(
1018
+ metrics.grandTotalRevenueContribution
1019
+ ),
1020
+ grandTotalQualifiedReferrersFinalScore: metrics.grandTotalQualifiedReferrersFinalScore,
1021
+ minFinalScoreToQualify: metrics.minFinalScoreToQualify
1022
+ };
1023
+ }
1024
+ function deserializeReferrerLeaderboardPage(page) {
1025
+ return {
1026
+ rules: deserializeReferralProgramRules(page.rules),
1027
+ referrers: page.referrers.map(deserializeAwardedReferrerMetrics),
1028
+ aggregatedMetrics: deserializeAggregatedReferrerMetrics(page.aggregatedMetrics),
1029
+ pageContext: page.pageContext,
1030
+ accurateAsOf: page.accurateAsOf
1031
+ };
1032
+ }
1033
+ function deserializeReferrerDetailRanked(detail) {
1034
+ return {
1035
+ type: detail.type,
1036
+ rules: deserializeReferralProgramRules(detail.rules),
1037
+ referrer: deserializeAwardedReferrerMetrics(detail.referrer),
1038
+ aggregatedMetrics: deserializeAggregatedReferrerMetrics(detail.aggregatedMetrics),
1039
+ accurateAsOf: detail.accurateAsOf
1040
+ };
1041
+ }
1042
+ function deserializeReferrerDetailUnranked(detail) {
1043
+ return {
1044
+ type: detail.type,
1045
+ rules: deserializeReferralProgramRules(detail.rules),
1046
+ referrer: deserializeUnrankedReferrerMetrics(detail.referrer),
1047
+ aggregatedMetrics: deserializeAggregatedReferrerMetrics(detail.aggregatedMetrics),
1048
+ accurateAsOf: detail.accurateAsOf
1049
+ };
1050
+ }
1051
+ function deserializeReferrerLeaderboardPageResponse(maybeResponse, valueLabel) {
1052
+ let deserialized;
1053
+ switch (maybeResponse.responseCode) {
1054
+ case "ok": {
1055
+ deserialized = {
1056
+ responseCode: maybeResponse.responseCode,
1057
+ data: deserializeReferrerLeaderboardPage(maybeResponse.data)
1058
+ };
1059
+ break;
1060
+ }
1061
+ case "error":
1062
+ deserialized = maybeResponse;
1063
+ break;
1064
+ }
1065
+ const schema = makeReferrerLeaderboardPageResponseSchema(valueLabel);
1066
+ const parsed = schema.safeParse(deserialized);
1067
+ if (parsed.error) {
1068
+ throw new Error(
1069
+ `Cannot deserialize SerializedReferrerLeaderboardPageResponse:
1070
+ ${prettifyError(parsed.error)}
1071
+ `
1072
+ );
1073
+ }
1074
+ return parsed.data;
1075
+ }
1076
+ function deserializeReferrerDetailResponse(maybeResponse, valueLabel) {
1077
+ let deserialized;
1078
+ switch (maybeResponse.responseCode) {
1079
+ case "ok": {
1080
+ switch (maybeResponse.data.type) {
1081
+ case "ranked":
1082
+ deserialized = {
1083
+ responseCode: maybeResponse.responseCode,
1084
+ data: deserializeReferrerDetailRanked(maybeResponse.data)
1085
+ };
1086
+ break;
1087
+ case "unranked":
1088
+ deserialized = {
1089
+ responseCode: maybeResponse.responseCode,
1090
+ data: deserializeReferrerDetailUnranked(maybeResponse.data)
1091
+ };
1092
+ break;
1093
+ }
1094
+ break;
1095
+ }
1096
+ case "error":
1097
+ deserialized = maybeResponse;
1098
+ break;
1099
+ }
1100
+ const schema = makeReferrerDetailResponseSchema(valueLabel);
1101
+ const parsed = schema.safeParse(deserialized);
1102
+ if (parsed.error) {
1103
+ throw new Error(`Cannot deserialize ReferrerDetailResponse:
1104
+ ${prettifyError(parsed.error)}
1105
+ `);
1106
+ }
1107
+ return parsed.data;
1108
+ }
1109
+
1110
+ // src/api/serialize.ts
1111
+ function serializeRevenueContribution(revenueContribution) {
1112
+ return revenueContribution.toString();
1113
+ }
1114
+ function serializeReferralProgramRules(rules) {
1115
+ return rules;
1116
+ }
1117
+ function serializeAwardedReferrerMetrics(metrics) {
1118
+ return {
1119
+ referrer: metrics.referrer,
1120
+ totalReferrals: metrics.totalReferrals,
1121
+ totalIncrementalDuration: metrics.totalIncrementalDuration,
1122
+ totalRevenueContribution: serializeRevenueContribution(metrics.totalRevenueContribution),
1123
+ score: metrics.score,
1124
+ rank: metrics.rank,
1125
+ isQualified: metrics.isQualified,
1126
+ finalScoreBoost: metrics.finalScoreBoost,
1127
+ finalScore: metrics.finalScore,
1128
+ awardPoolShare: metrics.awardPoolShare,
1129
+ awardPoolApproxValue: metrics.awardPoolApproxValue
1130
+ };
1131
+ }
1132
+ function serializeUnrankedReferrerMetrics(metrics) {
1133
+ return {
1134
+ referrer: metrics.referrer,
1135
+ totalReferrals: metrics.totalReferrals,
1136
+ totalIncrementalDuration: metrics.totalIncrementalDuration,
1137
+ totalRevenueContribution: serializeRevenueContribution(metrics.totalRevenueContribution),
1138
+ score: metrics.score,
1139
+ rank: metrics.rank,
1140
+ isQualified: metrics.isQualified,
1141
+ finalScoreBoost: metrics.finalScoreBoost,
1142
+ finalScore: metrics.finalScore,
1143
+ awardPoolShare: metrics.awardPoolShare,
1144
+ awardPoolApproxValue: metrics.awardPoolApproxValue
1145
+ };
1146
+ }
1147
+ function serializeAggregatedReferrerMetrics(metrics) {
1148
+ return {
1149
+ grandTotalReferrals: metrics.grandTotalReferrals,
1150
+ grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,
1151
+ grandTotalRevenueContribution: serializeRevenueContribution(
1152
+ metrics.grandTotalRevenueContribution
1153
+ ),
1154
+ grandTotalQualifiedReferrersFinalScore: metrics.grandTotalQualifiedReferrersFinalScore,
1155
+ minFinalScoreToQualify: metrics.minFinalScoreToQualify
1156
+ };
1157
+ }
1158
+ function serializeReferrerLeaderboardPage(page) {
1159
+ return {
1160
+ rules: serializeReferralProgramRules(page.rules),
1161
+ referrers: page.referrers.map(serializeAwardedReferrerMetrics),
1162
+ aggregatedMetrics: serializeAggregatedReferrerMetrics(page.aggregatedMetrics),
1163
+ pageContext: page.pageContext,
1164
+ accurateAsOf: page.accurateAsOf
1165
+ };
1166
+ }
1167
+ function serializeReferrerDetailRanked(detail) {
1168
+ return {
1169
+ type: detail.type,
1170
+ rules: serializeReferralProgramRules(detail.rules),
1171
+ referrer: serializeAwardedReferrerMetrics(detail.referrer),
1172
+ aggregatedMetrics: serializeAggregatedReferrerMetrics(detail.aggregatedMetrics),
1173
+ accurateAsOf: detail.accurateAsOf
1174
+ };
1175
+ }
1176
+ function serializeReferrerDetailUnranked(detail) {
1177
+ return {
1178
+ type: detail.type,
1179
+ rules: serializeReferralProgramRules(detail.rules),
1180
+ referrer: serializeUnrankedReferrerMetrics(detail.referrer),
1181
+ aggregatedMetrics: serializeAggregatedReferrerMetrics(detail.aggregatedMetrics),
1182
+ accurateAsOf: detail.accurateAsOf
1183
+ };
1184
+ }
1185
+ function serializeReferrerLeaderboardPageResponse(response) {
1186
+ switch (response.responseCode) {
1187
+ case ReferrerLeaderboardPageResponseCodes.Ok:
1188
+ return {
1189
+ responseCode: response.responseCode,
1190
+ data: serializeReferrerLeaderboardPage(response.data)
1191
+ };
1192
+ case ReferrerLeaderboardPageResponseCodes.Error:
1193
+ return response;
1194
+ }
1195
+ }
1196
+ function serializeReferrerDetailResponse(response) {
1197
+ switch (response.responseCode) {
1198
+ case ReferrerDetailResponseCodes.Ok:
1199
+ switch (response.data.type) {
1200
+ case "ranked":
1201
+ return {
1202
+ responseCode: response.responseCode,
1203
+ data: serializeReferrerDetailRanked(response.data)
1204
+ };
1205
+ case "unranked":
1206
+ return {
1207
+ responseCode: response.responseCode,
1208
+ data: serializeReferrerDetailUnranked(response.data)
1209
+ };
1210
+ }
1211
+ break;
1212
+ case ReferrerDetailResponseCodes.Error:
1213
+ return response;
1214
+ }
1215
+ }
1216
+
1217
+ // src/client.ts
1218
+ var DEFAULT_ENSNODE_API_URL = "https://api.alpha.ensnode.io";
1219
+ var ENSReferralsClient = class _ENSReferralsClient {
1220
+ options;
1221
+ static defaultOptions() {
1222
+ return {
1223
+ url: new URL(DEFAULT_ENSNODE_API_URL)
1224
+ };
1225
+ }
1226
+ constructor(options = {}) {
1227
+ this.options = {
1228
+ ..._ENSReferralsClient.defaultOptions(),
1229
+ ...options
1230
+ };
1231
+ }
1232
+ getOptions() {
1233
+ return Object.freeze({
1234
+ url: new URL(this.options.url.href)
1235
+ });
1236
+ }
1237
+ /**
1238
+ * Fetch Referrer Leaderboard Page
1239
+ *
1240
+ * Retrieves a paginated list of referrer leaderboard metrics with contribution percentages.
1241
+ * Each referrer's contribution is calculated as a percentage of the grand totals across all referrers.
1242
+ *
1243
+ * @param request - Pagination parameters
1244
+ * @param request.page - The page number to retrieve (1-indexed, default: 1)
1245
+ * @param request.recordsPerPage - Number of records per page (default: 25, max: 100)
1246
+ * @returns {ReferrerLeaderboardPageResponse}
1247
+ *
1248
+ * @throws if the ENSNode request fails
1249
+ * @throws if the ENSNode API returns an error response
1250
+ * @throws if the ENSNode response breaks required invariants
1251
+ *
1252
+ * @example
1253
+ * ```typescript
1254
+ * // Get first page with default page size (25 records)
1255
+ * const response = await client.getReferrerLeaderboardPage();
1256
+ * if (response.responseCode === ReferrerLeaderboardPageResponseCodes.Ok) {
1257
+ * const {
1258
+ * aggregatedMetrics,
1259
+ * referrers,
1260
+ * rules,
1261
+ * pageContext,
1262
+ * updatedAt
1263
+ * } = response.data;
1264
+ * console.log(aggregatedMetrics);
1265
+ * console.log(referrers);
1266
+ * console.log(rules);
1267
+ * console.log(updatedAt);
1268
+ * console.log(`Page ${pageContext.page} of ${pageContext.totalPages}`);
1269
+ * }
1270
+ * ```
1271
+ *
1272
+ * @example
1273
+ * ```typescript
1274
+ * // Get second page with 50 records per page
1275
+ * const response = await client.getReferrerLeaderboardPage({ page: 2, recordsPerPage: 50 });
1276
+ * ```
1277
+ *
1278
+ * @example
1279
+ * ```typescript
1280
+ * // Handle error response, ie. when Referrer Leaderboard is not currently available.
1281
+ * const response = await client.getReferrerLeaderboardPage();
1282
+ *
1283
+ * if (response.responseCode === ReferrerLeaderboardPageResponseCodes.Error) {
1284
+ * console.error(response.error);
1285
+ * console.error(response.errorMessage);
1286
+ * }
1287
+ * ```
1288
+ */
1289
+ async getReferrerLeaderboardPage(request) {
1290
+ const url = new URL(`/ensanalytics/referrers`, this.options.url);
1291
+ if (request?.page) url.searchParams.set("page", request.page.toString());
1292
+ if (request?.recordsPerPage)
1293
+ url.searchParams.set("recordsPerPage", request.recordsPerPage.toString());
1294
+ const response = await fetch(url);
1295
+ let responseData;
1296
+ try {
1297
+ responseData = await response.json();
1298
+ } catch {
1299
+ throw new Error("Malformed response data: invalid JSON");
1300
+ }
1301
+ return deserializeReferrerLeaderboardPageResponse(
1302
+ responseData
1303
+ );
1304
+ }
1305
+ /**
1306
+ * Fetch Referrer Detail
1307
+ *
1308
+ * Retrieves detailed information about a specific referrer, whether they are on the
1309
+ * leaderboard or not.
1310
+ *
1311
+ * The response data is a discriminated union type with a `type` field:
1312
+ *
1313
+ * **For referrers on the leaderboard** (`ReferrerDetailRanked`):
1314
+ * - `type`: {@link ReferrerDetailTypeIds.Ranked}
1315
+ * - `referrer`: The `AwardedReferrerMetrics` from @namehash/ens-referrals
1316
+ * - `rules`: The referral program rules
1317
+ * - `aggregatedMetrics`: Aggregated metrics for all referrers on the leaderboard
1318
+ * - `accurateAsOf`: Unix timestamp indicating when the data was last updated
1319
+ *
1320
+ * **For referrers NOT on the leaderboard** (`ReferrerDetailUnranked`):
1321
+ * - `type`: {@link ReferrerDetailTypeIds.Unranked}
1322
+ * - `referrer`: The `UnrankedReferrerMetrics` from @namehash/ens-referrals
1323
+ * - `rules`: The referral program rules
1324
+ * - `aggregatedMetrics`: Aggregated metrics for all referrers on the leaderboard
1325
+ * - `accurateAsOf`: Unix timestamp indicating when the data was last updated
1326
+ *
1327
+ * @see {@link https://www.npmjs.com/package/@namehash/ens-referrals|@namehash/ens-referrals} for calculation details
1328
+ *
1329
+ * @param request The referrer address to query
1330
+ * @returns {ReferrerDetailResponse} Returns the referrer detail response
1331
+ *
1332
+ * @throws if the ENSNode request fails
1333
+ * @throws if the response data is malformed
1334
+ *
1335
+ * @example
1336
+ * ```typescript
1337
+ * // Get referrer detail for a specific address
1338
+ * const response = await client.getReferrerDetail({
1339
+ * referrer: "0x1234567890123456789012345678901234567890"
1340
+ * });
1341
+ * if (response.responseCode === ReferrerDetailResponseCodes.Ok) {
1342
+ * const { type, referrer, rules, aggregatedMetrics, accurateAsOf } = response.data;
1343
+ * console.log(type); // ReferrerDetailTypeIds.Ranked or ReferrerDetailTypeIds.Unranked
1344
+ * console.log(referrer);
1345
+ * console.log(accurateAsOf);
1346
+ * }
1347
+ * ```
1348
+ *
1349
+ * @example
1350
+ * ```typescript
1351
+ * // Use discriminated union to check if referrer is ranked
1352
+ * const response = await client.getReferrerDetail({
1353
+ * referrer: "0x1234567890123456789012345678901234567890"
1354
+ * });
1355
+ * if (response.responseCode === ReferrerDetailResponseCodes.Ok) {
1356
+ * if (response.data.type === ReferrerDetailTypeIds.Ranked) {
1357
+ * // TypeScript knows this is ReferrerDetailRanked
1358
+ * console.log(`Rank: ${response.data.referrer.rank}`);
1359
+ * console.log(`Qualified: ${response.data.referrer.isQualified}`);
1360
+ * console.log(`Award Pool Share: ${response.data.referrer.awardPoolShare * 100}%`);
1361
+ * } else {
1362
+ * // TypeScript knows this is ReferrerDetailUnranked
1363
+ * console.log("Referrer is not on the leaderboard (no referrals yet)");
1364
+ * }
1365
+ * }
1366
+ * ```
1367
+ *
1368
+ * @example
1369
+ * ```typescript
1370
+ * // Handle error response, ie. when Referrer Detail is not currently available.
1371
+ * const response = await client.getReferrerDetail({
1372
+ * referrer: "0x1234567890123456789012345678901234567890"
1373
+ * });
1374
+ *
1375
+ * if (response.responseCode === ReferrerDetailResponseCodes.Error) {
1376
+ * console.error(response.error);
1377
+ * console.error(response.errorMessage);
1378
+ * }
1379
+ * ```
1380
+ */
1381
+ async getReferrerDetail(request) {
1382
+ const url = new URL(
1383
+ `/ensanalytics/referrers/${encodeURIComponent(request.referrer)}`,
1384
+ this.options.url
1385
+ );
1386
+ const response = await fetch(url);
1387
+ let responseData;
1388
+ try {
1389
+ responseData = await response.json();
1390
+ } catch {
1391
+ throw new Error("Malformed response data: invalid JSON");
1392
+ }
1393
+ return deserializeReferrerDetailResponse(responseData);
1394
+ }
1395
+ };
1396
+
1397
+ // src/currency.ts
1398
+ function isValidUSDQuantity(value) {
1399
+ return isFiniteNonNegativeNumber(value);
1400
+ }
1401
+ function validateUSDQuantity(value) {
1402
+ if (!isValidUSDQuantity(value)) {
1403
+ throw new Error(`Invalid USD quantity: ${value}.`);
1404
+ }
1405
+ }
1406
+
369
1407
  // src/leaderboard.ts
370
1408
  var buildReferrerLeaderboard = (allReferrers, rules, accurateAsOf) => {
371
1409
  const uniqueReferrers = allReferrers.map((referrer) => referrer.referrer);
@@ -401,159 +1439,14 @@ var buildReferrerLeaderboard = (allReferrers, rules, accurateAsOf) => {
401
1439
  };
402
1440
  };
403
1441
 
404
- // src/leaderboard-page.ts
405
- var REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT = 25;
406
- var REFERRERS_PER_LEADERBOARD_PAGE_MAX = 100;
407
- var validateReferrerLeaderboardPageParams = (params) => {
408
- if (params.page !== void 0 && !isPositiveInteger(params.page)) {
409
- throw new Error(
410
- `Invalid ReferrerLeaderboardPageParams: ${params.page}. page must be a positive integer.`
411
- );
412
- }
413
- if (params.recordsPerPage !== void 0 && !isPositiveInteger(params.recordsPerPage)) {
414
- throw new Error(
415
- `Invalid ReferrerLeaderboardPageParams: ${params.recordsPerPage}. recordsPerPage must be a positive integer.`
416
- );
417
- }
418
- if (params.recordsPerPage !== void 0 && params.recordsPerPage > REFERRERS_PER_LEADERBOARD_PAGE_MAX) {
419
- throw new Error(
420
- `Invalid ReferrerLeaderboardPageParams: ${params.recordsPerPage}. recordsPerPage must be less than or equal to ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}.`
421
- );
422
- }
423
- };
424
- var buildReferrerLeaderboardPageParams = (params) => {
425
- const result = {
426
- page: params.page ?? 1,
427
- recordsPerPage: params.recordsPerPage ?? REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT
428
- };
429
- validateReferrerLeaderboardPageParams(result);
430
- return result;
431
- };
432
- var validateReferrerLeaderboardPageContext = (context) => {
433
- validateReferrerLeaderboardPageParams(context);
434
- if (!isNonNegativeInteger(context.totalRecords)) {
435
- throw new Error(
436
- `Invalid ReferrerLeaderboardPageContext: total must be a non-negative integer but is ${context.totalRecords}.`
437
- );
438
- }
439
- const startIndex = (context.page - 1) * context.recordsPerPage;
440
- const endIndex = startIndex + context.recordsPerPage;
441
- if (!context.hasNext && endIndex < context.totalRecords) {
442
- throw new Error(
443
- `Invalid ReferrerLeaderboardPageContext: if hasNext is false, endIndex (${endIndex}) must be greater than or equal to total (${context.totalRecords}).`
444
- );
445
- } else if (context.hasNext && context.page * context.recordsPerPage >= context.totalRecords) {
446
- throw new Error(
447
- `Invalid ReferrerLeaderboardPageContext: if hasNext is true, endIndex (${endIndex}) must be less than total (${context.totalRecords}).`
448
- );
449
- }
450
- if (!context.hasPrev && context.page !== 1) {
451
- throw new Error(
452
- `Invalid ReferrerLeaderboardPageContext: if hasPrev is false, page must be the first page (1) but is ${context.page}.`
453
- );
454
- } else if (context.hasPrev && context.page === 1) {
455
- throw new Error(
456
- `Invalid ReferrerLeaderboardPageContext: if hasPrev is true, page must not be the first page (1) but is ${context.page}.`
457
- );
458
- }
459
- };
460
- var buildReferrerLeaderboardPageContext = (optionalParams, leaderboard) => {
461
- const materializedParams = buildReferrerLeaderboardPageParams(optionalParams);
462
- const totalRecords = leaderboard.referrers.size;
463
- const totalPages = Math.max(1, Math.ceil(totalRecords / materializedParams.recordsPerPage));
464
- if (materializedParams.page > totalPages) {
465
- throw new Error(
466
- `Invalid ReferrerLeaderboardPageContext: page ${materializedParams.page} exceeds total pages ${totalPages}.`
467
- );
468
- }
469
- if (totalRecords === 0) {
470
- return {
471
- ...materializedParams,
472
- totalRecords: 0,
473
- totalPages: 1,
474
- hasNext: false,
475
- hasPrev: false,
476
- startIndex: void 0,
477
- endIndex: void 0
478
- };
479
- }
480
- const startIndex = (materializedParams.page - 1) * materializedParams.recordsPerPage;
481
- const maxTheoreticalIndexOnPage = startIndex + (materializedParams.recordsPerPage - 1);
482
- const endIndex = Math.min(maxTheoreticalIndexOnPage, totalRecords - 1);
483
- const hasNext = maxTheoreticalIndexOnPage < totalRecords - 1;
484
- const hasPrev = materializedParams.page > 1;
485
- const result = {
486
- ...materializedParams,
487
- totalRecords,
488
- totalPages,
489
- hasNext,
490
- hasPrev,
491
- startIndex,
492
- endIndex
493
- };
494
- validateReferrerLeaderboardPageContext(result);
495
- return result;
496
- };
497
- var getReferrerLeaderboardPage = (pageParams, leaderboard) => {
498
- const pageContext = buildReferrerLeaderboardPageContext(pageParams, leaderboard);
499
- let referrers;
500
- if (pageContext.totalRecords > 0 && typeof pageContext.startIndex !== "undefined" && typeof pageContext.endIndex !== "undefined") {
501
- referrers = Array.from(leaderboard.referrers.values()).slice(
502
- pageContext.startIndex,
503
- pageContext.endIndex + 1
504
- // For `slice`, this is exclusive of the element at the index 'end'. We need it to be inclusive, hence plus one.
505
- );
506
- } else {
507
- referrers = [];
508
- }
509
- return {
510
- rules: leaderboard.rules,
511
- referrers,
512
- aggregatedMetrics: leaderboard.aggregatedMetrics,
513
- pageContext,
514
- accurateAsOf: leaderboard.accurateAsOf
515
- };
516
- };
517
-
518
1442
  // src/link.ts
519
- import { getAddress as getAddress2 } from "viem";
1443
+ import { getAddress } from "viem";
520
1444
  function buildEnsReferralUrl(address) {
521
1445
  const ensAppUrl = new URL("https://app.ens.domains");
522
- ensAppUrl.searchParams.set("referrer", getAddress2(address));
1446
+ ensAppUrl.searchParams.set("referrer", getAddress(address));
523
1447
  return ensAppUrl;
524
1448
  }
525
1449
 
526
- // src/referrer-detail.ts
527
- var ReferrerDetailTypeIds = {
528
- /**
529
- * Represents a referrer who is ranked on the leaderboard.
530
- */
531
- Ranked: "ranked",
532
- /**
533
- * Represents a referrer who is not ranked on the leaderboard.
534
- */
535
- Unranked: "unranked"
536
- };
537
- var getReferrerDetail = (referrer, leaderboard) => {
538
- const awardedReferrerMetrics = leaderboard.referrers.get(referrer);
539
- if (awardedReferrerMetrics) {
540
- return {
541
- type: ReferrerDetailTypeIds.Ranked,
542
- rules: leaderboard.rules,
543
- referrer: awardedReferrerMetrics,
544
- aggregatedMetrics: leaderboard.aggregatedMetrics,
545
- accurateAsOf: leaderboard.accurateAsOf
546
- };
547
- }
548
- return {
549
- type: ReferrerDetailTypeIds.Unranked,
550
- rules: leaderboard.rules,
551
- referrer: buildUnrankedReferrerMetrics(referrer),
552
- aggregatedMetrics: leaderboard.aggregatedMetrics,
553
- accurateAsOf: leaderboard.accurateAsOf
554
- };
555
- };
556
-
557
1450
  // src/rules.ts
558
1451
  var ENS_HOLIDAY_AWARDS_START_DATE = 1764547200;
559
1452
  var ENS_HOLIDAY_AWARDS_END_DATE = 1767225599;
@@ -603,22 +1496,21 @@ var calcReferralProgramStatus = (referralProgramRules, now) => {
603
1496
  return ReferralProgramStatuses.Active;
604
1497
  };
605
1498
  export {
606
- ENCODED_REFERRER_BYTE_LENGTH,
607
- ENCODED_REFERRER_BYTE_OFFSET,
1499
+ DEFAULT_ENSNODE_API_URL,
1500
+ ENSReferralsClient,
608
1501
  ENS_HOLIDAY_AWARDS_END_DATE,
609
1502
  ENS_HOLIDAY_AWARDS_MAX_QUALIFIED_REFERRERS,
610
1503
  ENS_HOLIDAY_AWARDS_START_DATE,
611
1504
  ENS_HOLIDAY_AWARDS_TOTAL_AWARD_POOL_VALUE,
612
- EXPECTED_ENCODED_REFERRER_PADDING,
613
1505
  REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT,
614
1506
  REFERRERS_PER_LEADERBOARD_PAGE_MAX,
615
1507
  ReferralProgramStatuses,
1508
+ ReferrerDetailResponseCodes,
616
1509
  ReferrerDetailTypeIds,
1510
+ ReferrerLeaderboardPageResponseCodes,
617
1511
  SECONDS_PER_YEAR,
618
- ZERO_ENCODED_REFERRER,
619
1512
  buildAggregatedReferrerMetrics,
620
1513
  buildAwardedReferrerMetrics,
621
- buildEncodedReferrer,
622
1514
  buildEnsReferralUrl,
623
1515
  buildRankedReferrerMetrics,
624
1516
  buildReferralProgramRules,
@@ -635,7 +1527,8 @@ export {
635
1527
  calcReferrerFinalScoreMultiplier,
636
1528
  calcReferrerScore,
637
1529
  compareReferrerMetrics,
638
- decodeEncodedReferrer,
1530
+ deserializeReferrerDetailResponse,
1531
+ deserializeReferrerLeaderboardPageResponse,
639
1532
  getReferrerDetail,
640
1533
  getReferrerLeaderboardPage,
641
1534
  isFiniteNonNegativeNumber,
@@ -648,6 +1541,8 @@ export {
648
1541
  isValidRevenueContribution,
649
1542
  isValidUSDQuantity,
650
1543
  normalizeAddress,
1544
+ serializeReferrerDetailResponse,
1545
+ serializeReferrerLeaderboardPageResponse,
651
1546
  sortReferrerMetrics,
652
1547
  validateAggregatedReferrerMetrics,
653
1548
  validateAwardedReferrerMetrics,