@ensnode/ensnode-sdk 0.0.0-next-20260130072518 → 0.0.0-next-20260131065208

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.cjs CHANGED
@@ -113,6 +113,9 @@ __export(index_exports, {
113
113
  deserializeErrorResponse: () => deserializeErrorResponse,
114
114
  deserializeIndexingStatusResponse: () => deserializeIndexingStatusResponse,
115
115
  deserializeOmnichainIndexingStatusSnapshot: () => deserializeOmnichainIndexingStatusSnapshot,
116
+ deserializePriceDai: () => deserializePriceDai,
117
+ deserializePriceEth: () => deserializePriceEth,
118
+ deserializePriceUsdc: () => deserializePriceUsdc,
116
119
  deserializeRealtimeIndexingStatusProjection: () => deserializeRealtimeIndexingStatusProjection,
117
120
  deserializeRegistrarActionsResponse: () => deserializeRegistrarActionsResponse,
118
121
  deserializeUnixTimestamp: () => deserializeUnixTimestamp,
@@ -206,14 +209,19 @@ __export(index_exports, {
206
209
  nameTokensPrerequisites: () => nameTokensPrerequisites,
207
210
  parseAccountId: () => parseAccountId,
208
211
  parseAssetId: () => parseAssetId,
212
+ parseDai: () => parseDai,
213
+ parseEth: () => parseEth,
209
214
  parseNonNegativeInteger: () => parseNonNegativeInteger,
210
215
  parseReverseName: () => parseReverseName,
216
+ parseUsdc: () => parseUsdc,
211
217
  priceDai: () => priceDai,
212
218
  priceEth: () => priceEth,
213
219
  priceUsdc: () => priceUsdc,
214
220
  registrarActionsFilter: () => registrarActionsFilter,
215
221
  registrarActionsPrerequisites: () => registrarActionsPrerequisites,
216
222
  reverseName: () => reverseName,
223
+ scaleBigintByNumber: () => scaleBigintByNumber,
224
+ scalePrice: () => scalePrice,
217
225
  serializeAssetId: () => serializeAssetId,
218
226
  serializeChainId: () => serializeChainId,
219
227
  serializeChainIndexingSnapshots: () => serializeChainIndexingSnapshots,
@@ -230,7 +238,9 @@ __export(index_exports, {
230
238
  serializeNamedRegistrarAction: () => serializeNamedRegistrarAction,
231
239
  serializeOmnichainIndexingStatusSnapshot: () => serializeOmnichainIndexingStatusSnapshot,
232
240
  serializePrice: () => serializePrice,
241
+ serializePriceDai: () => serializePriceDai,
233
242
  serializePriceEth: () => serializePriceEth,
243
+ serializePriceUsdc: () => serializePriceUsdc,
234
244
  serializeRealtimeIndexingStatusProjection: () => serializeRealtimeIndexingStatusProjection,
235
245
  serializeRegisteredNameTokens: () => serializeRegisteredNameTokens,
236
246
  serializeRegistrarAction: () => serializeRegistrarAction,
@@ -247,81 +257,17 @@ __export(index_exports, {
247
257
  module.exports = __toCommonJS(index_exports);
248
258
 
249
259
  // src/ensapi/config/deserialize.ts
250
- var import_v46 = require("zod/v4");
260
+ var import_v45 = require("zod/v4");
251
261
 
252
262
  // src/ensapi/config/zod-schemas.ts
253
- var import_v45 = require("zod/v4");
263
+ var import_v44 = require("zod/v4");
254
264
 
255
265
  // src/ensindexer/config/zod-schemas.ts
256
- var import_v43 = require("zod/v4");
257
-
258
- // src/shared/account-id.ts
259
- var import_viem = require("viem");
260
- var accountIdEqual = (a, b) => {
261
- return a.chainId === b.chainId && (0, import_viem.isAddressEqual)(a.address, b.address);
262
- };
263
-
264
- // src/shared/address.ts
265
- function asLowerCaseAddress(address) {
266
- return address.toLowerCase();
267
- }
268
-
269
- // src/shared/cache/lru-cache.ts
270
- var LruCache = class {
271
- _cache = /* @__PURE__ */ new Map();
272
- _capacity;
273
- /**
274
- * Create a new LRU cache with the given capacity.
275
- *
276
- * @param capacity The maximum number of items in the cache. If set to 0, the cache is effectively disabled.
277
- * @throws Error if capacity is not a non-negative integer.
278
- */
279
- constructor(capacity) {
280
- if (!Number.isInteger(capacity)) {
281
- throw new Error(
282
- `LruCache requires capacity to be an integer but a capacity of ${capacity} was requested.`
283
- );
284
- }
285
- if (capacity < 0) {
286
- throw new Error(
287
- `LruCache requires a non-negative capacity but a capacity of ${capacity} was requested.`
288
- );
289
- }
290
- this._capacity = capacity;
291
- }
292
- set(key, value) {
293
- this._cache.set(key, value);
294
- if (this._cache.size > this._capacity) {
295
- const oldestKey = this._cache.keys().next().value;
296
- this._cache.delete(oldestKey);
297
- }
298
- }
299
- get(key) {
300
- const value = this._cache.get(key);
301
- if (value) {
302
- this._cache.delete(key);
303
- this._cache.set(key, value);
304
- }
305
- return value;
306
- }
307
- clear() {
308
- this._cache.clear();
309
- }
310
- get size() {
311
- return this._cache.size;
312
- }
313
- get capacity() {
314
- return this._capacity;
315
- }
316
- };
317
-
318
- // src/shared/cache/swr-cache.ts
319
- var import_date_fns = require("date-fns");
320
- var import_getUnixTime = require("date-fns/getUnixTime");
321
-
322
- // src/shared/deserialize.ts
323
266
  var import_v42 = require("zod/v4");
324
267
 
268
+ // src/shared/collections.ts
269
+ var uniq = (arr) => [...new Set(arr)];
270
+
325
271
  // src/shared/zod-schemas.ts
326
272
  var import_caip = require("caip");
327
273
  var import_viem8 = require("viem");
@@ -351,23 +297,23 @@ var bigintToCoinType = (value) => {
351
297
  };
352
298
 
353
299
  // src/ens/constants.ts
354
- var import_viem2 = require("viem");
355
- var ROOT_NODE = (0, import_viem2.namehash)("");
356
- var ETH_NODE = (0, import_viem2.namehash)("eth");
357
- var BASENAMES_NODE = (0, import_viem2.namehash)("base.eth");
358
- var LINEANAMES_NODE = (0, import_viem2.namehash)("linea.eth");
359
- var ADDR_REVERSE_NODE = (0, import_viem2.namehash)("addr.reverse");
360
- var NODE_ANY = import_viem2.zeroHash;
300
+ var import_viem = require("viem");
301
+ var ROOT_NODE = (0, import_viem.namehash)("");
302
+ var ETH_NODE = (0, import_viem.namehash)("eth");
303
+ var BASENAMES_NODE = (0, import_viem.namehash)("base.eth");
304
+ var LINEANAMES_NODE = (0, import_viem.namehash)("linea.eth");
305
+ var ADDR_REVERSE_NODE = (0, import_viem.namehash)("addr.reverse");
306
+ var NODE_ANY = import_viem.zeroHash;
361
307
  var ROOT_RESOURCE = 0n;
362
308
 
363
309
  // src/ens/dns-encoded-name.ts
364
- var import_viem3 = require("viem");
310
+ var import_viem2 = require("viem");
365
311
  function decodeDNSEncodedLiteralName(packet) {
366
312
  return decodeDNSEncodedName(packet);
367
313
  }
368
314
  function decodeDNSEncodedName(packet) {
369
315
  const segments = [];
370
- const bytes = (0, import_viem3.hexToBytes)(packet);
316
+ const bytes = (0, import_viem2.hexToBytes)(packet);
371
317
  if (bytes.length === 0) throw new Error(`Packet is empty.`);
372
318
  let offset = 0;
373
319
  while (offset < bytes.length) {
@@ -381,7 +327,7 @@ function decodeDNSEncodedName(packet) {
381
327
  );
382
328
  }
383
329
  if (len === 0) break;
384
- const segment = (0, import_viem3.bytesToString)(bytes.subarray(offset + 1, offset + len + 1));
330
+ const segment = (0, import_viem2.bytesToString)(bytes.subarray(offset + 1, offset + len + 1));
385
331
  segments.push(segment);
386
332
  offset += len + 1;
387
333
  }
@@ -391,10 +337,10 @@ function decodeDNSEncodedName(packet) {
391
337
  }
392
338
 
393
339
  // src/ens/labelhash.ts
394
- var import_viem4 = require("viem");
340
+ var import_viem3 = require("viem");
395
341
  function isLabelHash(maybeLabelHash) {
396
342
  const expectedLength = maybeLabelHash.length === 66;
397
- const expectedEncoding = (0, import_viem4.isHex)(maybeLabelHash);
343
+ const expectedEncoding = (0, import_viem3.isHex)(maybeLabelHash);
398
344
  const expectedCasing = maybeLabelHash === maybeLabelHash.toLowerCase();
399
345
  return expectedLength && expectedEncoding && expectedCasing;
400
346
  }
@@ -456,11 +402,18 @@ var beautifyName = (name) => {
456
402
  };
457
403
 
458
404
  // src/ens/parse-reverse-name.ts
459
- var import_viem5 = require("viem");
405
+ var import_viem4 = require("viem");
406
+
407
+ // src/shared/address.ts
408
+ function asLowerCaseAddress(address) {
409
+ return address.toLowerCase();
410
+ }
411
+
412
+ // src/ens/parse-reverse-name.ts
460
413
  var REVERSE_NAME_REGEX = /^([0-9a-fA-F]+)\.([0-9a-f]{1,64}|addr|default)\.reverse$/;
461
414
  var parseAddressLabel = (addressLabel) => {
462
415
  const maybeAddress = `0x${addressLabel}`;
463
- if (!(0, import_viem5.isAddress)(maybeAddress)) {
416
+ if (!(0, import_viem4.isAddress)(maybeAddress)) {
464
417
  throw new Error(`Invalid EVM address "${maybeAddress}"`);
465
418
  }
466
419
  return asLowerCaseAddress(maybeAddress);
@@ -468,7 +421,7 @@ var parseAddressLabel = (addressLabel) => {
468
421
  var parseCoinTypeLabel = (coinTypeLabel) => {
469
422
  if (coinTypeLabel === "default") return DEFAULT_EVM_COIN_TYPE;
470
423
  if (coinTypeLabel === "addr") return ETH_COIN_TYPE;
471
- return bigintToCoinType((0, import_viem5.hexToBigInt)(`0x${coinTypeLabel}`));
424
+ return bigintToCoinType((0, import_viem4.hexToBigInt)(`0x${coinTypeLabel}`));
472
425
  };
473
426
  function parseReverseName(name) {
474
427
  const match = name.match(REVERSE_NAME_REGEX);
@@ -505,13 +458,59 @@ function reverseName(address, coinType) {
505
458
  }
506
459
 
507
460
  // src/ens/subname-helpers.ts
508
- var import_viem6 = require("viem");
509
- var makeSubdomainNode = (labelHash, node) => (0, import_viem6.keccak256)((0, import_viem6.concat)([node, labelHash]));
510
- var uint256ToHex32 = (num) => (0, import_viem6.toHex)(num, { size: 32 });
461
+ var import_viem5 = require("viem");
462
+ var makeSubdomainNode = (labelHash, node) => (0, import_viem5.keccak256)((0, import_viem5.concat)([node, labelHash]));
463
+ var uint256ToHex32 = (num) => (0, import_viem5.toHex)(num, { size: 32 });
511
464
 
512
465
  // src/ens/types.ts
513
466
  var import_datasources = require("@ensnode/datasources");
514
467
 
468
+ // src/shared/currencies.ts
469
+ var import_viem6 = require("viem");
470
+
471
+ // src/shared/numbers.ts
472
+ function bigIntToNumber(n) {
473
+ if (n < Number.MIN_SAFE_INTEGER) {
474
+ throw new Error(
475
+ `The bigint '${n.toString()}' value is too low to be to converted into a number.'`
476
+ );
477
+ }
478
+ if (n > Number.MAX_SAFE_INTEGER) {
479
+ throw new Error(
480
+ `The bigint '${n.toString()}' value is too high to be to converted into a number.'`
481
+ );
482
+ }
483
+ return Number(n);
484
+ }
485
+ function scaleBigintByNumber(value, scaleFactor) {
486
+ if (value < 0n) {
487
+ throw new Error(`scaleBigintByNumber: value must be non-negative, got: ${value.toString()}`);
488
+ }
489
+ if (!Number.isFinite(scaleFactor)) {
490
+ throw new Error(
491
+ `scaleBigintByNumber: scaleFactor must be a finite number, got: ${scaleFactor}`
492
+ );
493
+ }
494
+ if (scaleFactor < 0) {
495
+ throw new Error(`scaleBigintByNumber: scaleFactor must be non-negative, got: ${scaleFactor}`);
496
+ }
497
+ if (scaleFactor >= 1e21) {
498
+ throw new Error(`scaleBigintByNumber: scaleFactor must be less than 1e21, got: ${scaleFactor}`);
499
+ }
500
+ if (value === 0n || scaleFactor === 0) {
501
+ return 0n;
502
+ }
503
+ if (scaleFactor === 1) {
504
+ return value;
505
+ }
506
+ const fixedStr = scaleFactor.toFixed(20);
507
+ const [integerPart, decimalPart = ""] = fixedStr.split(".");
508
+ const trimmedDecimal = decimalPart.replace(/0+$/, "") || "0";
509
+ const numerator = BigInt(integerPart + trimmedDecimal);
510
+ const denominator = 10n ** BigInt(trimmedDecimal.length);
511
+ return value * numerator / denominator;
512
+ }
513
+
515
514
  // src/shared/currencies.ts
516
515
  var CurrencyIds = {
517
516
  ETH: "ETH",
@@ -580,6 +579,43 @@ function addPrices(...prices) {
580
579
  }
581
580
  );
582
581
  }
582
+ function scalePrice(price, scaleFactor) {
583
+ const scaledAmount = scaleBigintByNumber(price.amount, scaleFactor);
584
+ return {
585
+ ...price,
586
+ amount: scaledAmount
587
+ };
588
+ }
589
+ function validateAmountToParse(value) {
590
+ const trimmed = value.trim();
591
+ if (trimmed === "") {
592
+ throw new Error("amount must be a non-negative decimal string");
593
+ }
594
+ if (value !== trimmed) {
595
+ throw new Error("amount must not have leading or trailing whitespace");
596
+ }
597
+ if (trimmed.startsWith("-")) {
598
+ throw new Error("amount must be a non-negative decimal string");
599
+ }
600
+ }
601
+ function parseEth(value) {
602
+ validateAmountToParse(value);
603
+ const currencyInfo2 = getCurrencyInfo(CurrencyIds.ETH);
604
+ const amount = (0, import_viem6.parseUnits)(value, currencyInfo2.decimals);
605
+ return priceEth(amount);
606
+ }
607
+ function parseUsdc(value) {
608
+ validateAmountToParse(value);
609
+ const currencyInfo2 = getCurrencyInfo(CurrencyIds.USDC);
610
+ const amount = (0, import_viem6.parseUnits)(value, currencyInfo2.decimals);
611
+ return priceUsdc(amount);
612
+ }
613
+ function parseDai(value) {
614
+ validateAmountToParse(value);
615
+ const currencyInfo2 = getCurrencyInfo(CurrencyIds.DAI);
616
+ const amount = (0, import_viem6.parseUnits)(value, currencyInfo2.decimals);
617
+ return priceDai(amount);
618
+ }
583
619
 
584
620
  // src/shared/interpretation/reinterpretation.ts
585
621
  var import_viem7 = require("viem");
@@ -675,6 +711,8 @@ var makePriceCurrencySchema = (currency, valueLabel = "Price Currency") => impor
675
711
  })
676
712
  });
677
713
  var makePriceEthSchema = (valueLabel = "Price ETH") => makePriceCurrencySchema(CurrencyIds.ETH, valueLabel).transform((v) => v);
714
+ var makePriceUsdcSchema = (valueLabel = "Price USDC") => makePriceCurrencySchema(CurrencyIds.USDC, valueLabel).transform((v) => v);
715
+ var makePriceDaiSchema = (valueLabel = "Price DAI") => makePriceCurrencySchema(CurrencyIds.DAI, valueLabel).transform((v) => v);
678
716
  var makeAccountIdSchema = (valueLabel = "AccountId") => import_v4.z.strictObject({
679
717
  chainId: makeChainIdSchema(`${valueLabel} chain ID`),
680
718
  address: makeLowercaseAddressSchema(`${valueLabel} address`)
@@ -720,64 +758,341 @@ var makeReinterpretedNameSchema = (valueLabel = "Reinterpreted Name") => import_
720
758
  }
721
759
  }).transform(reinterpretName);
722
760
 
723
- // src/shared/deserialize.ts
724
- function deserializeChainId(maybeChainId, valueLabel) {
725
- const schema = makeChainIdStringSchema(valueLabel);
726
- const parsed = schema.safeParse(maybeChainId);
727
- if (parsed.error) {
728
- throw new Error(`Cannot deserialize ChainId:
729
- ${(0, import_v42.prettifyError)(parsed.error)}
730
- `);
731
- }
732
- return parsed.data;
761
+ // src/ensindexer/config/is-subgraph-compatible.ts
762
+ var import_datasources3 = require("@ensnode/datasources");
763
+
764
+ // src/ensindexer/config/types.ts
765
+ var PluginName = /* @__PURE__ */ ((PluginName2) => {
766
+ PluginName2["Subgraph"] = "subgraph";
767
+ PluginName2["Basenames"] = "basenames";
768
+ PluginName2["Lineanames"] = "lineanames";
769
+ PluginName2["ThreeDNS"] = "threedns";
770
+ PluginName2["ProtocolAcceleration"] = "protocol-acceleration";
771
+ PluginName2["Registrars"] = "registrars";
772
+ PluginName2["TokenScope"] = "tokenscope";
773
+ PluginName2["ENSv2"] = "ensv2";
774
+ return PluginName2;
775
+ })(PluginName || {});
776
+
777
+ // src/ensindexer/config/is-subgraph-compatible.ts
778
+ function isSubgraphCompatible(config) {
779
+ const onlySubgraphPluginActivated = config.plugins.length === 1 && config.plugins[0] === "subgraph" /* Subgraph */;
780
+ const isSubgraphLabelSet = config.labelSet.labelSetId === "subgraph" && config.labelSet.labelSetVersion === 0;
781
+ const isEnsTestEnvLabelSet = config.labelSet.labelSetId === "ens-test-env" && config.labelSet.labelSetVersion === 0;
782
+ const labelSetIsSubgraphCompatible = isSubgraphLabelSet || config.namespace === import_datasources3.ENSNamespaceIds.EnsTestEnv && isEnsTestEnvLabelSet;
783
+ return onlySubgraphPluginActivated && labelSetIsSubgraphCompatible;
733
784
  }
734
- function deserializeDatetime(maybeDatetime, valueLabel) {
735
- const schema = makeDatetimeSchema(valueLabel);
736
- const parsed = schema.safeParse(maybeDatetime);
737
- if (parsed.error) {
738
- throw new Error(`Cannot deserialize Datetime:
739
- ${(0, import_v42.prettifyError)(parsed.error)}
740
- `);
785
+
786
+ // src/ensindexer/config/validations.ts
787
+ function invariant_ensDbVersionIsSameAsEnsIndexerVersion(ctx) {
788
+ const versionInfo = ctx.value;
789
+ if (versionInfo.ensDb !== versionInfo.ensIndexer) {
790
+ ctx.issues.push({
791
+ code: "custom",
792
+ input: versionInfo,
793
+ message: "`ensDb` version must be same as `ensIndexer` version"
794
+ });
741
795
  }
742
- return parsed.data;
743
796
  }
744
- function deserializeUnixTimestamp(maybeTimestamp, valueLabel) {
745
- const schema = makeUnixTimestampSchema(valueLabel);
746
- const parsed = schema.safeParse(maybeTimestamp);
747
- if (parsed.error) {
748
- throw new Error(`Cannot deserialize Unix Timestamp:
749
- ${(0, import_v42.prettifyError)(parsed.error)}
750
- `);
797
+
798
+ // src/ensindexer/config/zod-schemas.ts
799
+ var makeIndexedChainIdsSchema = (valueLabel = "Indexed Chain IDs") => import_v42.z.array(makeChainIdSchema(valueLabel), {
800
+ error: `${valueLabel} must be an array.`
801
+ }).min(1, { error: `${valueLabel} list must include at least one element.` }).transform((v) => new Set(v));
802
+ var makePluginsListSchema = (valueLabel = "Plugins") => import_v42.z.array(import_v42.z.string(), {
803
+ error: `${valueLabel} must be a list of strings.`
804
+ }).min(1, {
805
+ error: `${valueLabel} must be a list of strings with at least one string value`
806
+ }).refine((arr) => arr.length === uniq(arr).length, {
807
+ error: `${valueLabel} cannot contain duplicate values.`
808
+ });
809
+ var makeDatabaseSchemaNameSchema = (valueLabel = "Database schema name") => import_v42.z.string({ error: `${valueLabel} must be a string` }).trim().nonempty({
810
+ error: `${valueLabel} is required and must be a non-empty string.`
811
+ });
812
+ var makeLabelSetIdSchema = (valueLabel) => {
813
+ return import_v42.z.string({ error: `${valueLabel} must be a string` }).min(1, { error: `${valueLabel} must be 1-50 characters long` }).max(50, { error: `${valueLabel} must be 1-50 characters long` }).regex(/^[a-z-]+$/, {
814
+ error: `${valueLabel} can only contain lowercase letters (a-z) and hyphens (-)`
815
+ });
816
+ };
817
+ var makeLabelSetVersionSchema = (valueLabel) => {
818
+ return import_v42.z.coerce.number({ error: `${valueLabel} must be an integer.` }).pipe(makeNonNegativeIntegerSchema(valueLabel));
819
+ };
820
+ var makeFullyPinnedLabelSetSchema = (valueLabel = "Label set") => {
821
+ let valueLabelLabelSetId = valueLabel;
822
+ let valueLabelLabelSetVersion = valueLabel;
823
+ if (valueLabel === "LABEL_SET") {
824
+ valueLabelLabelSetId = "LABEL_SET_ID";
825
+ valueLabelLabelSetVersion = "LABEL_SET_VERSION";
826
+ } else {
827
+ valueLabelLabelSetId = `${valueLabel}.labelSetId`;
828
+ valueLabelLabelSetVersion = `${valueLabel}.labelSetVersion`;
751
829
  }
752
- return parsed.data;
753
- }
754
- function deserializeUrl(maybeUrl, valueLabel) {
755
- const schema = makeUrlSchema(valueLabel);
756
- const parsed = schema.safeParse(maybeUrl);
757
- if (parsed.error) {
758
- throw new Error(`Cannot deserialize URL:
759
- ${(0, import_v42.prettifyError)(parsed.error)}
760
- `);
830
+ return import_v42.z.object({
831
+ labelSetId: makeLabelSetIdSchema(valueLabelLabelSetId),
832
+ labelSetVersion: makeLabelSetVersionSchema(valueLabelLabelSetVersion)
833
+ });
834
+ };
835
+ var makeNonEmptyStringSchema = (valueLabel = "Value") => import_v42.z.string().nonempty({ error: `${valueLabel} must be a non-empty string.` });
836
+ var makeENSIndexerVersionInfoSchema = (valueLabel = "Value") => import_v42.z.strictObject(
837
+ {
838
+ nodejs: makeNonEmptyStringSchema(),
839
+ ponder: makeNonEmptyStringSchema(),
840
+ ensDb: makeNonEmptyStringSchema(),
841
+ ensIndexer: makeNonEmptyStringSchema(),
842
+ ensNormalize: makeNonEmptyStringSchema(),
843
+ ensRainbow: makeNonEmptyStringSchema(),
844
+ ensRainbowSchema: makePositiveIntegerSchema()
845
+ },
846
+ {
847
+ error: `${valueLabel} must be a valid ENSIndexerVersionInfo object.`
761
848
  }
762
- return parsed.data;
763
- }
764
- function deserializeBlockNumber(maybeBlockNumber, valueLabel) {
765
- const schema = makeBlockNumberSchema(valueLabel);
766
- const parsed = schema.safeParse(maybeBlockNumber);
767
- if (parsed.error) {
768
- throw new Error(`Cannot deserialize BlockNumber:
769
- ${(0, import_v42.prettifyError)(parsed.error)}
770
- `);
849
+ ).check(invariant_ensDbVersionIsSameAsEnsIndexerVersion);
850
+ function invariant_isSubgraphCompatibleRequirements(ctx) {
851
+ const { value: config } = ctx;
852
+ if (config.isSubgraphCompatible && !isSubgraphCompatible(config)) {
853
+ ctx.issues.push({
854
+ code: "custom",
855
+ input: config,
856
+ message: `'isSubgraphCompatible' requires only the '${"subgraph" /* Subgraph */}' plugin to be active and labelSet must be {labelSetId: "subgraph", labelSetVersion: 0}`
857
+ });
771
858
  }
772
- return parsed.data;
773
859
  }
774
- function deserializeBlockrange(maybeBlockrange, valueLabel) {
775
- const schema = makeBlockrangeSchema(valueLabel);
776
- const parsed = schema.safeParse(maybeBlockrange);
777
- if (parsed.error) {
778
- throw new Error(`Cannot deserialize Blockrange:
779
- ${(0, import_v42.prettifyError)(parsed.error)}
780
- `);
860
+ var makeENSIndexerPublicConfigSchema = (valueLabel = "ENSIndexerPublicConfig") => import_v42.z.object({
861
+ labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`),
862
+ indexedChainIds: makeIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),
863
+ isSubgraphCompatible: import_v42.z.boolean({ error: `${valueLabel}.isSubgraphCompatible` }),
864
+ namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),
865
+ plugins: makePluginsListSchema(`${valueLabel}.plugins`),
866
+ databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),
867
+ versionInfo: makeENSIndexerVersionInfoSchema(`${valueLabel}.versionInfo`)
868
+ }).check(invariant_isSubgraphCompatibleRequirements);
869
+
870
+ // src/shared/config/thegraph.ts
871
+ var import_v43 = require("zod/v4");
872
+ var TheGraphCannotFallbackReasonSchema = import_v43.z.enum({
873
+ NotSubgraphCompatible: "not-subgraph-compatible",
874
+ NoApiKey: "no-api-key",
875
+ NoSubgraphUrl: "no-subgraph-url"
876
+ });
877
+ var TheGraphFallbackSchema = import_v43.z.discriminatedUnion("canFallback", [
878
+ import_v43.z.strictObject({
879
+ canFallback: import_v43.z.literal(true),
880
+ url: import_v43.z.string()
881
+ }),
882
+ import_v43.z.strictObject({
883
+ canFallback: import_v43.z.literal(false),
884
+ reason: TheGraphCannotFallbackReasonSchema
885
+ })
886
+ ]);
887
+
888
+ // src/ensapi/config/zod-schemas.ts
889
+ function makeENSApiPublicConfigSchema(valueLabel) {
890
+ const label = valueLabel ?? "ENSApiPublicConfig";
891
+ return import_v44.z.strictObject({
892
+ version: import_v44.z.string().min(1, `${label}.version must be a non-empty string`),
893
+ theGraphFallback: TheGraphFallbackSchema,
894
+ ensIndexerPublicConfig: makeENSIndexerPublicConfigSchema(`${label}.ensIndexerPublicConfig`)
895
+ });
896
+ }
897
+
898
+ // src/ensapi/config/deserialize.ts
899
+ function deserializeENSApiPublicConfig(maybeConfig, valueLabel) {
900
+ const schema = makeENSApiPublicConfigSchema(valueLabel);
901
+ try {
902
+ return schema.parse(maybeConfig);
903
+ } catch (error) {
904
+ if (error instanceof import_v45.ZodError) {
905
+ throw new Error(`Cannot deserialize ENSApiPublicConfig:
906
+ ${(0, import_v45.prettifyError)(error)}
907
+ `);
908
+ }
909
+ throw error;
910
+ }
911
+ }
912
+
913
+ // src/ensindexer/config/deserialize.ts
914
+ var import_v46 = require("zod/v4");
915
+ function deserializeENSIndexerPublicConfig(maybeConfig, valueLabel) {
916
+ const schema = makeENSIndexerPublicConfigSchema(valueLabel);
917
+ const parsed = schema.safeParse(maybeConfig);
918
+ if (parsed.error) {
919
+ throw new Error(`Cannot deserialize ENSIndexerPublicConfig:
920
+ ${(0, import_v46.prettifyError)(parsed.error)}
921
+ `);
922
+ }
923
+ return parsed.data;
924
+ }
925
+
926
+ // src/ensindexer/config/label-utils.ts
927
+ var import_viem9 = require("viem");
928
+ function labelHashToBytes(labelHash) {
929
+ try {
930
+ if (labelHash.length !== 66) {
931
+ throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);
932
+ }
933
+ if (labelHash !== labelHash.toLowerCase()) {
934
+ throw new Error("Labelhash must be in lowercase");
935
+ }
936
+ if (!labelHash.startsWith("0x")) {
937
+ throw new Error("Labelhash must be 0x-prefixed");
938
+ }
939
+ const bytes = (0, import_viem9.hexToBytes)(labelHash);
940
+ if (bytes.length !== 32) {
941
+ throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);
942
+ }
943
+ return bytes;
944
+ } catch (e) {
945
+ if (e instanceof Error) {
946
+ throw e;
947
+ }
948
+ throw new Error("Invalid hex format");
949
+ }
950
+ }
951
+
952
+ // src/ensindexer/config/labelset-utils.ts
953
+ function buildLabelSetId(maybeLabelSetId) {
954
+ return makeLabelSetIdSchema("LabelSetId").parse(maybeLabelSetId);
955
+ }
956
+ function buildLabelSetVersion(maybeLabelSetVersion) {
957
+ return makeLabelSetVersionSchema("LabelSetVersion").parse(maybeLabelSetVersion);
958
+ }
959
+ function buildEnsRainbowClientLabelSet(labelSetId, labelSetVersion) {
960
+ if (labelSetVersion !== void 0 && labelSetId === void 0) {
961
+ throw new Error("When a labelSetVersion is defined, labelSetId must also be defined.");
962
+ }
963
+ return { labelSetId, labelSetVersion };
964
+ }
965
+ function validateSupportedLabelSetAndVersion(serverSet, clientSet) {
966
+ if (clientSet.labelSetId === void 0) {
967
+ return;
968
+ }
969
+ if (serverSet.labelSetId !== clientSet.labelSetId) {
970
+ throw new Error(
971
+ `Server label set ID "${serverSet.labelSetId}" does not match client's requested label set ID "${clientSet.labelSetId}".`
972
+ );
973
+ }
974
+ if (clientSet.labelSetVersion !== void 0 && serverSet.highestLabelSetVersion < clientSet.labelSetVersion) {
975
+ throw new Error(
976
+ `Server highest label set version ${serverSet.highestLabelSetVersion} is less than client's requested version ${clientSet.labelSetVersion} for label set ID "${clientSet.labelSetId}".`
977
+ );
978
+ }
979
+ }
980
+
981
+ // src/ensindexer/config/parsing.ts
982
+ function parseNonNegativeInteger(maybeNumber) {
983
+ const trimmed = maybeNumber.trim();
984
+ if (!trimmed) {
985
+ throw new Error("Input cannot be empty");
986
+ }
987
+ if (trimmed === "-0") {
988
+ throw new Error("Negative zero is not a valid non-negative integer");
989
+ }
990
+ const num = Number(maybeNumber);
991
+ if (Number.isNaN(num)) {
992
+ throw new Error(`"${maybeNumber}" is not a valid number`);
993
+ }
994
+ if (!Number.isFinite(num)) {
995
+ throw new Error(`"${maybeNumber}" is not a finite number`);
996
+ }
997
+ if (!Number.isInteger(num)) {
998
+ throw new Error(`"${maybeNumber}" is not an integer`);
999
+ }
1000
+ if (num < 0) {
1001
+ throw new Error(`"${maybeNumber}" is not a non-negative integer`);
1002
+ }
1003
+ return num;
1004
+ }
1005
+
1006
+ // src/ensindexer/config/serialize.ts
1007
+ function serializeIndexedChainIds(indexedChainIds) {
1008
+ return Array.from(indexedChainIds);
1009
+ }
1010
+ function serializeENSIndexerPublicConfig(config) {
1011
+ const {
1012
+ labelSet,
1013
+ indexedChainIds,
1014
+ databaseSchemaName,
1015
+ isSubgraphCompatible: isSubgraphCompatible2,
1016
+ namespace,
1017
+ plugins,
1018
+ versionInfo
1019
+ } = config;
1020
+ return {
1021
+ labelSet,
1022
+ indexedChainIds: serializeIndexedChainIds(indexedChainIds),
1023
+ databaseSchemaName,
1024
+ isSubgraphCompatible: isSubgraphCompatible2,
1025
+ namespace,
1026
+ plugins,
1027
+ versionInfo
1028
+ };
1029
+ }
1030
+
1031
+ // src/ensindexer/indexing-status/deserialize.ts
1032
+ var import_v49 = require("zod/v4");
1033
+
1034
+ // src/ensindexer/indexing-status/zod-schemas.ts
1035
+ var import_v48 = require("zod/v4");
1036
+
1037
+ // src/shared/deserialize.ts
1038
+ var import_v47 = require("zod/v4");
1039
+ function deserializeChainId(maybeChainId, valueLabel) {
1040
+ const schema = makeChainIdStringSchema(valueLabel);
1041
+ const parsed = schema.safeParse(maybeChainId);
1042
+ if (parsed.error) {
1043
+ throw new Error(`Cannot deserialize ChainId:
1044
+ ${(0, import_v47.prettifyError)(parsed.error)}
1045
+ `);
1046
+ }
1047
+ return parsed.data;
1048
+ }
1049
+ function deserializeDatetime(maybeDatetime, valueLabel) {
1050
+ const schema = makeDatetimeSchema(valueLabel);
1051
+ const parsed = schema.safeParse(maybeDatetime);
1052
+ if (parsed.error) {
1053
+ throw new Error(`Cannot deserialize Datetime:
1054
+ ${(0, import_v47.prettifyError)(parsed.error)}
1055
+ `);
1056
+ }
1057
+ return parsed.data;
1058
+ }
1059
+ function deserializeUnixTimestamp(maybeTimestamp, valueLabel) {
1060
+ const schema = makeUnixTimestampSchema(valueLabel);
1061
+ const parsed = schema.safeParse(maybeTimestamp);
1062
+ if (parsed.error) {
1063
+ throw new Error(`Cannot deserialize Unix Timestamp:
1064
+ ${(0, import_v47.prettifyError)(parsed.error)}
1065
+ `);
1066
+ }
1067
+ return parsed.data;
1068
+ }
1069
+ function deserializeUrl(maybeUrl, valueLabel) {
1070
+ const schema = makeUrlSchema(valueLabel);
1071
+ const parsed = schema.safeParse(maybeUrl);
1072
+ if (parsed.error) {
1073
+ throw new Error(`Cannot deserialize URL:
1074
+ ${(0, import_v47.prettifyError)(parsed.error)}
1075
+ `);
1076
+ }
1077
+ return parsed.data;
1078
+ }
1079
+ function deserializeBlockNumber(maybeBlockNumber, valueLabel) {
1080
+ const schema = makeBlockNumberSchema(valueLabel);
1081
+ const parsed = schema.safeParse(maybeBlockNumber);
1082
+ if (parsed.error) {
1083
+ throw new Error(`Cannot deserialize BlockNumber:
1084
+ ${(0, import_v47.prettifyError)(parsed.error)}
1085
+ `);
1086
+ }
1087
+ return parsed.data;
1088
+ }
1089
+ function deserializeBlockrange(maybeBlockrange, valueLabel) {
1090
+ const schema = makeBlockrangeSchema(valueLabel);
1091
+ const parsed = schema.safeParse(maybeBlockrange);
1092
+ if (parsed.error) {
1093
+ throw new Error(`Cannot deserialize Blockrange:
1094
+ ${(0, import_v47.prettifyError)(parsed.error)}
1095
+ `);
781
1096
  }
782
1097
  return parsed.data;
783
1098
  }
@@ -786,7 +1101,7 @@ function deserializeBlockRef(maybeBlockRef, valueLabel) {
786
1101
  const parsed = schema.safeParse(maybeBlockRef);
787
1102
  if (parsed.error) {
788
1103
  throw new Error(`Cannot deserialize BlockRef:
789
- ${(0, import_v42.prettifyError)(parsed.error)}
1104
+ ${(0, import_v47.prettifyError)(parsed.error)}
790
1105
  `);
791
1106
  }
792
1107
  return parsed.data;
@@ -796,7 +1111,7 @@ function deserializeDuration(maybeDuration, valueLabel) {
796
1111
  const parsed = schema.safeParse(maybeDuration);
797
1112
  if (parsed.error) {
798
1113
  throw new RangeError(`Cannot deserialize Duration:
799
- ${(0, import_v42.prettifyError)(parsed.error)}
1114
+ ${(0, import_v47.prettifyError)(parsed.error)}
800
1115
  `);
801
1116
  }
802
1117
  return parsed.data;
@@ -806,1234 +1121,698 @@ function parseAccountId(maybeAccountId, valueLabel) {
806
1121
  const parsed = schema.safeParse(maybeAccountId);
807
1122
  if (parsed.error) {
808
1123
  throw new RangeError(`Cannot deserialize AccountId:
809
- ${(0, import_v42.prettifyError)(parsed.error)}
1124
+ ${(0, import_v47.prettifyError)(parsed.error)}
810
1125
  `);
811
1126
  }
812
1127
  return parsed.data;
813
1128
  }
814
-
815
- // src/shared/datetime.ts
816
- function durationBetween(start, end) {
817
- return deserializeDuration(end - start, "Duration");
1129
+ function deserializePriceEth(maybePrice, valueLabel) {
1130
+ const schema = makePriceEthSchema(valueLabel);
1131
+ const parsed = schema.safeParse(maybePrice);
1132
+ if (parsed.error) {
1133
+ throw new Error(`Cannot deserialize PriceEth:
1134
+ ${(0, import_v47.prettifyError)(parsed.error)}
1135
+ `);
1136
+ }
1137
+ return parsed.data;
818
1138
  }
819
- function addDuration(timestamp, duration) {
820
- return deserializeUnixTimestamp(timestamp + duration, "UnixTimestamp");
1139
+ function deserializePriceUsdc(maybePrice, valueLabel) {
1140
+ const schema = makePriceUsdcSchema(valueLabel);
1141
+ const parsed = schema.safeParse(maybePrice);
1142
+ if (parsed.error) {
1143
+ throw new Error(`Cannot deserialize PriceUsdc:
1144
+ ${(0, import_v47.prettifyError)(parsed.error)}
1145
+ `);
1146
+ }
1147
+ return parsed.data;
821
1148
  }
822
-
823
- // src/shared/cache/swr-cache.ts
824
- var SWRCache = class {
825
- constructor(options) {
826
- this.options = options;
827
- if (options.proactiveRevalidationInterval) {
828
- this.backgroundInterval = setInterval(
829
- () => this.revalidate(),
830
- (0, import_date_fns.secondsToMilliseconds)(options.proactiveRevalidationInterval)
831
- );
832
- }
833
- if (options.proactivelyInitialize) this.revalidate();
834
- }
835
- cache = null;
836
- inProgressRevalidate = null;
837
- backgroundInterval = null;
838
- async revalidate() {
839
- if (!this.inProgressRevalidate) {
840
- this.inProgressRevalidate = this.options.fn().then((result) => {
841
- this.cache = {
842
- result,
843
- updatedAt: (0, import_getUnixTime.getUnixTime)(/* @__PURE__ */ new Date())
844
- };
845
- }).catch((error) => {
846
- if (!this.cache) {
847
- this.cache = {
848
- // ensure thrown value is always an Error instance
849
- result: error instanceof Error ? error : new Error(String(error)),
850
- updatedAt: (0, import_getUnixTime.getUnixTime)(/* @__PURE__ */ new Date())
851
- };
852
- }
853
- }).finally(() => {
854
- this.inProgressRevalidate = null;
855
- });
856
- }
857
- return this.inProgressRevalidate;
1149
+ function deserializePriceDai(maybePrice, valueLabel) {
1150
+ const schema = makePriceDaiSchema(valueLabel);
1151
+ const parsed = schema.safeParse(maybePrice);
1152
+ if (parsed.error) {
1153
+ throw new Error(`Cannot deserialize PriceDai:
1154
+ ${(0, import_v47.prettifyError)(parsed.error)}
1155
+ `);
858
1156
  }
1157
+ return parsed.data;
1158
+ }
1159
+
1160
+ // src/ensindexer/indexing-status/types.ts
1161
+ var ChainIndexingConfigTypeIds = {
859
1162
  /**
860
- * Read the most recently cached result from the `SWRCache`.
861
- *
862
- * @returns a `ValueType` that was most recently successfully returned by `fn` or `Error` if `fn`
863
- * has never successfully returned.
1163
+ * Represents that indexing of the chain should be performed for an indefinite range.
864
1164
  */
865
- async read() {
866
- if (!this.cache) await this.revalidate();
867
- if (!this.cache) throw new Error("never");
868
- if (durationBetween(this.cache.updatedAt, (0, import_getUnixTime.getUnixTime)(/* @__PURE__ */ new Date())) > this.options.ttl) {
869
- this.revalidate();
870
- }
871
- return this.cache.result;
872
- }
1165
+ Indefinite: "indefinite",
873
1166
  /**
874
- * Destroys the background revalidation interval, if exists.
1167
+ * Represents that indexing of the chain should be performed for a definite range.
875
1168
  */
876
- destroy() {
877
- if (this.backgroundInterval) {
878
- clearInterval(this.backgroundInterval);
879
- this.backgroundInterval = null;
880
- }
881
- }
1169
+ Definite: "definite"
882
1170
  };
883
-
884
- // src/shared/cache/ttl-cache.ts
885
- var import_getUnixTime2 = require("date-fns/getUnixTime");
886
- var TtlCache = class {
887
- _cache = /* @__PURE__ */ new Map();
888
- _ttl;
1171
+ var ChainIndexingStatusIds = {
889
1172
  /**
890
- * Create a new TTL cache with the given TTL.
1173
+ * Represents that indexing of the chain is not ready to begin yet because:
1174
+ * - ENSIndexer is in its initialization phase and the data to build a
1175
+ * "true" {@link ChainIndexingSnapshot} for the chain is still being loaded; or
1176
+ * - ENSIndexer is using an omnichain indexing strategy and the
1177
+ * `omnichainIndexingCursor` is <= `config.startBlock.timestamp` for the chain's
1178
+ * {@link ChainIndexingSnapshot}.
1179
+ */
1180
+ Queued: "chain-queued",
1181
+ /**
1182
+ * Represents that indexing of the chain is in progress and under a special
1183
+ * "backfill" phase that optimizes for accelerated indexing until reaching the
1184
+ * "fixed target" `backfillEndBlock`.
1185
+ */
1186
+ Backfill: "chain-backfill",
1187
+ /**
1188
+ * Represents that the "backfill" phase of indexing the chain is completed
1189
+ * and that the chain is configured to be indexed for an indefinite range.
1190
+ * Therefore, indexing of the chain remains indefinitely in progress where
1191
+ * ENSIndexer will continuously work to discover and index new blocks as they
1192
+ * are added to the chain across time.
1193
+ */
1194
+ Following: "chain-following",
1195
+ /**
1196
+ * Represents that indexing of the chain is completed as the chain is configured
1197
+ * to be indexed for a definite range and the indexing of all blocks through
1198
+ * that definite range is completed.
1199
+ */
1200
+ Completed: "chain-completed"
1201
+ };
1202
+ var OmnichainIndexingStatusIds = {
1203
+ /**
1204
+ * Represents that omnichain indexing is not ready to begin yet because
1205
+ * ENSIndexer is in its initialization phase and the data to build a "true"
1206
+ * {@link OmnichainIndexingStatusSnapshot} is still being loaded.
1207
+ */
1208
+ Unstarted: "omnichain-unstarted",
1209
+ /**
1210
+ * Represents that omnichain indexing is in an overall "backfill" status because
1211
+ * - At least one indexed chain has a `chainStatus` of
1212
+ * {@link ChainIndexingStatusIds.Backfill}; and
1213
+ * - No indexed chain has a `chainStatus` of {@link ChainIndexingStatusIds.Following}.
1214
+ */
1215
+ Backfill: "omnichain-backfill",
1216
+ /**
1217
+ * Represents that omnichain indexing is in an overall "following" status because
1218
+ * at least one indexed chain has a `chainStatus` of
1219
+ * {@link ChainIndexingStatusIds.Following}.
1220
+ */
1221
+ Following: "omnichain-following",
1222
+ /**
1223
+ * Represents that omnichain indexing has completed because all indexed chains have
1224
+ * a `chainStatus` of {@link ChainIndexingStatusIds.Completed}.
1225
+ */
1226
+ Completed: "omnichain-completed"
1227
+ };
1228
+ var CrossChainIndexingStrategyIds = {
1229
+ /**
1230
+ * Represents that the indexing of events across all indexed chains will
1231
+ * proceed in a deterministic "omnichain" ordering by block timestamp, chain ID,
1232
+ * and block number.
891
1233
  *
892
- * @param ttl Time-to-live duration in seconds. Items expire after this duration.
1234
+ * This strategy is "deterministic" in that the order of processing cross-chain indexed
1235
+ * events and each resulting indexed data state transition recorded in ENSDb is always
1236
+ * the same for each ENSIndexer instance operating with an equivalent
1237
+ * `ENSIndexerConfig` and ENSIndexer version. However it also has the drawbacks of:
1238
+ * - increased indexing latency that must wait for the slowest indexed chain to
1239
+ * add new blocks or to discover new blocks through the configured RPCs.
1240
+ * - if any indexed chain gets "stuck" due to chain or RPC failures, all indexed chains
1241
+ * will be affected.
893
1242
  */
894
- constructor(ttl) {
895
- this._ttl = ttl;
1243
+ Omnichain: "omnichain"
1244
+ };
1245
+
1246
+ // src/shared/block-ref.ts
1247
+ function isBefore(blockA, blockB) {
1248
+ return blockA.number < blockB.number && blockA.timestamp < blockB.timestamp;
1249
+ }
1250
+ function isEqualTo(blockA, blockB) {
1251
+ return blockA.number === blockB.number && blockA.timestamp === blockB.timestamp;
1252
+ }
1253
+ function isBeforeOrEqualTo(blockA, blockB) {
1254
+ return isBefore(blockA, blockB) || isEqualTo(blockA, blockB);
1255
+ }
1256
+
1257
+ // src/ensindexer/indexing-status/helpers.ts
1258
+ function getOmnichainIndexingStatus(chains) {
1259
+ if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(chains)) {
1260
+ return OmnichainIndexingStatusIds.Following;
896
1261
  }
897
- _cleanup() {
898
- const now = (0, import_getUnixTime2.getUnixTime)(/* @__PURE__ */ new Date());
899
- for (const [key, entry] of this._cache.entries()) {
900
- if (entry.expiresAt <= now) {
901
- this._cache.delete(key);
902
- }
903
- }
1262
+ if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(chains)) {
1263
+ return OmnichainIndexingStatusIds.Backfill;
904
1264
  }
905
- set(key, value) {
906
- this._cleanup();
907
- const expiresAt = addDuration((0, import_getUnixTime2.getUnixTime)(/* @__PURE__ */ new Date()), this._ttl);
908
- this._cache.set(key, { value, expiresAt });
1265
+ if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(chains)) {
1266
+ return OmnichainIndexingStatusIds.Unstarted;
909
1267
  }
910
- get(key) {
911
- this._cleanup();
912
- const entry = this._cache.get(key);
913
- if (!entry) {
914
- return void 0;
915
- }
916
- if (entry.expiresAt <= (0, import_getUnixTime2.getUnixTime)(/* @__PURE__ */ new Date())) {
917
- this._cache.delete(key);
918
- return void 0;
919
- }
920
- return entry.value;
1268
+ if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(chains)) {
1269
+ return OmnichainIndexingStatusIds.Completed;
921
1270
  }
922
- clear() {
923
- this._cache.clear();
1271
+ throw new Error(`Unable to determine omnichain indexing status for provided chains.`);
1272
+ }
1273
+ function getTimestampForLowestOmnichainStartBlock(chains) {
1274
+ const earliestKnownBlockTimestamps = chains.map(
1275
+ (chain) => chain.config.startBlock.timestamp
1276
+ );
1277
+ return Math.min(...earliestKnownBlockTimestamps);
1278
+ }
1279
+ function getTimestampForHighestOmnichainKnownBlock(chains) {
1280
+ const latestKnownBlockTimestamps = [];
1281
+ for (const chain of chains) {
1282
+ switch (chain.chainStatus) {
1283
+ case ChainIndexingStatusIds.Queued:
1284
+ if (chain.config.configType === ChainIndexingConfigTypeIds.Definite && chain.config.endBlock) {
1285
+ latestKnownBlockTimestamps.push(chain.config.endBlock.timestamp);
1286
+ }
1287
+ break;
1288
+ case ChainIndexingStatusIds.Backfill:
1289
+ latestKnownBlockTimestamps.push(chain.backfillEndBlock.timestamp);
1290
+ break;
1291
+ case ChainIndexingStatusIds.Completed:
1292
+ latestKnownBlockTimestamps.push(chain.latestIndexedBlock.timestamp);
1293
+ break;
1294
+ case ChainIndexingStatusIds.Following:
1295
+ latestKnownBlockTimestamps.push(chain.latestKnownBlock.timestamp);
1296
+ break;
1297
+ }
924
1298
  }
925
- get size() {
926
- this._cleanup();
927
- return this._cache.size;
1299
+ return Math.max(...latestKnownBlockTimestamps);
1300
+ }
1301
+ function getOmnichainIndexingCursor(chains) {
1302
+ if (chains.length === 0) {
1303
+ throw new Error(`Unable to determine omnichain indexing cursor when no chains were provided.`);
928
1304
  }
929
- get capacity() {
930
- return Number.MAX_SAFE_INTEGER;
1305
+ if (getOmnichainIndexingStatus(chains) === OmnichainIndexingStatusIds.Unstarted) {
1306
+ const earliestStartBlockTimestamps = chains.map((chain) => chain.config.startBlock.timestamp);
1307
+ return Math.min(...earliestStartBlockTimestamps) - 1;
931
1308
  }
932
- has(key) {
933
- this._cleanup();
934
- const entry = this._cache.get(key);
935
- if (!entry) {
936
- return false;
937
- }
938
- if (entry.expiresAt <= (0, import_getUnixTime2.getUnixTime)(/* @__PURE__ */ new Date())) {
939
- this._cache.delete(key);
940
- return false;
941
- }
942
- return true;
1309
+ const latestIndexedBlockTimestamps = chains.filter((chain) => chain.chainStatus !== ChainIndexingStatusIds.Queued).map((chain) => chain.latestIndexedBlock.timestamp);
1310
+ if (latestIndexedBlockTimestamps.length < 1) {
1311
+ throw new Error("latestIndexedBlockTimestamps array must include at least one element");
943
1312
  }
944
- delete(key) {
945
- return this._cache.delete(key);
1313
+ return Math.max(...latestIndexedBlockTimestamps);
1314
+ }
1315
+ function createIndexingConfig(startBlock, endBlock) {
1316
+ if (endBlock) {
1317
+ return {
1318
+ configType: ChainIndexingConfigTypeIds.Definite,
1319
+ startBlock,
1320
+ endBlock
1321
+ };
946
1322
  }
947
- };
948
-
949
- // src/shared/collections.ts
950
- var uniq = (arr) => [...new Set(arr)];
951
-
952
- // src/shared/datasource-contract.ts
953
- var import_datasources3 = require("@ensnode/datasources");
954
- var maybeGetDatasourceContract = (namespaceId, datasourceName, contractName) => {
955
- const datasource = (0, import_datasources3.maybeGetDatasource)(namespaceId, datasourceName);
956
- if (!datasource) return void 0;
957
- const address = datasource.contracts[contractName]?.address;
958
- if (address === void 0 || Array.isArray(address)) return void 0;
959
1323
  return {
960
- chainId: datasource.chain.id,
961
- address
1324
+ configType: ChainIndexingConfigTypeIds.Indefinite,
1325
+ startBlock
962
1326
  };
963
- };
964
- var getDatasourceContract = (namespaceId, datasourceName, contractName) => {
965
- const contract = maybeGetDatasourceContract(namespaceId, datasourceName, contractName);
966
- if (!contract) {
967
- throw new Error(
968
- `Expected contract not found for ${namespaceId} ${datasourceName} ${contractName}`
969
- );
970
- }
971
- return contract;
972
- };
973
- var makeContractMatcher = (namespace, b) => (datasourceName, contractName) => {
974
- const a = maybeGetDatasourceContract(namespace, datasourceName, contractName);
975
- return a && accountIdEqual(a, b);
976
- };
977
-
978
- // src/shared/interpretation/interpret-address.ts
979
- var import_viem9 = require("viem");
980
- var interpretAddress = (owner) => (0, import_viem9.isAddressEqual)(import_viem9.zeroAddress, owner) ? null : owner;
981
-
982
- // src/shared/interpretation/interpret-record-values.ts
983
- var import_viem10 = require("viem");
984
-
985
- // src/shared/null-bytes.ts
986
- var hasNullByte = (value) => value.indexOf("\0") !== -1;
987
- var stripNullBytes = (value) => value.replaceAll("\0", "");
988
-
989
- // src/shared/interpretation/interpret-record-values.ts
990
- function interpretNameRecordValue(value) {
991
- if (value === "") return null;
992
- if (!isNormalizedName(value)) return null;
993
- return value;
994
1327
  }
995
- function interpretAddressRecordValue(value) {
996
- if (hasNullByte(value)) return null;
997
- if (value === "") return null;
998
- if (value === "0x") return null;
999
- if (!(0, import_viem10.isAddress)(value)) return value;
1000
- if ((0, import_viem10.isAddressEqual)(value, import_viem10.zeroAddress)) return null;
1001
- return asLowerCaseAddress(value);
1328
+ function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(chains) {
1329
+ return chains.every((chain) => chain.chainStatus === ChainIndexingStatusIds.Queued);
1002
1330
  }
1003
- function interpretTextRecordKey(key) {
1004
- if (hasNullByte(key)) return null;
1005
- if (key === "") return null;
1006
- return key;
1331
+ function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(chains) {
1332
+ const atLeastOneChainInTargetStatus = chains.some(
1333
+ (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill
1334
+ );
1335
+ const otherChainsHaveValidStatuses = chains.every(
1336
+ (chain) => chain.chainStatus === ChainIndexingStatusIds.Queued || chain.chainStatus === ChainIndexingStatusIds.Backfill || chain.chainStatus === ChainIndexingStatusIds.Completed
1337
+ );
1338
+ return atLeastOneChainInTargetStatus && otherChainsHaveValidStatuses;
1007
1339
  }
1008
- function interpretTextRecordValue(value) {
1009
- if (hasNullByte(value)) return null;
1010
- if (value === "") return null;
1011
- return value;
1340
+ function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(chains) {
1341
+ const allChainsHaveValidStatuses = chains.every(
1342
+ (chain) => chain.chainStatus === ChainIndexingStatusIds.Completed
1343
+ );
1344
+ return allChainsHaveValidStatuses;
1012
1345
  }
1013
-
1014
- // src/shared/interpretation/interpret-tokenid.ts
1015
- var interpretTokenIdAsLabelHash = (tokenId) => uint256ToHex32(tokenId);
1016
- var interpretTokenIdAsNode = (tokenId) => uint256ToHex32(tokenId);
1017
-
1018
- // src/shared/interpretation/interpreted-names-and-labels.ts
1019
- var import_viem12 = require("viem");
1020
- var import_ens5 = require("viem/ens");
1021
-
1022
- // src/shared/labelhash.ts
1023
- var import_viem11 = require("viem");
1024
- var labelhashLiteralLabel = (label) => (0, import_viem11.keccak256)((0, import_viem11.stringToBytes)(label));
1025
-
1026
- // src/shared/interpretation/interpreted-names-and-labels.ts
1027
- function literalLabelToInterpretedLabel(label) {
1028
- if (isNormalizedLabel(label)) return label;
1029
- return encodeLabelHash(labelhashLiteralLabel(label));
1346
+ function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(chains) {
1347
+ const allChainsHaveValidStatuses = chains.some(
1348
+ (chain) => chain.chainStatus === ChainIndexingStatusIds.Following
1349
+ );
1350
+ return allChainsHaveValidStatuses;
1030
1351
  }
1031
- function literalLabelsToInterpretedName(labels) {
1032
- return labels.map(literalLabelToInterpretedLabel).join(".");
1352
+ function sortChainStatusesByStartBlockAsc(chains) {
1353
+ chains.sort(
1354
+ ([, chainA], [, chainB]) => chainA.config.startBlock.timestamp - chainB.config.startBlock.timestamp
1355
+ );
1356
+ return chains;
1033
1357
  }
1034
- function interpretedLabelsToInterpretedName(labels) {
1035
- return labels.join(".");
1358
+ function getLatestIndexedBlockRef(indexingStatus, chainId) {
1359
+ const chainIndexingStatus = indexingStatus.omnichainSnapshot.chains.get(chainId);
1360
+ if (chainIndexingStatus === void 0) {
1361
+ return null;
1362
+ }
1363
+ if (chainIndexingStatus.chainStatus === ChainIndexingStatusIds.Queued) {
1364
+ return null;
1365
+ }
1366
+ return chainIndexingStatus.latestIndexedBlock;
1036
1367
  }
1037
- function literalLabelsToLiteralName(labels) {
1038
- return labels.join(".");
1368
+
1369
+ // src/ensindexer/indexing-status/validations.ts
1370
+ function invariant_chainSnapshotQueuedBlocks(ctx) {
1371
+ const { config } = ctx.value;
1372
+ if (config.configType === ChainIndexingConfigTypeIds.Indefinite) {
1373
+ return;
1374
+ }
1375
+ if (config.endBlock && isBeforeOrEqualTo(config.startBlock, config.endBlock) === false) {
1376
+ ctx.issues.push({
1377
+ code: "custom",
1378
+ input: ctx.value,
1379
+ message: "`config.startBlock` must be before or same as `config.endBlock`."
1380
+ });
1381
+ }
1039
1382
  }
1040
- function interpretedNameToInterpretedLabels(name) {
1041
- return name.split(".");
1383
+ function invariant_chainSnapshotBackfillBlocks(ctx) {
1384
+ const { config, latestIndexedBlock, backfillEndBlock } = ctx.value;
1385
+ if (isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {
1386
+ ctx.issues.push({
1387
+ code: "custom",
1388
+ input: ctx.value,
1389
+ message: "`config.startBlock` must be before or same as `latestIndexedBlock`."
1390
+ });
1391
+ }
1392
+ if (isBeforeOrEqualTo(latestIndexedBlock, backfillEndBlock) === false) {
1393
+ ctx.issues.push({
1394
+ code: "custom",
1395
+ input: ctx.value,
1396
+ message: "`latestIndexedBlock` must be before or same as `backfillEndBlock`."
1397
+ });
1398
+ }
1399
+ if (config.configType === ChainIndexingConfigTypeIds.Indefinite) {
1400
+ return;
1401
+ }
1402
+ if (config.endBlock && isEqualTo(backfillEndBlock, config.endBlock) === false) {
1403
+ ctx.issues.push({
1404
+ code: "custom",
1405
+ input: ctx.value,
1406
+ message: "`backfillEndBlock` must be the same as `config.endBlock`."
1407
+ });
1408
+ }
1042
1409
  }
1043
- function encodedLabelToLabelhash(label) {
1044
- if (label.length !== 66) return null;
1045
- if (label.indexOf("[") !== 0) return null;
1046
- if (label.indexOf("]") !== 65) return null;
1047
- const hash = `0x${label.slice(1, 65)}`;
1048
- if (!(0, import_viem12.isHex)(hash)) return null;
1049
- return hash;
1410
+ function invariant_chainSnapshotCompletedBlocks(ctx) {
1411
+ const { config, latestIndexedBlock } = ctx.value;
1412
+ if (isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {
1413
+ ctx.issues.push({
1414
+ code: "custom",
1415
+ input: ctx.value,
1416
+ message: "`config.startBlock` must be before or same as `latestIndexedBlock`."
1417
+ });
1418
+ }
1419
+ if (isBeforeOrEqualTo(latestIndexedBlock, config.endBlock) === false) {
1420
+ ctx.issues.push({
1421
+ code: "custom",
1422
+ input: ctx.value,
1423
+ message: "`latestIndexedBlock` must be before or same as `config.endBlock`."
1424
+ });
1425
+ }
1050
1426
  }
1051
- function isInterpetedLabel(label) {
1052
- if (label.startsWith("[")) {
1053
- const labelHash = encodedLabelToLabelhash(label);
1054
- if (labelHash === null) return false;
1427
+ function invariant_chainSnapshotFollowingBlocks(ctx) {
1428
+ const { config, latestIndexedBlock, latestKnownBlock } = ctx.value;
1429
+ if (isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {
1430
+ ctx.issues.push({
1431
+ code: "custom",
1432
+ input: ctx.value,
1433
+ message: "`config.startBlock` must be before or same as `latestIndexedBlock`."
1434
+ });
1435
+ }
1436
+ if (isBeforeOrEqualTo(latestIndexedBlock, latestKnownBlock) === false) {
1437
+ ctx.issues.push({
1438
+ code: "custom",
1439
+ input: ctx.value,
1440
+ message: "`latestIndexedBlock` must be before or same as `latestKnownBlock`."
1441
+ });
1055
1442
  }
1056
- return isNormalizedLabel(label);
1057
1443
  }
1058
- function isInterpretedName(name) {
1059
- return name.split(".").every(isInterpetedLabel);
1444
+ function invariant_omnichainSnapshotStatusIsConsistentWithChainSnapshot(ctx) {
1445
+ const snapshot = ctx.value;
1446
+ const chains = Array.from(snapshot.chains.values());
1447
+ const expectedOmnichainStatus = getOmnichainIndexingStatus(chains);
1448
+ const actualOmnichainStatus = snapshot.omnichainStatus;
1449
+ if (expectedOmnichainStatus !== actualOmnichainStatus) {
1450
+ ctx.issues.push({
1451
+ code: "custom",
1452
+ input: snapshot,
1453
+ message: `'${actualOmnichainStatus}' is an invalid omnichainStatus. Expected '${expectedOmnichainStatus}' based on the statuses of individual chains.`
1454
+ });
1455
+ }
1060
1456
  }
1061
- function interpretedNameToLabelHashPath(name) {
1062
- return interpretedNameToInterpretedLabels(name).map((label) => {
1063
- if (!isInterpetedLabel(label)) {
1064
- throw new Error(
1065
- `Invariant(interpretedNameToLabelHashPath): Expected InterpretedLabel, received '${label}'.`
1066
- );
1067
- }
1068
- const maybeLabelHash = encodedLabelToLabelhash(label);
1069
- if (maybeLabelHash !== null) return maybeLabelHash;
1070
- return (0, import_ens5.labelhash)(label);
1071
- }).toReversed();
1457
+ function invariant_omnichainIndexingCursorLowerThanEarliestStartBlockAcrossQueuedChains(ctx) {
1458
+ const snapshot = ctx.value;
1459
+ const queuedChains = Array.from(snapshot.chains.values()).filter(
1460
+ (chain) => chain.chainStatus === ChainIndexingStatusIds.Queued
1461
+ );
1462
+ if (queuedChains.length === 0) {
1463
+ return;
1464
+ }
1465
+ const queuedChainStartBlocks = queuedChains.map((chain) => chain.config.startBlock.timestamp);
1466
+ const queuedChainEarliestStartBlock = Math.min(...queuedChainStartBlocks);
1467
+ if (snapshot.omnichainIndexingCursor >= queuedChainEarliestStartBlock) {
1468
+ ctx.issues.push({
1469
+ code: "custom",
1470
+ input: snapshot,
1471
+ message: "`omnichainIndexingCursor` must be lower than the earliest start block across all queued chains."
1472
+ });
1473
+ }
1072
1474
  }
1073
-
1074
- // src/shared/numbers.ts
1075
- function bigIntToNumber(n) {
1076
- if (n < Number.MIN_SAFE_INTEGER) {
1077
- throw new Error(
1078
- `The bigint '${n.toString()}' value is too low to be to converted into a number.'`
1079
- );
1475
+ function invariant_omnichainIndexingCursorLowerThanOrEqualToLatestBackfillEndBlockAcrossBackfillChains(ctx) {
1476
+ const snapshot = ctx.value;
1477
+ const backfillChains = Array.from(snapshot.chains.values()).filter(
1478
+ (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill
1479
+ );
1480
+ if (backfillChains.length === 0) {
1481
+ return;
1080
1482
  }
1081
- if (n > Number.MAX_SAFE_INTEGER) {
1082
- throw new Error(
1083
- `The bigint '${n.toString()}' value is too high to be to converted into a number.'`
1084
- );
1483
+ const backfillEndBlocks = backfillChains.map((chain) => chain.backfillEndBlock.timestamp);
1484
+ const highestBackfillEndBlock = Math.max(...backfillEndBlocks);
1485
+ if (snapshot.omnichainIndexingCursor > highestBackfillEndBlock) {
1486
+ ctx.issues.push({
1487
+ code: "custom",
1488
+ input: snapshot,
1489
+ message: "`omnichainIndexingCursor` must be lower than or equal to the highest `backfillEndBlock` across all backfill chains."
1490
+ });
1085
1491
  }
1086
- return Number(n);
1087
1492
  }
1088
-
1089
- // src/shared/root-registry.ts
1090
- var import_datasources4 = require("@ensnode/datasources");
1091
- var getENSv1Registry = (namespace) => getDatasourceContract(namespace, import_datasources4.DatasourceNames.ENSRoot, "ENSv1Registry");
1092
- var isENSv1Registry = (namespace, contract) => accountIdEqual(getENSv1Registry(namespace), contract);
1093
- var getENSv2RootRegistry = (namespace) => getDatasourceContract(namespace, import_datasources4.DatasourceNames.ENSv2Root, "RootRegistry");
1094
- var getENSv2RootRegistryId = (namespace) => makeRegistryId(getENSv2RootRegistry(namespace));
1095
- var isENSv2RootRegistry = (namespace, contract) => accountIdEqual(getENSv2RootRegistry(namespace), contract);
1096
-
1097
- // src/shared/serialize.ts
1098
- var import_caip2 = require("caip");
1099
- function serializeChainId(chainId) {
1100
- return chainId.toString();
1101
- }
1102
- function serializeDatetime(datetime) {
1103
- return datetime.toISOString();
1104
- }
1105
- function serializeUrl(url) {
1106
- return url.toString();
1107
- }
1108
- function serializePrice(price) {
1109
- return {
1110
- currency: price.currency,
1111
- amount: price.amount.toString()
1112
- };
1113
- }
1114
- function serializePriceEth(price) {
1115
- return serializePrice(price);
1116
- }
1117
- function formatAccountId(accountId) {
1118
- return import_caip2.AccountId.format({
1119
- chainId: { namespace: "eip155", reference: accountId.chainId.toString() },
1120
- address: accountId.address
1121
- }).toLowerCase();
1122
- }
1123
- function formatAssetId({
1124
- assetNamespace,
1125
- contract: { chainId, address },
1126
- tokenId
1127
- }) {
1128
- return import_caip2.AssetId.format({
1129
- chainId: { namespace: "eip155", reference: chainId.toString() },
1130
- assetName: { namespace: assetNamespace, reference: address },
1131
- tokenId: uint256ToHex32(tokenId)
1132
- }).toLowerCase();
1493
+ function invariant_omnichainIndexingCursorIsEqualToHighestLatestIndexedBlockAcrossIndexedChain(ctx) {
1494
+ const snapshot = ctx.value;
1495
+ const indexedChains = Array.from(snapshot.chains.values()).filter(
1496
+ (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill || chain.chainStatus === ChainIndexingStatusIds.Completed || chain.chainStatus === ChainIndexingStatusIds.Following
1497
+ );
1498
+ if (indexedChains.length === 0) {
1499
+ return;
1500
+ }
1501
+ const indexedChainLatestIndexedBlocks = indexedChains.map(
1502
+ (chain) => chain.latestIndexedBlock.timestamp
1503
+ );
1504
+ const indexedChainHighestLatestIndexedBlock = Math.max(...indexedChainLatestIndexedBlocks);
1505
+ if (snapshot.omnichainIndexingCursor !== indexedChainHighestLatestIndexedBlock) {
1506
+ ctx.issues.push({
1507
+ code: "custom",
1508
+ input: snapshot,
1509
+ message: "`omnichainIndexingCursor` must be same as the highest `latestIndexedBlock` across all indexed chains."
1510
+ });
1511
+ }
1133
1512
  }
1134
-
1135
- // src/shared/types.ts
1136
- var AssetNamespaces = {
1137
- ERC721: "erc721",
1138
- ERC1155: "erc1155"
1139
- };
1140
-
1141
- // src/shared/url.ts
1142
- function isHttpProtocol(url) {
1143
- return ["http:", "https:"].includes(url.protocol);
1513
+ function invariant_omnichainSnapshotUnstartedHasValidChains(ctx) {
1514
+ const chains = ctx.value;
1515
+ const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(
1516
+ Array.from(chains.values())
1517
+ );
1518
+ if (hasValidChains === false) {
1519
+ ctx.issues.push({
1520
+ code: "custom",
1521
+ input: chains,
1522
+ message: `For omnichain status snapshot 'unstarted', all chains must have "queued" status.`
1523
+ });
1524
+ }
1144
1525
  }
1145
- function isWebSocketProtocol(url) {
1146
- return ["ws:", "wss:"].includes(url.protocol);
1526
+ function invariant_omnichainStatusSnapshotBackfillHasValidChains(ctx) {
1527
+ const chains = ctx.value;
1528
+ const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(
1529
+ Array.from(chains.values())
1530
+ );
1531
+ if (hasValidChains === false) {
1532
+ ctx.issues.push({
1533
+ code: "custom",
1534
+ input: chains,
1535
+ message: `For omnichain status snapshot 'backfill', at least one chain must be in "backfill" status and each chain has to have a status of either "queued", "backfill" or "completed".`
1536
+ });
1537
+ }
1147
1538
  }
1148
-
1149
- // src/ensindexer/config/is-subgraph-compatible.ts
1150
- var import_datasources5 = require("@ensnode/datasources");
1151
-
1152
- // src/ensindexer/config/types.ts
1153
- var PluginName = /* @__PURE__ */ ((PluginName2) => {
1154
- PluginName2["Subgraph"] = "subgraph";
1155
- PluginName2["Basenames"] = "basenames";
1156
- PluginName2["Lineanames"] = "lineanames";
1157
- PluginName2["ThreeDNS"] = "threedns";
1158
- PluginName2["ProtocolAcceleration"] = "protocol-acceleration";
1159
- PluginName2["Registrars"] = "registrars";
1160
- PluginName2["TokenScope"] = "tokenscope";
1161
- PluginName2["ENSv2"] = "ensv2";
1162
- return PluginName2;
1163
- })(PluginName || {});
1164
-
1165
- // src/ensindexer/config/is-subgraph-compatible.ts
1166
- function isSubgraphCompatible(config) {
1167
- const onlySubgraphPluginActivated = config.plugins.length === 1 && config.plugins[0] === "subgraph" /* Subgraph */;
1168
- const isSubgraphLabelSet = config.labelSet.labelSetId === "subgraph" && config.labelSet.labelSetVersion === 0;
1169
- const isEnsTestEnvLabelSet = config.labelSet.labelSetId === "ens-test-env" && config.labelSet.labelSetVersion === 0;
1170
- const labelSetIsSubgraphCompatible = isSubgraphLabelSet || config.namespace === import_datasources5.ENSNamespaceIds.EnsTestEnv && isEnsTestEnvLabelSet;
1171
- return onlySubgraphPluginActivated && labelSetIsSubgraphCompatible;
1539
+ function invariant_omnichainStatusSnapshotCompletedHasValidChains(ctx) {
1540
+ const chains = ctx.value;
1541
+ const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(
1542
+ Array.from(chains.values())
1543
+ );
1544
+ if (hasValidChains === false) {
1545
+ ctx.issues.push({
1546
+ code: "custom",
1547
+ input: chains,
1548
+ message: `For omnichain status snapshot 'completed', all chains must have "completed" status.`
1549
+ });
1550
+ }
1172
1551
  }
1173
-
1174
- // src/ensindexer/config/validations.ts
1175
- function invariant_ensDbVersionIsSameAsEnsIndexerVersion(ctx) {
1176
- const versionInfo = ctx.value;
1177
- if (versionInfo.ensDb !== versionInfo.ensIndexer) {
1552
+ function invariant_slowestChainEqualsToOmnichainSnapshotTime(ctx) {
1553
+ const { slowestChainIndexingCursor, omnichainSnapshot } = ctx.value;
1554
+ const { omnichainIndexingCursor } = omnichainSnapshot;
1555
+ if (slowestChainIndexingCursor !== omnichainIndexingCursor) {
1556
+ console.log("invariant_slowestChainEqualsToOmnichainSnapshotTime", {
1557
+ slowestChainIndexingCursor,
1558
+ omnichainIndexingCursor
1559
+ });
1178
1560
  ctx.issues.push({
1179
1561
  code: "custom",
1180
- input: versionInfo,
1181
- message: "`ensDb` version must be same as `ensIndexer` version"
1562
+ input: ctx.value,
1563
+ message: `'slowestChainIndexingCursor' must be equal to 'omnichainSnapshot.omnichainIndexingCursor'`
1182
1564
  });
1183
1565
  }
1184
1566
  }
1185
-
1186
- // src/ensindexer/config/zod-schemas.ts
1187
- var makeIndexedChainIdsSchema = (valueLabel = "Indexed Chain IDs") => import_v43.z.array(makeChainIdSchema(valueLabel), {
1188
- error: `${valueLabel} must be an array.`
1189
- }).min(1, { error: `${valueLabel} list must include at least one element.` }).transform((v) => new Set(v));
1190
- var makePluginsListSchema = (valueLabel = "Plugins") => import_v43.z.array(import_v43.z.string(), {
1191
- error: `${valueLabel} must be a list of strings.`
1192
- }).min(1, {
1193
- error: `${valueLabel} must be a list of strings with at least one string value`
1194
- }).refine((arr) => arr.length === uniq(arr).length, {
1195
- error: `${valueLabel} cannot contain duplicate values.`
1196
- });
1197
- var makeDatabaseSchemaNameSchema = (valueLabel = "Database schema name") => import_v43.z.string({ error: `${valueLabel} must be a string` }).trim().nonempty({
1198
- error: `${valueLabel} is required and must be a non-empty string.`
1199
- });
1200
- var makeLabelSetIdSchema = (valueLabel) => {
1201
- return import_v43.z.string({ error: `${valueLabel} must be a string` }).min(1, { error: `${valueLabel} must be 1-50 characters long` }).max(50, { error: `${valueLabel} must be 1-50 characters long` }).regex(/^[a-z-]+$/, {
1202
- error: `${valueLabel} can only contain lowercase letters (a-z) and hyphens (-)`
1203
- });
1204
- };
1205
- var makeLabelSetVersionSchema = (valueLabel) => {
1206
- return import_v43.z.coerce.number({ error: `${valueLabel} must be an integer.` }).pipe(makeNonNegativeIntegerSchema(valueLabel));
1207
- };
1208
- var makeFullyPinnedLabelSetSchema = (valueLabel = "Label set") => {
1209
- let valueLabelLabelSetId = valueLabel;
1210
- let valueLabelLabelSetVersion = valueLabel;
1211
- if (valueLabel === "LABEL_SET") {
1212
- valueLabelLabelSetId = "LABEL_SET_ID";
1213
- valueLabelLabelSetVersion = "LABEL_SET_VERSION";
1214
- } else {
1215
- valueLabelLabelSetId = `${valueLabel}.labelSetId`;
1216
- valueLabelLabelSetVersion = `${valueLabel}.labelSetVersion`;
1567
+ function invariant_snapshotTimeIsTheHighestKnownBlockTimestamp(ctx) {
1568
+ const { snapshotTime, omnichainSnapshot } = ctx.value;
1569
+ const chains = Array.from(omnichainSnapshot.chains.values());
1570
+ const startBlockTimestamps = chains.map((chain) => chain.config.startBlock.timestamp);
1571
+ const endBlockTimestamps = chains.map((chain) => chain.config).filter((chainConfig) => chainConfig.configType === ChainIndexingConfigTypeIds.Definite).map((chainConfig) => chainConfig.endBlock.timestamp);
1572
+ const backfillEndBlockTimestamps = chains.filter((chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill).map((chain) => chain.backfillEndBlock.timestamp);
1573
+ const latestKnownBlockTimestamps = chains.filter((chain) => chain.chainStatus === ChainIndexingStatusIds.Following).map((chain) => chain.latestKnownBlock.timestamp);
1574
+ const highestKnownBlockTimestamp = Math.max(
1575
+ ...startBlockTimestamps,
1576
+ ...endBlockTimestamps,
1577
+ ...backfillEndBlockTimestamps,
1578
+ ...latestKnownBlockTimestamps
1579
+ );
1580
+ if (snapshotTime < highestKnownBlockTimestamp) {
1581
+ ctx.issues.push({
1582
+ code: "custom",
1583
+ input: ctx.value,
1584
+ message: `'snapshotTime' (${snapshotTime}) must be greater than or equal to the "highest known block timestamp" (${highestKnownBlockTimestamp})`
1585
+ });
1217
1586
  }
1218
- return import_v43.z.object({
1219
- labelSetId: makeLabelSetIdSchema(valueLabelLabelSetId),
1220
- labelSetVersion: makeLabelSetVersionSchema(valueLabelLabelSetVersion)
1221
- });
1222
- };
1223
- var makeNonEmptyStringSchema = (valueLabel = "Value") => import_v43.z.string().nonempty({ error: `${valueLabel} must be a non-empty string.` });
1224
- var makeENSIndexerVersionInfoSchema = (valueLabel = "Value") => import_v43.z.strictObject(
1225
- {
1226
- nodejs: makeNonEmptyStringSchema(),
1227
- ponder: makeNonEmptyStringSchema(),
1228
- ensDb: makeNonEmptyStringSchema(),
1229
- ensIndexer: makeNonEmptyStringSchema(),
1230
- ensNormalize: makeNonEmptyStringSchema(),
1231
- ensRainbow: makeNonEmptyStringSchema(),
1232
- ensRainbowSchema: makePositiveIntegerSchema()
1233
- },
1234
- {
1235
- error: `${valueLabel} must be a valid ENSIndexerVersionInfo object.`
1587
+ }
1588
+ function invariant_realtimeIndexingStatusProjectionProjectedAtIsAfterOrEqualToSnapshotTime(ctx) {
1589
+ const projection = ctx.value;
1590
+ const { snapshot, projectedAt } = projection;
1591
+ if (snapshot.snapshotTime > projectedAt) {
1592
+ ctx.issues.push({
1593
+ code: "custom",
1594
+ input: projection,
1595
+ message: "`projectedAt` must be after or same as `snapshot.snapshotTime`."
1596
+ });
1236
1597
  }
1237
- ).check(invariant_ensDbVersionIsSameAsEnsIndexerVersion);
1238
- function invariant_isSubgraphCompatibleRequirements(ctx) {
1239
- const { value: config } = ctx;
1240
- if (config.isSubgraphCompatible && !isSubgraphCompatible(config)) {
1598
+ }
1599
+ function invariant_realtimeIndexingStatusProjectionWorstCaseDistanceIsCorrect(ctx) {
1600
+ const projection = ctx.value;
1601
+ const { projectedAt, snapshot, worstCaseDistance } = projection;
1602
+ const { omnichainSnapshot } = snapshot;
1603
+ const expectedWorstCaseDistance = projectedAt - omnichainSnapshot.omnichainIndexingCursor;
1604
+ if (worstCaseDistance !== expectedWorstCaseDistance) {
1241
1605
  ctx.issues.push({
1242
1606
  code: "custom",
1243
- input: config,
1244
- message: `'isSubgraphCompatible' requires only the '${"subgraph" /* Subgraph */}' plugin to be active and labelSet must be {labelSetId: "subgraph", labelSetVersion: 0}`
1607
+ input: projection,
1608
+ message: "`worstCaseDistance` must be the exact difference between `projectedAt` and `snapshot.omnichainIndexingCursor`."
1245
1609
  });
1246
1610
  }
1247
1611
  }
1248
- var makeENSIndexerPublicConfigSchema = (valueLabel = "ENSIndexerPublicConfig") => import_v43.z.object({
1249
- labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`),
1250
- indexedChainIds: makeIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),
1251
- isSubgraphCompatible: import_v43.z.boolean({ error: `${valueLabel}.isSubgraphCompatible` }),
1252
- namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),
1253
- plugins: makePluginsListSchema(`${valueLabel}.plugins`),
1254
- databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),
1255
- versionInfo: makeENSIndexerVersionInfoSchema(`${valueLabel}.versionInfo`)
1256
- }).check(invariant_isSubgraphCompatibleRequirements);
1257
1612
 
1258
- // src/shared/config/thegraph.ts
1259
- var import_v44 = require("zod/v4");
1260
- var TheGraphCannotFallbackReasonSchema = import_v44.z.enum({
1261
- NotSubgraphCompatible: "not-subgraph-compatible",
1262
- NoApiKey: "no-api-key",
1263
- NoSubgraphUrl: "no-subgraph-url"
1264
- });
1265
- var TheGraphFallbackSchema = import_v44.z.discriminatedUnion("canFallback", [
1266
- import_v44.z.strictObject({
1267
- canFallback: import_v44.z.literal(true),
1268
- url: import_v44.z.string()
1613
+ // src/ensindexer/indexing-status/zod-schemas.ts
1614
+ var makeChainIndexingConfigSchema = (valueLabel = "Value") => import_v48.z.discriminatedUnion("configType", [
1615
+ import_v48.z.strictObject({
1616
+ configType: import_v48.z.literal(ChainIndexingConfigTypeIds.Indefinite),
1617
+ startBlock: makeBlockRefSchema(valueLabel)
1269
1618
  }),
1270
- import_v44.z.strictObject({
1271
- canFallback: import_v44.z.literal(false),
1272
- reason: TheGraphCannotFallbackReasonSchema
1619
+ import_v48.z.strictObject({
1620
+ configType: import_v48.z.literal(ChainIndexingConfigTypeIds.Definite),
1621
+ startBlock: makeBlockRefSchema(valueLabel),
1622
+ endBlock: makeBlockRefSchema(valueLabel)
1273
1623
  })
1274
1624
  ]);
1275
-
1276
- // src/ensapi/config/zod-schemas.ts
1277
- function makeENSApiPublicConfigSchema(valueLabel) {
1278
- const label = valueLabel ?? "ENSApiPublicConfig";
1279
- return import_v45.z.strictObject({
1280
- version: import_v45.z.string().min(1, `${label}.version must be a non-empty string`),
1281
- theGraphFallback: TheGraphFallbackSchema,
1282
- ensIndexerPublicConfig: makeENSIndexerPublicConfigSchema(`${label}.ensIndexerPublicConfig`)
1283
- });
1284
- }
1285
-
1286
- // src/ensapi/config/deserialize.ts
1287
- function deserializeENSApiPublicConfig(maybeConfig, valueLabel) {
1288
- const schema = makeENSApiPublicConfigSchema(valueLabel);
1289
- try {
1290
- return schema.parse(maybeConfig);
1291
- } catch (error) {
1292
- if (error instanceof import_v46.ZodError) {
1293
- throw new Error(`Cannot deserialize ENSApiPublicConfig:
1294
- ${(0, import_v46.prettifyError)(error)}
1295
- `);
1296
- }
1297
- throw error;
1625
+ var makeChainIndexingStatusSnapshotQueuedSchema = (valueLabel = "Value") => import_v48.z.strictObject({
1626
+ chainStatus: import_v48.z.literal(ChainIndexingStatusIds.Queued),
1627
+ config: makeChainIndexingConfigSchema(valueLabel)
1628
+ }).check(invariant_chainSnapshotQueuedBlocks);
1629
+ var makeChainIndexingStatusSnapshotBackfillSchema = (valueLabel = "Value") => import_v48.z.strictObject({
1630
+ chainStatus: import_v48.z.literal(ChainIndexingStatusIds.Backfill),
1631
+ config: makeChainIndexingConfigSchema(valueLabel),
1632
+ latestIndexedBlock: makeBlockRefSchema(valueLabel),
1633
+ backfillEndBlock: makeBlockRefSchema(valueLabel)
1634
+ }).check(invariant_chainSnapshotBackfillBlocks);
1635
+ var makeChainIndexingStatusSnapshotCompletedSchema = (valueLabel = "Value") => import_v48.z.strictObject({
1636
+ chainStatus: import_v48.z.literal(ChainIndexingStatusIds.Completed),
1637
+ config: import_v48.z.strictObject({
1638
+ configType: import_v48.z.literal(ChainIndexingConfigTypeIds.Definite),
1639
+ startBlock: makeBlockRefSchema(valueLabel),
1640
+ endBlock: makeBlockRefSchema(valueLabel)
1641
+ }),
1642
+ latestIndexedBlock: makeBlockRefSchema(valueLabel)
1643
+ }).check(invariant_chainSnapshotCompletedBlocks);
1644
+ var makeChainIndexingStatusSnapshotFollowingSchema = (valueLabel = "Value") => import_v48.z.strictObject({
1645
+ chainStatus: import_v48.z.literal(ChainIndexingStatusIds.Following),
1646
+ config: import_v48.z.strictObject({
1647
+ configType: import_v48.z.literal(ChainIndexingConfigTypeIds.Indefinite),
1648
+ startBlock: makeBlockRefSchema(valueLabel)
1649
+ }),
1650
+ latestIndexedBlock: makeBlockRefSchema(valueLabel),
1651
+ latestKnownBlock: makeBlockRefSchema(valueLabel)
1652
+ }).check(invariant_chainSnapshotFollowingBlocks);
1653
+ var makeChainIndexingStatusSnapshotSchema = (valueLabel = "Value") => import_v48.z.discriminatedUnion("chainStatus", [
1654
+ makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),
1655
+ makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),
1656
+ makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),
1657
+ makeChainIndexingStatusSnapshotFollowingSchema(valueLabel)
1658
+ ]);
1659
+ var makeChainIndexingStatusesSchema = (valueLabel = "Value") => import_v48.z.record(makeChainIdStringSchema(), makeChainIndexingStatusSnapshotSchema(valueLabel), {
1660
+ error: "Chains indexing statuses must be an object mapping valid chain IDs to their indexing status snapshots."
1661
+ }).transform((serializedChainsIndexingStatus) => {
1662
+ const chainsIndexingStatus = /* @__PURE__ */ new Map();
1663
+ for (const [chainIdString, chainStatus] of Object.entries(serializedChainsIndexingStatus)) {
1664
+ chainsIndexingStatus.set(deserializeChainId(chainIdString), chainStatus);
1298
1665
  }
1299
- }
1666
+ return chainsIndexingStatus;
1667
+ });
1668
+ var makeOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel) => import_v48.z.strictObject({
1669
+ omnichainStatus: import_v48.z.literal(OmnichainIndexingStatusIds.Unstarted),
1670
+ chains: makeChainIndexingStatusesSchema(valueLabel).check(invariant_omnichainSnapshotUnstartedHasValidChains).transform((chains) => chains),
1671
+ omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel)
1672
+ });
1673
+ var makeOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel) => import_v48.z.strictObject({
1674
+ omnichainStatus: import_v48.z.literal(OmnichainIndexingStatusIds.Backfill),
1675
+ chains: makeChainIndexingStatusesSchema(valueLabel).check(invariant_omnichainStatusSnapshotBackfillHasValidChains).transform(
1676
+ (chains) => chains
1677
+ ),
1678
+ omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel)
1679
+ });
1680
+ var makeOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel) => import_v48.z.strictObject({
1681
+ omnichainStatus: import_v48.z.literal(OmnichainIndexingStatusIds.Completed),
1682
+ chains: makeChainIndexingStatusesSchema(valueLabel).check(invariant_omnichainStatusSnapshotCompletedHasValidChains).transform((chains) => chains),
1683
+ omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel)
1684
+ });
1685
+ var makeOmnichainIndexingStatusSnapshotFollowingSchema = (valueLabel) => import_v48.z.strictObject({
1686
+ omnichainStatus: import_v48.z.literal(OmnichainIndexingStatusIds.Following),
1687
+ chains: makeChainIndexingStatusesSchema(valueLabel),
1688
+ omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel)
1689
+ });
1690
+ var makeOmnichainIndexingStatusSnapshotSchema = (valueLabel = "Omnichain Indexing Snapshot") => import_v48.z.discriminatedUnion("omnichainStatus", [
1691
+ makeOmnichainIndexingStatusSnapshotUnstartedSchema(valueLabel),
1692
+ makeOmnichainIndexingStatusSnapshotBackfillSchema(valueLabel),
1693
+ makeOmnichainIndexingStatusSnapshotCompletedSchema(valueLabel),
1694
+ makeOmnichainIndexingStatusSnapshotFollowingSchema(valueLabel)
1695
+ ]).check(invariant_omnichainSnapshotStatusIsConsistentWithChainSnapshot).check(invariant_omnichainIndexingCursorLowerThanEarliestStartBlockAcrossQueuedChains).check(
1696
+ invariant_omnichainIndexingCursorLowerThanOrEqualToLatestBackfillEndBlockAcrossBackfillChains
1697
+ ).check(invariant_omnichainIndexingCursorIsEqualToHighestLatestIndexedBlockAcrossIndexedChain);
1698
+ var makeCrossChainIndexingStatusSnapshotOmnichainSchema = (valueLabel = "Cross-chain Indexing Status Snapshot Omnichain") => import_v48.z.strictObject({
1699
+ strategy: import_v48.z.literal(CrossChainIndexingStrategyIds.Omnichain),
1700
+ slowestChainIndexingCursor: makeUnixTimestampSchema(valueLabel),
1701
+ snapshotTime: makeUnixTimestampSchema(valueLabel),
1702
+ omnichainSnapshot: makeOmnichainIndexingStatusSnapshotSchema(valueLabel)
1703
+ }).check(invariant_slowestChainEqualsToOmnichainSnapshotTime).check(invariant_snapshotTimeIsTheHighestKnownBlockTimestamp);
1704
+ var makeCrossChainIndexingStatusSnapshotSchema = (valueLabel = "Cross-chain Indexing Status Snapshot") => import_v48.z.discriminatedUnion("strategy", [
1705
+ makeCrossChainIndexingStatusSnapshotOmnichainSchema(valueLabel)
1706
+ ]);
1707
+ var makeRealtimeIndexingStatusProjectionSchema = (valueLabel = "Realtime Indexing Status Projection") => import_v48.z.strictObject({
1708
+ projectedAt: makeUnixTimestampSchema(valueLabel),
1709
+ worstCaseDistance: makeDurationSchema(valueLabel),
1710
+ snapshot: makeCrossChainIndexingStatusSnapshotSchema(valueLabel)
1711
+ }).check(invariant_realtimeIndexingStatusProjectionProjectedAtIsAfterOrEqualToSnapshotTime).check(invariant_realtimeIndexingStatusProjectionWorstCaseDistanceIsCorrect);
1300
1712
 
1301
- // src/ensindexer/config/deserialize.ts
1302
- var import_v47 = require("zod/v4");
1303
- function deserializeENSIndexerPublicConfig(maybeConfig, valueLabel) {
1304
- const schema = makeENSIndexerPublicConfigSchema(valueLabel);
1305
- const parsed = schema.safeParse(maybeConfig);
1713
+ // src/ensindexer/indexing-status/deserialize.ts
1714
+ function deserializeChainIndexingStatusSnapshot(maybeSnapshot, valueLabel) {
1715
+ const schema = makeChainIndexingStatusSnapshotSchema(valueLabel);
1716
+ const parsed = schema.safeParse(maybeSnapshot);
1306
1717
  if (parsed.error) {
1307
- throw new Error(`Cannot deserialize ENSIndexerPublicConfig:
1308
- ${(0, import_v47.prettifyError)(parsed.error)}
1309
- `);
1718
+ throw new Error(
1719
+ `Cannot deserialize into ChainIndexingStatusSnapshot:
1720
+ ${(0, import_v49.prettifyError)(parsed.error)}
1721
+ `
1722
+ );
1310
1723
  }
1311
1724
  return parsed.data;
1312
1725
  }
1313
-
1314
- // src/ensindexer/config/label-utils.ts
1315
- var import_viem13 = require("viem");
1316
- function labelHashToBytes(labelHash) {
1317
- try {
1318
- if (labelHash.length !== 66) {
1319
- throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);
1320
- }
1321
- if (labelHash !== labelHash.toLowerCase()) {
1322
- throw new Error("Labelhash must be in lowercase");
1323
- }
1324
- if (!labelHash.startsWith("0x")) {
1325
- throw new Error("Labelhash must be 0x-prefixed");
1326
- }
1327
- const bytes = (0, import_viem13.hexToBytes)(labelHash);
1328
- if (bytes.length !== 32) {
1329
- throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);
1330
- }
1331
- return bytes;
1332
- } catch (e) {
1333
- if (e instanceof Error) {
1334
- throw e;
1335
- }
1336
- throw new Error("Invalid hex format");
1337
- }
1338
- }
1339
-
1340
- // src/ensindexer/config/labelset-utils.ts
1341
- function buildLabelSetId(maybeLabelSetId) {
1342
- return makeLabelSetIdSchema("LabelSetId").parse(maybeLabelSetId);
1343
- }
1344
- function buildLabelSetVersion(maybeLabelSetVersion) {
1345
- return makeLabelSetVersionSchema("LabelSetVersion").parse(maybeLabelSetVersion);
1346
- }
1347
- function buildEnsRainbowClientLabelSet(labelSetId, labelSetVersion) {
1348
- if (labelSetVersion !== void 0 && labelSetId === void 0) {
1349
- throw new Error("When a labelSetVersion is defined, labelSetId must also be defined.");
1350
- }
1351
- return { labelSetId, labelSetVersion };
1352
- }
1353
- function validateSupportedLabelSetAndVersion(serverSet, clientSet) {
1354
- if (clientSet.labelSetId === void 0) {
1355
- return;
1356
- }
1357
- if (serverSet.labelSetId !== clientSet.labelSetId) {
1726
+ function deserializeOmnichainIndexingStatusSnapshot(maybeSnapshot, valueLabel) {
1727
+ const schema = makeOmnichainIndexingStatusSnapshotSchema(valueLabel);
1728
+ const parsed = schema.safeParse(maybeSnapshot);
1729
+ if (parsed.error) {
1358
1730
  throw new Error(
1359
- `Server label set ID "${serverSet.labelSetId}" does not match client's requested label set ID "${clientSet.labelSetId}".`
1731
+ `Cannot deserialize into OmnichainIndexingStatusSnapshot:
1732
+ ${(0, import_v49.prettifyError)(parsed.error)}
1733
+ `
1360
1734
  );
1361
1735
  }
1362
- if (clientSet.labelSetVersion !== void 0 && serverSet.highestLabelSetVersion < clientSet.labelSetVersion) {
1736
+ return parsed.data;
1737
+ }
1738
+ function deserializeCrossChainIndexingStatusSnapshot(maybeSnapshot, valueLabel) {
1739
+ const schema = makeCrossChainIndexingStatusSnapshotSchema(valueLabel);
1740
+ const parsed = schema.safeParse(maybeSnapshot);
1741
+ if (parsed.error) {
1363
1742
  throw new Error(
1364
- `Server highest label set version ${serverSet.highestLabelSetVersion} is less than client's requested version ${clientSet.labelSetVersion} for label set ID "${clientSet.labelSetId}".`
1743
+ `Cannot deserialize into CrossChainIndexingStatusSnapshot:
1744
+ ${(0, import_v49.prettifyError)(parsed.error)}
1745
+ `
1365
1746
  );
1366
1747
  }
1748
+ return parsed.data;
1367
1749
  }
1368
-
1369
- // src/ensindexer/config/parsing.ts
1370
- function parseNonNegativeInteger(maybeNumber) {
1371
- const trimmed = maybeNumber.trim();
1372
- if (!trimmed) {
1373
- throw new Error("Input cannot be empty");
1374
- }
1375
- if (trimmed === "-0") {
1376
- throw new Error("Negative zero is not a valid non-negative integer");
1377
- }
1378
- const num = Number(maybeNumber);
1379
- if (Number.isNaN(num)) {
1380
- throw new Error(`"${maybeNumber}" is not a valid number`);
1381
- }
1382
- if (!Number.isFinite(num)) {
1383
- throw new Error(`"${maybeNumber}" is not a finite number`);
1384
- }
1385
- if (!Number.isInteger(num)) {
1386
- throw new Error(`"${maybeNumber}" is not an integer`);
1387
- }
1388
- if (num < 0) {
1389
- throw new Error(`"${maybeNumber}" is not a non-negative integer`);
1750
+ function deserializeRealtimeIndexingStatusProjection(maybeProjection, valueLabel) {
1751
+ const schema = makeRealtimeIndexingStatusProjectionSchema(valueLabel);
1752
+ const parsed = schema.safeParse(maybeProjection);
1753
+ if (parsed.error) {
1754
+ throw new Error(
1755
+ `Cannot deserialize into RealtimeIndexingStatusProjection:
1756
+ ${(0, import_v49.prettifyError)(parsed.error)}
1757
+ `
1758
+ );
1390
1759
  }
1391
- return num;
1760
+ return parsed.data;
1392
1761
  }
1393
1762
 
1394
- // src/ensindexer/config/serialize.ts
1395
- function serializeIndexedChainIds(indexedChainIds) {
1396
- return Array.from(indexedChainIds);
1397
- }
1398
- function serializeENSIndexerPublicConfig(config) {
1399
- const {
1400
- labelSet,
1401
- indexedChainIds,
1402
- databaseSchemaName,
1403
- isSubgraphCompatible: isSubgraphCompatible2,
1404
- namespace,
1405
- plugins,
1406
- versionInfo
1407
- } = config;
1763
+ // src/ensindexer/indexing-status/projection.ts
1764
+ function createRealtimeIndexingStatusProjection(snapshot, now) {
1765
+ const projectedAt = Math.max(now, snapshot.snapshotTime);
1408
1766
  return {
1409
- labelSet,
1410
- indexedChainIds: serializeIndexedChainIds(indexedChainIds),
1411
- databaseSchemaName,
1412
- isSubgraphCompatible: isSubgraphCompatible2,
1413
- namespace,
1414
- plugins,
1415
- versionInfo
1767
+ projectedAt,
1768
+ worstCaseDistance: projectedAt - snapshot.slowestChainIndexingCursor,
1769
+ snapshot
1416
1770
  };
1417
1771
  }
1418
1772
 
1419
- // src/ensindexer/indexing-status/deserialize.ts
1420
- var import_v49 = require("zod/v4");
1421
-
1422
- // src/ensindexer/indexing-status/zod-schemas.ts
1423
- var import_v48 = require("zod/v4");
1424
-
1425
- // src/ensindexer/indexing-status/types.ts
1426
- var ChainIndexingConfigTypeIds = {
1427
- /**
1428
- * Represents that indexing of the chain should be performed for an indefinite range.
1429
- */
1430
- Indefinite: "indefinite",
1431
- /**
1432
- * Represents that indexing of the chain should be performed for a definite range.
1433
- */
1434
- Definite: "definite"
1435
- };
1436
- var ChainIndexingStatusIds = {
1437
- /**
1438
- * Represents that indexing of the chain is not ready to begin yet because:
1439
- * - ENSIndexer is in its initialization phase and the data to build a
1440
- * "true" {@link ChainIndexingSnapshot} for the chain is still being loaded; or
1441
- * - ENSIndexer is using an omnichain indexing strategy and the
1442
- * `omnichainIndexingCursor` is <= `config.startBlock.timestamp` for the chain's
1443
- * {@link ChainIndexingSnapshot}.
1444
- */
1445
- Queued: "chain-queued",
1446
- /**
1447
- * Represents that indexing of the chain is in progress and under a special
1448
- * "backfill" phase that optimizes for accelerated indexing until reaching the
1449
- * "fixed target" `backfillEndBlock`.
1450
- */
1451
- Backfill: "chain-backfill",
1452
- /**
1453
- * Represents that the "backfill" phase of indexing the chain is completed
1454
- * and that the chain is configured to be indexed for an indefinite range.
1455
- * Therefore, indexing of the chain remains indefinitely in progress where
1456
- * ENSIndexer will continuously work to discover and index new blocks as they
1457
- * are added to the chain across time.
1458
- */
1459
- Following: "chain-following",
1460
- /**
1461
- * Represents that indexing of the chain is completed as the chain is configured
1462
- * to be indexed for a definite range and the indexing of all blocks through
1463
- * that definite range is completed.
1464
- */
1465
- Completed: "chain-completed"
1466
- };
1467
- var OmnichainIndexingStatusIds = {
1468
- /**
1469
- * Represents that omnichain indexing is not ready to begin yet because
1470
- * ENSIndexer is in its initialization phase and the data to build a "true"
1471
- * {@link OmnichainIndexingStatusSnapshot} is still being loaded.
1472
- */
1473
- Unstarted: "omnichain-unstarted",
1474
- /**
1475
- * Represents that omnichain indexing is in an overall "backfill" status because
1476
- * - At least one indexed chain has a `chainStatus` of
1477
- * {@link ChainIndexingStatusIds.Backfill}; and
1478
- * - No indexed chain has a `chainStatus` of {@link ChainIndexingStatusIds.Following}.
1479
- */
1480
- Backfill: "omnichain-backfill",
1481
- /**
1482
- * Represents that omnichain indexing is in an overall "following" status because
1483
- * at least one indexed chain has a `chainStatus` of
1484
- * {@link ChainIndexingStatusIds.Following}.
1485
- */
1486
- Following: "omnichain-following",
1487
- /**
1488
- * Represents that omnichain indexing has completed because all indexed chains have
1489
- * a `chainStatus` of {@link ChainIndexingStatusIds.Completed}.
1490
- */
1491
- Completed: "omnichain-completed"
1492
- };
1493
- var CrossChainIndexingStrategyIds = {
1494
- /**
1495
- * Represents that the indexing of events across all indexed chains will
1496
- * proceed in a deterministic "omnichain" ordering by block timestamp, chain ID,
1497
- * and block number.
1498
- *
1499
- * This strategy is "deterministic" in that the order of processing cross-chain indexed
1500
- * events and each resulting indexed data state transition recorded in ENSDb is always
1501
- * the same for each ENSIndexer instance operating with an equivalent
1502
- * `ENSIndexerConfig` and ENSIndexer version. However it also has the drawbacks of:
1503
- * - increased indexing latency that must wait for the slowest indexed chain to
1504
- * add new blocks or to discover new blocks through the configured RPCs.
1505
- * - if any indexed chain gets "stuck" due to chain or RPC failures, all indexed chains
1506
- * will be affected.
1507
- */
1508
- Omnichain: "omnichain"
1509
- };
1510
-
1511
- // src/shared/block-ref.ts
1512
- function isBefore(blockA, blockB) {
1513
- return blockA.number < blockB.number && blockA.timestamp < blockB.timestamp;
1514
- }
1515
- function isEqualTo(blockA, blockB) {
1516
- return blockA.number === blockB.number && blockA.timestamp === blockB.timestamp;
1517
- }
1518
- function isBeforeOrEqualTo(blockA, blockB) {
1519
- return isBefore(blockA, blockB) || isEqualTo(blockA, blockB);
1520
- }
1521
-
1522
- // src/ensindexer/indexing-status/helpers.ts
1523
- function getOmnichainIndexingStatus(chains) {
1524
- if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(chains)) {
1525
- return OmnichainIndexingStatusIds.Following;
1526
- }
1527
- if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(chains)) {
1528
- return OmnichainIndexingStatusIds.Backfill;
1529
- }
1530
- if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(chains)) {
1531
- return OmnichainIndexingStatusIds.Unstarted;
1532
- }
1533
- if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(chains)) {
1534
- return OmnichainIndexingStatusIds.Completed;
1535
- }
1536
- throw new Error(`Unable to determine omnichain indexing status for provided chains.`);
1537
- }
1538
- function getTimestampForLowestOmnichainStartBlock(chains) {
1539
- const earliestKnownBlockTimestamps = chains.map(
1540
- (chain) => chain.config.startBlock.timestamp
1541
- );
1542
- return Math.min(...earliestKnownBlockTimestamps);
1543
- }
1544
- function getTimestampForHighestOmnichainKnownBlock(chains) {
1545
- const latestKnownBlockTimestamps = [];
1546
- for (const chain of chains) {
1547
- switch (chain.chainStatus) {
1548
- case ChainIndexingStatusIds.Queued:
1549
- if (chain.config.configType === ChainIndexingConfigTypeIds.Definite && chain.config.endBlock) {
1550
- latestKnownBlockTimestamps.push(chain.config.endBlock.timestamp);
1551
- }
1552
- break;
1553
- case ChainIndexingStatusIds.Backfill:
1554
- latestKnownBlockTimestamps.push(chain.backfillEndBlock.timestamp);
1555
- break;
1556
- case ChainIndexingStatusIds.Completed:
1557
- latestKnownBlockTimestamps.push(chain.latestIndexedBlock.timestamp);
1558
- break;
1559
- case ChainIndexingStatusIds.Following:
1560
- latestKnownBlockTimestamps.push(chain.latestKnownBlock.timestamp);
1561
- break;
1562
- }
1563
- }
1564
- return Math.max(...latestKnownBlockTimestamps);
1565
- }
1566
- function getOmnichainIndexingCursor(chains) {
1567
- if (chains.length === 0) {
1568
- throw new Error(`Unable to determine omnichain indexing cursor when no chains were provided.`);
1569
- }
1570
- if (getOmnichainIndexingStatus(chains) === OmnichainIndexingStatusIds.Unstarted) {
1571
- const earliestStartBlockTimestamps = chains.map((chain) => chain.config.startBlock.timestamp);
1572
- return Math.min(...earliestStartBlockTimestamps) - 1;
1573
- }
1574
- const latestIndexedBlockTimestamps = chains.filter((chain) => chain.chainStatus !== ChainIndexingStatusIds.Queued).map((chain) => chain.latestIndexedBlock.timestamp);
1575
- if (latestIndexedBlockTimestamps.length < 1) {
1576
- throw new Error("latestIndexedBlockTimestamps array must include at least one element");
1577
- }
1578
- return Math.max(...latestIndexedBlockTimestamps);
1579
- }
1580
- function createIndexingConfig(startBlock, endBlock) {
1581
- if (endBlock) {
1582
- return {
1583
- configType: ChainIndexingConfigTypeIds.Definite,
1584
- startBlock,
1585
- endBlock
1586
- };
1587
- }
1588
- return {
1589
- configType: ChainIndexingConfigTypeIds.Indefinite,
1590
- startBlock
1591
- };
1592
- }
1593
- function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(chains) {
1594
- return chains.every((chain) => chain.chainStatus === ChainIndexingStatusIds.Queued);
1595
- }
1596
- function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(chains) {
1597
- const atLeastOneChainInTargetStatus = chains.some(
1598
- (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill
1599
- );
1600
- const otherChainsHaveValidStatuses = chains.every(
1601
- (chain) => chain.chainStatus === ChainIndexingStatusIds.Queued || chain.chainStatus === ChainIndexingStatusIds.Backfill || chain.chainStatus === ChainIndexingStatusIds.Completed
1602
- );
1603
- return atLeastOneChainInTargetStatus && otherChainsHaveValidStatuses;
1604
- }
1605
- function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(chains) {
1606
- const allChainsHaveValidStatuses = chains.every(
1607
- (chain) => chain.chainStatus === ChainIndexingStatusIds.Completed
1608
- );
1609
- return allChainsHaveValidStatuses;
1610
- }
1611
- function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(chains) {
1612
- const allChainsHaveValidStatuses = chains.some(
1613
- (chain) => chain.chainStatus === ChainIndexingStatusIds.Following
1614
- );
1615
- return allChainsHaveValidStatuses;
1616
- }
1617
- function sortChainStatusesByStartBlockAsc(chains) {
1618
- chains.sort(
1619
- ([, chainA], [, chainB]) => chainA.config.startBlock.timestamp - chainB.config.startBlock.timestamp
1620
- );
1621
- return chains;
1622
- }
1623
- function getLatestIndexedBlockRef(indexingStatus, chainId) {
1624
- const chainIndexingStatus = indexingStatus.omnichainSnapshot.chains.get(chainId);
1625
- if (chainIndexingStatus === void 0) {
1626
- return null;
1627
- }
1628
- if (chainIndexingStatus.chainStatus === ChainIndexingStatusIds.Queued) {
1629
- return null;
1630
- }
1631
- return chainIndexingStatus.latestIndexedBlock;
1632
- }
1633
-
1634
- // src/ensindexer/indexing-status/validations.ts
1635
- function invariant_chainSnapshotQueuedBlocks(ctx) {
1636
- const { config } = ctx.value;
1637
- if (config.configType === ChainIndexingConfigTypeIds.Indefinite) {
1638
- return;
1639
- }
1640
- if (config.endBlock && isBeforeOrEqualTo(config.startBlock, config.endBlock) === false) {
1641
- ctx.issues.push({
1642
- code: "custom",
1643
- input: ctx.value,
1644
- message: "`config.startBlock` must be before or same as `config.endBlock`."
1645
- });
1646
- }
1647
- }
1648
- function invariant_chainSnapshotBackfillBlocks(ctx) {
1649
- const { config, latestIndexedBlock, backfillEndBlock } = ctx.value;
1650
- if (isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {
1651
- ctx.issues.push({
1652
- code: "custom",
1653
- input: ctx.value,
1654
- message: "`config.startBlock` must be before or same as `latestIndexedBlock`."
1655
- });
1656
- }
1657
- if (isBeforeOrEqualTo(latestIndexedBlock, backfillEndBlock) === false) {
1658
- ctx.issues.push({
1659
- code: "custom",
1660
- input: ctx.value,
1661
- message: "`latestIndexedBlock` must be before or same as `backfillEndBlock`."
1662
- });
1663
- }
1664
- if (config.configType === ChainIndexingConfigTypeIds.Indefinite) {
1665
- return;
1666
- }
1667
- if (config.endBlock && isEqualTo(backfillEndBlock, config.endBlock) === false) {
1668
- ctx.issues.push({
1669
- code: "custom",
1670
- input: ctx.value,
1671
- message: "`backfillEndBlock` must be the same as `config.endBlock`."
1672
- });
1673
- }
1674
- }
1675
- function invariant_chainSnapshotCompletedBlocks(ctx) {
1676
- const { config, latestIndexedBlock } = ctx.value;
1677
- if (isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {
1678
- ctx.issues.push({
1679
- code: "custom",
1680
- input: ctx.value,
1681
- message: "`config.startBlock` must be before or same as `latestIndexedBlock`."
1682
- });
1683
- }
1684
- if (isBeforeOrEqualTo(latestIndexedBlock, config.endBlock) === false) {
1685
- ctx.issues.push({
1686
- code: "custom",
1687
- input: ctx.value,
1688
- message: "`latestIndexedBlock` must be before or same as `config.endBlock`."
1689
- });
1690
- }
1691
- }
1692
- function invariant_chainSnapshotFollowingBlocks(ctx) {
1693
- const { config, latestIndexedBlock, latestKnownBlock } = ctx.value;
1694
- if (isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {
1695
- ctx.issues.push({
1696
- code: "custom",
1697
- input: ctx.value,
1698
- message: "`config.startBlock` must be before or same as `latestIndexedBlock`."
1699
- });
1700
- }
1701
- if (isBeforeOrEqualTo(latestIndexedBlock, latestKnownBlock) === false) {
1702
- ctx.issues.push({
1703
- code: "custom",
1704
- input: ctx.value,
1705
- message: "`latestIndexedBlock` must be before or same as `latestKnownBlock`."
1706
- });
1707
- }
1708
- }
1709
- function invariant_omnichainSnapshotStatusIsConsistentWithChainSnapshot(ctx) {
1710
- const snapshot = ctx.value;
1711
- const chains = Array.from(snapshot.chains.values());
1712
- const expectedOmnichainStatus = getOmnichainIndexingStatus(chains);
1713
- const actualOmnichainStatus = snapshot.omnichainStatus;
1714
- if (expectedOmnichainStatus !== actualOmnichainStatus) {
1715
- ctx.issues.push({
1716
- code: "custom",
1717
- input: snapshot,
1718
- message: `'${actualOmnichainStatus}' is an invalid omnichainStatus. Expected '${expectedOmnichainStatus}' based on the statuses of individual chains.`
1719
- });
1720
- }
1721
- }
1722
- function invariant_omnichainIndexingCursorLowerThanEarliestStartBlockAcrossQueuedChains(ctx) {
1723
- const snapshot = ctx.value;
1724
- const queuedChains = Array.from(snapshot.chains.values()).filter(
1725
- (chain) => chain.chainStatus === ChainIndexingStatusIds.Queued
1726
- );
1727
- if (queuedChains.length === 0) {
1728
- return;
1729
- }
1730
- const queuedChainStartBlocks = queuedChains.map((chain) => chain.config.startBlock.timestamp);
1731
- const queuedChainEarliestStartBlock = Math.min(...queuedChainStartBlocks);
1732
- if (snapshot.omnichainIndexingCursor >= queuedChainEarliestStartBlock) {
1733
- ctx.issues.push({
1734
- code: "custom",
1735
- input: snapshot,
1736
- message: "`omnichainIndexingCursor` must be lower than the earliest start block across all queued chains."
1737
- });
1738
- }
1739
- }
1740
- function invariant_omnichainIndexingCursorLowerThanOrEqualToLatestBackfillEndBlockAcrossBackfillChains(ctx) {
1741
- const snapshot = ctx.value;
1742
- const backfillChains = Array.from(snapshot.chains.values()).filter(
1743
- (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill
1744
- );
1745
- if (backfillChains.length === 0) {
1746
- return;
1747
- }
1748
- const backfillEndBlocks = backfillChains.map((chain) => chain.backfillEndBlock.timestamp);
1749
- const highestBackfillEndBlock = Math.max(...backfillEndBlocks);
1750
- if (snapshot.omnichainIndexingCursor > highestBackfillEndBlock) {
1751
- ctx.issues.push({
1752
- code: "custom",
1753
- input: snapshot,
1754
- message: "`omnichainIndexingCursor` must be lower than or equal to the highest `backfillEndBlock` across all backfill chains."
1755
- });
1756
- }
1757
- }
1758
- function invariant_omnichainIndexingCursorIsEqualToHighestLatestIndexedBlockAcrossIndexedChain(ctx) {
1759
- const snapshot = ctx.value;
1760
- const indexedChains = Array.from(snapshot.chains.values()).filter(
1761
- (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill || chain.chainStatus === ChainIndexingStatusIds.Completed || chain.chainStatus === ChainIndexingStatusIds.Following
1762
- );
1763
- if (indexedChains.length === 0) {
1764
- return;
1765
- }
1766
- const indexedChainLatestIndexedBlocks = indexedChains.map(
1767
- (chain) => chain.latestIndexedBlock.timestamp
1768
- );
1769
- const indexedChainHighestLatestIndexedBlock = Math.max(...indexedChainLatestIndexedBlocks);
1770
- if (snapshot.omnichainIndexingCursor !== indexedChainHighestLatestIndexedBlock) {
1771
- ctx.issues.push({
1772
- code: "custom",
1773
- input: snapshot,
1774
- message: "`omnichainIndexingCursor` must be same as the highest `latestIndexedBlock` across all indexed chains."
1775
- });
1776
- }
1777
- }
1778
- function invariant_omnichainSnapshotUnstartedHasValidChains(ctx) {
1779
- const chains = ctx.value;
1780
- const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(
1781
- Array.from(chains.values())
1782
- );
1783
- if (hasValidChains === false) {
1784
- ctx.issues.push({
1785
- code: "custom",
1786
- input: chains,
1787
- message: `For omnichain status snapshot 'unstarted', all chains must have "queued" status.`
1788
- });
1789
- }
1790
- }
1791
- function invariant_omnichainStatusSnapshotBackfillHasValidChains(ctx) {
1792
- const chains = ctx.value;
1793
- const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(
1794
- Array.from(chains.values())
1795
- );
1796
- if (hasValidChains === false) {
1797
- ctx.issues.push({
1798
- code: "custom",
1799
- input: chains,
1800
- message: `For omnichain status snapshot 'backfill', at least one chain must be in "backfill" status and each chain has to have a status of either "queued", "backfill" or "completed".`
1801
- });
1802
- }
1803
- }
1804
- function invariant_omnichainStatusSnapshotCompletedHasValidChains(ctx) {
1805
- const chains = ctx.value;
1806
- const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(
1807
- Array.from(chains.values())
1808
- );
1809
- if (hasValidChains === false) {
1810
- ctx.issues.push({
1811
- code: "custom",
1812
- input: chains,
1813
- message: `For omnichain status snapshot 'completed', all chains must have "completed" status.`
1814
- });
1815
- }
1816
- }
1817
- function invariant_slowestChainEqualsToOmnichainSnapshotTime(ctx) {
1818
- const { slowestChainIndexingCursor, omnichainSnapshot } = ctx.value;
1819
- const { omnichainIndexingCursor } = omnichainSnapshot;
1820
- if (slowestChainIndexingCursor !== omnichainIndexingCursor) {
1821
- console.log("invariant_slowestChainEqualsToOmnichainSnapshotTime", {
1822
- slowestChainIndexingCursor,
1823
- omnichainIndexingCursor
1824
- });
1825
- ctx.issues.push({
1826
- code: "custom",
1827
- input: ctx.value,
1828
- message: `'slowestChainIndexingCursor' must be equal to 'omnichainSnapshot.omnichainIndexingCursor'`
1829
- });
1830
- }
1831
- }
1832
- function invariant_snapshotTimeIsTheHighestKnownBlockTimestamp(ctx) {
1833
- const { snapshotTime, omnichainSnapshot } = ctx.value;
1834
- const chains = Array.from(omnichainSnapshot.chains.values());
1835
- const startBlockTimestamps = chains.map((chain) => chain.config.startBlock.timestamp);
1836
- const endBlockTimestamps = chains.map((chain) => chain.config).filter((chainConfig) => chainConfig.configType === ChainIndexingConfigTypeIds.Definite).map((chainConfig) => chainConfig.endBlock.timestamp);
1837
- const backfillEndBlockTimestamps = chains.filter((chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill).map((chain) => chain.backfillEndBlock.timestamp);
1838
- const latestKnownBlockTimestamps = chains.filter((chain) => chain.chainStatus === ChainIndexingStatusIds.Following).map((chain) => chain.latestKnownBlock.timestamp);
1839
- const highestKnownBlockTimestamp = Math.max(
1840
- ...startBlockTimestamps,
1841
- ...endBlockTimestamps,
1842
- ...backfillEndBlockTimestamps,
1843
- ...latestKnownBlockTimestamps
1844
- );
1845
- if (snapshotTime < highestKnownBlockTimestamp) {
1846
- ctx.issues.push({
1847
- code: "custom",
1848
- input: ctx.value,
1849
- message: `'snapshotTime' (${snapshotTime}) must be greater than or equal to the "highest known block timestamp" (${highestKnownBlockTimestamp})`
1850
- });
1851
- }
1852
- }
1853
- function invariant_realtimeIndexingStatusProjectionProjectedAtIsAfterOrEqualToSnapshotTime(ctx) {
1854
- const projection = ctx.value;
1855
- const { snapshot, projectedAt } = projection;
1856
- if (snapshot.snapshotTime > projectedAt) {
1857
- ctx.issues.push({
1858
- code: "custom",
1859
- input: projection,
1860
- message: "`projectedAt` must be after or same as `snapshot.snapshotTime`."
1861
- });
1862
- }
1863
- }
1864
- function invariant_realtimeIndexingStatusProjectionWorstCaseDistanceIsCorrect(ctx) {
1865
- const projection = ctx.value;
1866
- const { projectedAt, snapshot, worstCaseDistance } = projection;
1867
- const { omnichainSnapshot } = snapshot;
1868
- const expectedWorstCaseDistance = projectedAt - omnichainSnapshot.omnichainIndexingCursor;
1869
- if (worstCaseDistance !== expectedWorstCaseDistance) {
1870
- ctx.issues.push({
1871
- code: "custom",
1872
- input: projection,
1873
- message: "`worstCaseDistance` must be the exact difference between `projectedAt` and `snapshot.omnichainIndexingCursor`."
1874
- });
1875
- }
1876
- }
1877
-
1878
- // src/ensindexer/indexing-status/zod-schemas.ts
1879
- var makeChainIndexingConfigSchema = (valueLabel = "Value") => import_v48.z.discriminatedUnion("configType", [
1880
- import_v48.z.strictObject({
1881
- configType: import_v48.z.literal(ChainIndexingConfigTypeIds.Indefinite),
1882
- startBlock: makeBlockRefSchema(valueLabel)
1883
- }),
1884
- import_v48.z.strictObject({
1885
- configType: import_v48.z.literal(ChainIndexingConfigTypeIds.Definite),
1886
- startBlock: makeBlockRefSchema(valueLabel),
1887
- endBlock: makeBlockRefSchema(valueLabel)
1888
- })
1889
- ]);
1890
- var makeChainIndexingStatusSnapshotQueuedSchema = (valueLabel = "Value") => import_v48.z.strictObject({
1891
- chainStatus: import_v48.z.literal(ChainIndexingStatusIds.Queued),
1892
- config: makeChainIndexingConfigSchema(valueLabel)
1893
- }).check(invariant_chainSnapshotQueuedBlocks);
1894
- var makeChainIndexingStatusSnapshotBackfillSchema = (valueLabel = "Value") => import_v48.z.strictObject({
1895
- chainStatus: import_v48.z.literal(ChainIndexingStatusIds.Backfill),
1896
- config: makeChainIndexingConfigSchema(valueLabel),
1897
- latestIndexedBlock: makeBlockRefSchema(valueLabel),
1898
- backfillEndBlock: makeBlockRefSchema(valueLabel)
1899
- }).check(invariant_chainSnapshotBackfillBlocks);
1900
- var makeChainIndexingStatusSnapshotCompletedSchema = (valueLabel = "Value") => import_v48.z.strictObject({
1901
- chainStatus: import_v48.z.literal(ChainIndexingStatusIds.Completed),
1902
- config: import_v48.z.strictObject({
1903
- configType: import_v48.z.literal(ChainIndexingConfigTypeIds.Definite),
1904
- startBlock: makeBlockRefSchema(valueLabel),
1905
- endBlock: makeBlockRefSchema(valueLabel)
1906
- }),
1907
- latestIndexedBlock: makeBlockRefSchema(valueLabel)
1908
- }).check(invariant_chainSnapshotCompletedBlocks);
1909
- var makeChainIndexingStatusSnapshotFollowingSchema = (valueLabel = "Value") => import_v48.z.strictObject({
1910
- chainStatus: import_v48.z.literal(ChainIndexingStatusIds.Following),
1911
- config: import_v48.z.strictObject({
1912
- configType: import_v48.z.literal(ChainIndexingConfigTypeIds.Indefinite),
1913
- startBlock: makeBlockRefSchema(valueLabel)
1914
- }),
1915
- latestIndexedBlock: makeBlockRefSchema(valueLabel),
1916
- latestKnownBlock: makeBlockRefSchema(valueLabel)
1917
- }).check(invariant_chainSnapshotFollowingBlocks);
1918
- var makeChainIndexingStatusSnapshotSchema = (valueLabel = "Value") => import_v48.z.discriminatedUnion("chainStatus", [
1919
- makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),
1920
- makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),
1921
- makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),
1922
- makeChainIndexingStatusSnapshotFollowingSchema(valueLabel)
1923
- ]);
1924
- var makeChainIndexingStatusesSchema = (valueLabel = "Value") => import_v48.z.record(makeChainIdStringSchema(), makeChainIndexingStatusSnapshotSchema(valueLabel), {
1925
- error: "Chains indexing statuses must be an object mapping valid chain IDs to their indexing status snapshots."
1926
- }).transform((serializedChainsIndexingStatus) => {
1927
- const chainsIndexingStatus = /* @__PURE__ */ new Map();
1928
- for (const [chainIdString, chainStatus] of Object.entries(serializedChainsIndexingStatus)) {
1929
- chainsIndexingStatus.set(deserializeChainId(chainIdString), chainStatus);
1930
- }
1931
- return chainsIndexingStatus;
1932
- });
1933
- var makeOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel) => import_v48.z.strictObject({
1934
- omnichainStatus: import_v48.z.literal(OmnichainIndexingStatusIds.Unstarted),
1935
- chains: makeChainIndexingStatusesSchema(valueLabel).check(invariant_omnichainSnapshotUnstartedHasValidChains).transform((chains) => chains),
1936
- omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel)
1937
- });
1938
- var makeOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel) => import_v48.z.strictObject({
1939
- omnichainStatus: import_v48.z.literal(OmnichainIndexingStatusIds.Backfill),
1940
- chains: makeChainIndexingStatusesSchema(valueLabel).check(invariant_omnichainStatusSnapshotBackfillHasValidChains).transform(
1941
- (chains) => chains
1942
- ),
1943
- omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel)
1944
- });
1945
- var makeOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel) => import_v48.z.strictObject({
1946
- omnichainStatus: import_v48.z.literal(OmnichainIndexingStatusIds.Completed),
1947
- chains: makeChainIndexingStatusesSchema(valueLabel).check(invariant_omnichainStatusSnapshotCompletedHasValidChains).transform((chains) => chains),
1948
- omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel)
1949
- });
1950
- var makeOmnichainIndexingStatusSnapshotFollowingSchema = (valueLabel) => import_v48.z.strictObject({
1951
- omnichainStatus: import_v48.z.literal(OmnichainIndexingStatusIds.Following),
1952
- chains: makeChainIndexingStatusesSchema(valueLabel),
1953
- omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel)
1954
- });
1955
- var makeOmnichainIndexingStatusSnapshotSchema = (valueLabel = "Omnichain Indexing Snapshot") => import_v48.z.discriminatedUnion("omnichainStatus", [
1956
- makeOmnichainIndexingStatusSnapshotUnstartedSchema(valueLabel),
1957
- makeOmnichainIndexingStatusSnapshotBackfillSchema(valueLabel),
1958
- makeOmnichainIndexingStatusSnapshotCompletedSchema(valueLabel),
1959
- makeOmnichainIndexingStatusSnapshotFollowingSchema(valueLabel)
1960
- ]).check(invariant_omnichainSnapshotStatusIsConsistentWithChainSnapshot).check(invariant_omnichainIndexingCursorLowerThanEarliestStartBlockAcrossQueuedChains).check(
1961
- invariant_omnichainIndexingCursorLowerThanOrEqualToLatestBackfillEndBlockAcrossBackfillChains
1962
- ).check(invariant_omnichainIndexingCursorIsEqualToHighestLatestIndexedBlockAcrossIndexedChain);
1963
- var makeCrossChainIndexingStatusSnapshotOmnichainSchema = (valueLabel = "Cross-chain Indexing Status Snapshot Omnichain") => import_v48.z.strictObject({
1964
- strategy: import_v48.z.literal(CrossChainIndexingStrategyIds.Omnichain),
1965
- slowestChainIndexingCursor: makeUnixTimestampSchema(valueLabel),
1966
- snapshotTime: makeUnixTimestampSchema(valueLabel),
1967
- omnichainSnapshot: makeOmnichainIndexingStatusSnapshotSchema(valueLabel)
1968
- }).check(invariant_slowestChainEqualsToOmnichainSnapshotTime).check(invariant_snapshotTimeIsTheHighestKnownBlockTimestamp);
1969
- var makeCrossChainIndexingStatusSnapshotSchema = (valueLabel = "Cross-chain Indexing Status Snapshot") => import_v48.z.discriminatedUnion("strategy", [
1970
- makeCrossChainIndexingStatusSnapshotOmnichainSchema(valueLabel)
1971
- ]);
1972
- var makeRealtimeIndexingStatusProjectionSchema = (valueLabel = "Realtime Indexing Status Projection") => import_v48.z.strictObject({
1973
- projectedAt: makeUnixTimestampSchema(valueLabel),
1974
- worstCaseDistance: makeDurationSchema(valueLabel),
1975
- snapshot: makeCrossChainIndexingStatusSnapshotSchema(valueLabel)
1976
- }).check(invariant_realtimeIndexingStatusProjectionProjectedAtIsAfterOrEqualToSnapshotTime).check(invariant_realtimeIndexingStatusProjectionWorstCaseDistanceIsCorrect);
1977
-
1978
- // src/ensindexer/indexing-status/deserialize.ts
1979
- function deserializeChainIndexingStatusSnapshot(maybeSnapshot, valueLabel) {
1980
- const schema = makeChainIndexingStatusSnapshotSchema(valueLabel);
1981
- const parsed = schema.safeParse(maybeSnapshot);
1982
- if (parsed.error) {
1983
- throw new Error(
1984
- `Cannot deserialize into ChainIndexingStatusSnapshot:
1985
- ${(0, import_v49.prettifyError)(parsed.error)}
1986
- `
1987
- );
1988
- }
1989
- return parsed.data;
1990
- }
1991
- function deserializeOmnichainIndexingStatusSnapshot(maybeSnapshot, valueLabel) {
1992
- const schema = makeOmnichainIndexingStatusSnapshotSchema(valueLabel);
1993
- const parsed = schema.safeParse(maybeSnapshot);
1994
- if (parsed.error) {
1995
- throw new Error(
1996
- `Cannot deserialize into OmnichainIndexingStatusSnapshot:
1997
- ${(0, import_v49.prettifyError)(parsed.error)}
1998
- `
1999
- );
2000
- }
2001
- return parsed.data;
1773
+ // src/shared/serialize.ts
1774
+ var import_caip2 = require("caip");
1775
+ function serializeChainId(chainId) {
1776
+ return chainId.toString();
2002
1777
  }
2003
- function deserializeCrossChainIndexingStatusSnapshot(maybeSnapshot, valueLabel) {
2004
- const schema = makeCrossChainIndexingStatusSnapshotSchema(valueLabel);
2005
- const parsed = schema.safeParse(maybeSnapshot);
2006
- if (parsed.error) {
2007
- throw new Error(
2008
- `Cannot deserialize into CrossChainIndexingStatusSnapshot:
2009
- ${(0, import_v49.prettifyError)(parsed.error)}
2010
- `
2011
- );
2012
- }
2013
- return parsed.data;
1778
+ function serializeDatetime(datetime) {
1779
+ return datetime.toISOString();
2014
1780
  }
2015
- function deserializeRealtimeIndexingStatusProjection(maybeProjection, valueLabel) {
2016
- const schema = makeRealtimeIndexingStatusProjectionSchema(valueLabel);
2017
- const parsed = schema.safeParse(maybeProjection);
2018
- if (parsed.error) {
2019
- throw new Error(
2020
- `Cannot deserialize into RealtimeIndexingStatusProjection:
2021
- ${(0, import_v49.prettifyError)(parsed.error)}
2022
- `
2023
- );
2024
- }
2025
- return parsed.data;
1781
+ function serializeUrl(url) {
1782
+ return url.toString();
2026
1783
  }
2027
-
2028
- // src/ensindexer/indexing-status/projection.ts
2029
- function createRealtimeIndexingStatusProjection(snapshot, now) {
2030
- const projectedAt = Math.max(now, snapshot.snapshotTime);
1784
+ function serializePrice(price) {
2031
1785
  return {
2032
- projectedAt,
2033
- worstCaseDistance: projectedAt - snapshot.slowestChainIndexingCursor,
2034
- snapshot
1786
+ currency: price.currency,
1787
+ amount: price.amount.toString()
2035
1788
  };
2036
1789
  }
1790
+ function serializePriceEth(price) {
1791
+ return serializePrice(price);
1792
+ }
1793
+ function serializePriceUsdc(price) {
1794
+ return serializePrice(price);
1795
+ }
1796
+ function serializePriceDai(price) {
1797
+ return serializePrice(price);
1798
+ }
1799
+ function formatAccountId(accountId) {
1800
+ return import_caip2.AccountId.format({
1801
+ chainId: { namespace: "eip155", reference: accountId.chainId.toString() },
1802
+ address: accountId.address
1803
+ }).toLowerCase();
1804
+ }
1805
+ function formatAssetId({
1806
+ assetNamespace,
1807
+ contract: { chainId, address },
1808
+ tokenId
1809
+ }) {
1810
+ return import_caip2.AssetId.format({
1811
+ chainId: { namespace: "eip155", reference: chainId.toString() },
1812
+ assetName: { namespace: assetNamespace, reference: address },
1813
+ tokenId: uint256ToHex32(tokenId)
1814
+ }).toLowerCase();
1815
+ }
2037
1816
 
2038
1817
  // src/ensindexer/indexing-status/serialize.ts
2039
1818
  function serializeCrossChainIndexingStatusSnapshotOmnichain({
@@ -2172,21 +1951,61 @@ function serializeIndexingStatusResponse(response) {
2172
1951
  var import_v416 = require("zod/v4");
2173
1952
 
2174
1953
  // src/api/name-tokens/zod-schemas.ts
2175
- var import_viem17 = require("viem");
1954
+ var import_viem14 = require("viem");
2176
1955
  var import_v415 = require("zod/v4");
2177
1956
 
2178
1957
  // src/tokenscope/assets.ts
2179
- var import_viem16 = require("viem");
1958
+ var import_viem13 = require("viem");
2180
1959
  var import_v413 = require("zod/v4");
2181
1960
 
2182
1961
  // src/tokenscope/zod-schemas.ts
2183
1962
  var import_caip3 = require("caip");
2184
- var import_viem15 = require("viem");
1963
+ var import_viem12 = require("viem");
2185
1964
  var import_v412 = require("zod/v4");
2186
1965
 
1966
+ // src/shared/types.ts
1967
+ var AssetNamespaces = {
1968
+ ERC721: "erc721",
1969
+ ERC1155: "erc1155"
1970
+ };
1971
+
1972
+ // src/tokenscope/name-token.ts
1973
+ var import_viem11 = require("viem");
1974
+ var import_datasources5 = require("@ensnode/datasources");
1975
+
1976
+ // src/shared/account-id.ts
1977
+ var import_viem10 = require("viem");
1978
+ var accountIdEqual = (a, b) => {
1979
+ return a.chainId === b.chainId && (0, import_viem10.isAddressEqual)(a.address, b.address);
1980
+ };
1981
+
1982
+ // src/shared/datasource-contract.ts
1983
+ var import_datasources4 = require("@ensnode/datasources");
1984
+ var maybeGetDatasourceContract = (namespaceId, datasourceName, contractName) => {
1985
+ const datasource = (0, import_datasources4.maybeGetDatasource)(namespaceId, datasourceName);
1986
+ if (!datasource) return void 0;
1987
+ const address = datasource.contracts[contractName]?.address;
1988
+ if (address === void 0 || Array.isArray(address)) return void 0;
1989
+ return {
1990
+ chainId: datasource.chain.id,
1991
+ address
1992
+ };
1993
+ };
1994
+ var getDatasourceContract = (namespaceId, datasourceName, contractName) => {
1995
+ const contract = maybeGetDatasourceContract(namespaceId, datasourceName, contractName);
1996
+ if (!contract) {
1997
+ throw new Error(
1998
+ `Expected contract not found for ${namespaceId} ${datasourceName} ${contractName}`
1999
+ );
2000
+ }
2001
+ return contract;
2002
+ };
2003
+ var makeContractMatcher = (namespace, b) => (datasourceName, contractName) => {
2004
+ const a = maybeGetDatasourceContract(namespace, datasourceName, contractName);
2005
+ return a && accountIdEqual(a, b);
2006
+ };
2007
+
2187
2008
  // src/tokenscope/name-token.ts
2188
- var import_viem14 = require("viem");
2189
- var import_datasources6 = require("@ensnode/datasources");
2190
2009
  var NameTokenOwnershipTypes = {
2191
2010
  /**
2192
2011
  * Name Token is owned by NameWrapper account.
@@ -2217,12 +2036,12 @@ function serializeNameToken(nameToken) {
2217
2036
  function getNameWrapperAccounts(namespaceId) {
2218
2037
  const ethnamesNameWrapperAccount = getDatasourceContract(
2219
2038
  namespaceId,
2220
- import_datasources6.DatasourceNames.ENSRoot,
2039
+ import_datasources5.DatasourceNames.ENSRoot,
2221
2040
  "NameWrapper"
2222
2041
  );
2223
2042
  const lineanamesNameWrapperAccount = maybeGetDatasourceContract(
2224
2043
  namespaceId,
2225
- import_datasources6.DatasourceNames.Lineanames,
2044
+ import_datasources5.DatasourceNames.Lineanames,
2226
2045
  "NameWrapper"
2227
2046
  );
2228
2047
  const nameWrapperAccounts = [
@@ -2245,7 +2064,7 @@ function getNameTokenOwnership(namespaceId, name, owner) {
2245
2064
  owner
2246
2065
  };
2247
2066
  }
2248
- if ((0, import_viem14.isAddressEqual)(owner.address, import_viem14.zeroAddress)) {
2067
+ if ((0, import_viem11.isAddressEqual)(owner.address, import_viem11.zeroAddress)) {
2249
2068
  return {
2250
2069
  ownershipType: NameTokenOwnershipTypes.Burned,
2251
2070
  owner
@@ -2300,7 +2119,7 @@ var makeAssetIdStringSchema = (valueLabel = "Asset ID String Schema") => import_
2300
2119
  }, makeAssetIdSchema(valueLabel));
2301
2120
  function invariant_nameTokenOwnershipHasNonZeroAddressOwner(ctx) {
2302
2121
  const ownership = ctx.value;
2303
- if (ctx.value.owner.address === import_viem15.zeroAddress) {
2122
+ if (ctx.value.owner.address === import_viem12.zeroAddress) {
2304
2123
  ctx.issues.push({
2305
2124
  code: "custom",
2306
2125
  input: ctx.value,
@@ -2326,7 +2145,7 @@ var makeNameTokenOwnershipUnknownSchema = (valueLabel = "Name Token Ownership Un
2326
2145
  }).check(invariant_nameTokenOwnershipHasNonZeroAddressOwner);
2327
2146
  function invariant_nameTokenOwnershipHasZeroAddressOwner(ctx) {
2328
2147
  const ownership = ctx.value;
2329
- if (ctx.value.owner.address !== import_viem15.zeroAddress) {
2148
+ if (ctx.value.owner.address !== import_viem12.zeroAddress) {
2330
2149
  ctx.issues.push({
2331
2150
  code: "custom",
2332
2151
  input: ctx.value,
@@ -2504,11 +2323,11 @@ var NFTTransferTypes = {
2504
2323
  };
2505
2324
  var getNFTTransferType = (from, to, allowMintedRemint, metadata, currentlyIndexedOwner) => {
2506
2325
  const isIndexed = currentlyIndexedOwner !== void 0;
2507
- const isIndexedAsMinted = isIndexed && !(0, import_viem16.isAddressEqual)(currentlyIndexedOwner, import_viem16.zeroAddress);
2508
- const isMint = (0, import_viem16.isAddressEqual)(from, import_viem16.zeroAddress);
2509
- const isBurn = (0, import_viem16.isAddressEqual)(to, import_viem16.zeroAddress);
2510
- const isSelfTransfer = (0, import_viem16.isAddressEqual)(from, to);
2511
- if (isIndexed && !(0, import_viem16.isAddressEqual)(currentlyIndexedOwner, from)) {
2326
+ const isIndexedAsMinted = isIndexed && !(0, import_viem13.isAddressEqual)(currentlyIndexedOwner, import_viem13.zeroAddress);
2327
+ const isMint = (0, import_viem13.isAddressEqual)(from, import_viem13.zeroAddress);
2328
+ const isBurn = (0, import_viem13.isAddressEqual)(to, import_viem13.zeroAddress);
2329
+ const isSelfTransfer = (0, import_viem13.isAddressEqual)(from, to);
2330
+ if (isIndexed && !(0, import_viem13.isAddressEqual)(currentlyIndexedOwner, from)) {
2512
2331
  if (isMint && allowMintedRemint) {
2513
2332
  } else {
2514
2333
  throw new Error(
@@ -2641,7 +2460,7 @@ var makeRegisteredNameTokenSchema = (valueLabel = "Registered Name Token", seria
2641
2460
  accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
2642
2461
  }).check(function invariant_nameIsAssociatedWithDomainId(ctx) {
2643
2462
  const { name, domainId } = ctx.value;
2644
- if ((0, import_viem17.namehash)(name) !== domainId) {
2463
+ if ((0, import_viem14.namehash)(name) !== domainId) {
2645
2464
  ctx.issues.push({
2646
2465
  code: "custom",
2647
2466
  input: ctx.value,
@@ -2793,41 +2612,41 @@ function serializeNameTokensResponse(response) {
2793
2612
  var import_v420 = require("zod/v4");
2794
2613
 
2795
2614
  // src/api/registrar-actions/zod-schemas.ts
2796
- var import_ens10 = require("viem/ens");
2615
+ var import_ens7 = require("viem/ens");
2797
2616
  var import_v419 = require("zod/v4");
2798
2617
 
2799
2618
  // src/registrars/zod-schemas.ts
2800
2619
  var import_v417 = require("zod/v4");
2801
2620
 
2802
2621
  // src/registrars/encoded-referrer.ts
2803
- var import_viem18 = require("viem");
2622
+ var import_viem15 = require("viem");
2804
2623
  var ENCODED_REFERRER_BYTE_OFFSET = 12;
2805
2624
  var ENCODED_REFERRER_BYTE_LENGTH = 32;
2806
- var EXPECTED_ENCODED_REFERRER_PADDING = (0, import_viem18.pad)("0x", {
2625
+ var EXPECTED_ENCODED_REFERRER_PADDING = (0, import_viem15.pad)("0x", {
2807
2626
  size: ENCODED_REFERRER_BYTE_OFFSET,
2808
2627
  dir: "left"
2809
2628
  });
2810
- var ZERO_ENCODED_REFERRER = (0, import_viem18.pad)("0x", {
2629
+ var ZERO_ENCODED_REFERRER = (0, import_viem15.pad)("0x", {
2811
2630
  size: ENCODED_REFERRER_BYTE_LENGTH,
2812
2631
  dir: "left"
2813
2632
  });
2814
2633
  function buildEncodedReferrer(address) {
2815
2634
  const lowercaseAddress = address.toLowerCase();
2816
- return (0, import_viem18.pad)(lowercaseAddress, { size: ENCODED_REFERRER_BYTE_LENGTH, dir: "left" });
2635
+ return (0, import_viem15.pad)(lowercaseAddress, { size: ENCODED_REFERRER_BYTE_LENGTH, dir: "left" });
2817
2636
  }
2818
2637
  function decodeEncodedReferrer(encodedReferrer) {
2819
- if ((0, import_viem18.size)(encodedReferrer) !== ENCODED_REFERRER_BYTE_LENGTH) {
2638
+ if ((0, import_viem15.size)(encodedReferrer) !== ENCODED_REFERRER_BYTE_LENGTH) {
2820
2639
  throw new Error(
2821
2640
  `Encoded referrer value must be represented by ${ENCODED_REFERRER_BYTE_LENGTH} bytes.`
2822
2641
  );
2823
2642
  }
2824
- const padding = (0, import_viem18.slice)(encodedReferrer, 0, ENCODED_REFERRER_BYTE_OFFSET);
2643
+ const padding = (0, import_viem15.slice)(encodedReferrer, 0, ENCODED_REFERRER_BYTE_OFFSET);
2825
2644
  if (padding !== EXPECTED_ENCODED_REFERRER_PADDING) {
2826
- return import_viem18.zeroAddress;
2645
+ return import_viem15.zeroAddress;
2827
2646
  }
2828
- const decodedReferrer = (0, import_viem18.slice)(encodedReferrer, ENCODED_REFERRER_BYTE_OFFSET);
2647
+ const decodedReferrer = (0, import_viem15.slice)(encodedReferrer, ENCODED_REFERRER_BYTE_OFFSET);
2829
2648
  try {
2830
- return (0, import_viem18.getAddress)(decodedReferrer);
2649
+ return (0, import_viem15.getAddress)(decodedReferrer);
2831
2650
  } catch {
2832
2651
  throw new Error(`Decoded referrer value must be a valid EVM address.`);
2833
2652
  }
@@ -3062,7 +2881,7 @@ var RegistrarActionsResponseCodes = {
3062
2881
  function invariant_registrationLifecycleNodeMatchesName(ctx) {
3063
2882
  const { name, action } = ctx.value;
3064
2883
  const expectedNode = action.registrationLifecycle.node;
3065
- const actualNode = (0, import_ens10.namehash)(name);
2884
+ const actualNode = (0, import_ens7.namehash)(name);
3066
2885
  if (actualNode !== expectedNode) {
3067
2886
  ctx.issues.push({
3068
2887
  code: "custom",
@@ -3219,11 +3038,11 @@ var registrarActionsPrerequisites = Object.freeze({
3219
3038
  });
3220
3039
 
3221
3040
  // src/registrars/basenames-subregistry.ts
3222
- var import_datasources7 = require("@ensnode/datasources");
3041
+ var import_datasources6 = require("@ensnode/datasources");
3223
3042
  function getBasenamesSubregistryId(namespace) {
3224
- const datasource = (0, import_datasources7.maybeGetDatasource)(namespace, import_datasources7.DatasourceNames.Basenames);
3043
+ const datasource = (0, import_datasources6.maybeGetDatasource)(namespace, import_datasources6.DatasourceNames.Basenames);
3225
3044
  if (!datasource) {
3226
- throw new Error(`Datasource not found for ${namespace} ${import_datasources7.DatasourceNames.Basenames}`);
3045
+ throw new Error(`Datasource not found for ${namespace} ${import_datasources6.DatasourceNames.Basenames}`);
3227
3046
  }
3228
3047
  const address = datasource.contracts.BaseRegistrar?.address;
3229
3048
  if (address === void 0 || Array.isArray(address)) {
@@ -3236,12 +3055,12 @@ function getBasenamesSubregistryId(namespace) {
3236
3055
  }
3237
3056
  function getBasenamesSubregistryManagedName(namespaceId) {
3238
3057
  switch (namespaceId) {
3239
- case import_datasources7.ENSNamespaceIds.Mainnet:
3058
+ case import_datasources6.ENSNamespaceIds.Mainnet:
3240
3059
  return "base.eth";
3241
- case import_datasources7.ENSNamespaceIds.Sepolia:
3242
- case import_datasources7.ENSNamespaceIds.SepoliaV2:
3060
+ case import_datasources6.ENSNamespaceIds.Sepolia:
3061
+ case import_datasources6.ENSNamespaceIds.SepoliaV2:
3243
3062
  return "basetest.eth";
3244
- case import_datasources7.ENSNamespaceIds.EnsTestEnv:
3063
+ case import_datasources6.ENSNamespaceIds.EnsTestEnv:
3245
3064
  throw new Error(
3246
3065
  `No registrar managed name is known for the 'basenames' subregistry within the "${namespaceId}" namespace.`
3247
3066
  );
@@ -3249,11 +3068,11 @@ function getBasenamesSubregistryManagedName(namespaceId) {
3249
3068
  }
3250
3069
 
3251
3070
  // src/registrars/ethnames-subregistry.ts
3252
- var import_datasources8 = require("@ensnode/datasources");
3071
+ var import_datasources7 = require("@ensnode/datasources");
3253
3072
  function getEthnamesSubregistryId(namespace) {
3254
- const datasource = (0, import_datasources8.maybeGetDatasource)(namespace, import_datasources8.DatasourceNames.ENSRoot);
3073
+ const datasource = (0, import_datasources7.maybeGetDatasource)(namespace, import_datasources7.DatasourceNames.ENSRoot);
3255
3074
  if (!datasource) {
3256
- throw new Error(`Datasource not found for ${namespace} ${import_datasources8.DatasourceNames.ENSRoot}`);
3075
+ throw new Error(`Datasource not found for ${namespace} ${import_datasources7.DatasourceNames.ENSRoot}`);
3257
3076
  }
3258
3077
  const address = datasource.contracts.BaseRegistrar?.address;
3259
3078
  if (address === void 0 || Array.isArray(address)) {
@@ -3266,20 +3085,20 @@ function getEthnamesSubregistryId(namespace) {
3266
3085
  }
3267
3086
  function getEthnamesSubregistryManagedName(namespaceId) {
3268
3087
  switch (namespaceId) {
3269
- case import_datasources8.ENSNamespaceIds.Mainnet:
3270
- case import_datasources8.ENSNamespaceIds.Sepolia:
3271
- case import_datasources8.ENSNamespaceIds.SepoliaV2:
3272
- case import_datasources8.ENSNamespaceIds.EnsTestEnv:
3088
+ case import_datasources7.ENSNamespaceIds.Mainnet:
3089
+ case import_datasources7.ENSNamespaceIds.Sepolia:
3090
+ case import_datasources7.ENSNamespaceIds.SepoliaV2:
3091
+ case import_datasources7.ENSNamespaceIds.EnsTestEnv:
3273
3092
  return "eth";
3274
3093
  }
3275
3094
  }
3276
3095
 
3277
3096
  // src/registrars/lineanames-subregistry.ts
3278
- var import_datasources9 = require("@ensnode/datasources");
3097
+ var import_datasources8 = require("@ensnode/datasources");
3279
3098
  function getLineanamesSubregistryId(namespace) {
3280
- const datasource = (0, import_datasources9.maybeGetDatasource)(namespace, import_datasources9.DatasourceNames.Lineanames);
3099
+ const datasource = (0, import_datasources8.maybeGetDatasource)(namespace, import_datasources8.DatasourceNames.Lineanames);
3281
3100
  if (!datasource) {
3282
- throw new Error(`Datasource not found for ${namespace} ${import_datasources9.DatasourceNames.Lineanames}`);
3101
+ throw new Error(`Datasource not found for ${namespace} ${import_datasources8.DatasourceNames.Lineanames}`);
3283
3102
  }
3284
3103
  const address = datasource.contracts.BaseRegistrar?.address;
3285
3104
  if (address === void 0 || Array.isArray(address)) {
@@ -3292,12 +3111,12 @@ function getLineanamesSubregistryId(namespace) {
3292
3111
  }
3293
3112
  function getLineanamesSubregistryManagedName(namespaceId) {
3294
3113
  switch (namespaceId) {
3295
- case import_datasources9.ENSNamespaceIds.Mainnet:
3114
+ case import_datasources8.ENSNamespaceIds.Mainnet:
3296
3115
  return "linea.eth";
3297
- case import_datasources9.ENSNamespaceIds.Sepolia:
3298
- case import_datasources9.ENSNamespaceIds.SepoliaV2:
3116
+ case import_datasources8.ENSNamespaceIds.Sepolia:
3117
+ case import_datasources8.ENSNamespaceIds.SepoliaV2:
3299
3118
  return "linea-sepolia.eth";
3300
- case import_datasources9.ENSNamespaceIds.EnsTestEnv:
3119
+ case import_datasources8.ENSNamespaceIds.EnsTestEnv:
3301
3120
  throw new Error(
3302
3121
  `No registrar managed name is known for the 'Lineanames' subregistry within the "${namespaceId}" namespace.`
3303
3122
  );
@@ -3404,15 +3223,15 @@ var ClientError = class _ClientError extends Error {
3404
3223
  };
3405
3224
 
3406
3225
  // src/deployments.ts
3407
- var import_datasources10 = require("@ensnode/datasources");
3226
+ var import_datasources9 = require("@ensnode/datasources");
3408
3227
  var DEFAULT_ENSNODE_API_URL_MAINNET = "https://api.alpha.ensnode.io";
3409
3228
  var DEFAULT_ENSNODE_API_URL_SEPOLIA = "https://api.alpha-sepolia.ensnode.io";
3410
3229
  var getDefaultEnsNodeUrl = (namespace) => {
3411
- const effectiveNamespace = namespace ?? import_datasources10.ENSNamespaceIds.Mainnet;
3230
+ const effectiveNamespace = namespace ?? import_datasources9.ENSNamespaceIds.Mainnet;
3412
3231
  switch (effectiveNamespace) {
3413
- case import_datasources10.ENSNamespaceIds.Mainnet:
3232
+ case import_datasources9.ENSNamespaceIds.Mainnet:
3414
3233
  return new URL(DEFAULT_ENSNODE_API_URL_MAINNET);
3415
- case import_datasources10.ENSNamespaceIds.Sepolia:
3234
+ case import_datasources9.ENSNamespaceIds.Sepolia:
3416
3235
  return new URL(DEFAULT_ENSNODE_API_URL_SEPOLIA);
3417
3236
  default:
3418
3237
  throw new Error(
@@ -3831,136 +3650,435 @@ var ENSNodeClient = class _ENSNodeClient {
3831
3650
  return deserializeRegistrarActionsResponse(responseData);
3832
3651
  }
3833
3652
  /**
3834
- * Fetch Name Tokens for requested name.
3835
- *
3836
- * @param request.name - Name for which Name Tokens will be fetched.
3837
- * @returns {NameTokensResponse}
3838
- *
3839
- * @throws if the ENSNode request fails
3840
- * @throws if the ENSNode API returns an error response
3841
- * @throws if the ENSNode response breaks required invariants
3842
- *
3843
- * @example
3844
- * ```ts
3845
- * import {
3846
- * ENSNodeClient,
3847
- * } from "@ensnode/ensnode-sdk";
3848
- * import { namehash } from "viem/ens";
3849
- *
3850
- * const client: ENSNodeClient;
3851
- *
3852
- * // get latest name token records from the indexed subregistry based on the requested name
3853
- * const response = await client.nameTokens({
3854
- * name: "vitalik.eth"
3855
- * });
3653
+ * Fetch Name Tokens for requested name.
3654
+ *
3655
+ * @param request.name - Name for which Name Tokens will be fetched.
3656
+ * @returns {NameTokensResponse}
3657
+ *
3658
+ * @throws if the ENSNode request fails
3659
+ * @throws if the ENSNode API returns an error response
3660
+ * @throws if the ENSNode response breaks required invariants
3661
+ *
3662
+ * @example
3663
+ * ```ts
3664
+ * import {
3665
+ * ENSNodeClient,
3666
+ * } from "@ensnode/ensnode-sdk";
3667
+ * import { namehash } from "viem/ens";
3668
+ *
3669
+ * const client: ENSNodeClient;
3670
+ *
3671
+ * // get latest name token records from the indexed subregistry based on the requested name
3672
+ * const response = await client.nameTokens({
3673
+ * name: "vitalik.eth"
3674
+ * });
3675
+ *
3676
+ * const response = await client.nameTokens({
3677
+ * domainId: "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835" // namehash('vitalik.eth')
3678
+ * })
3679
+ * ```
3680
+ */
3681
+ async nameTokens(request) {
3682
+ const url = new URL(`/api/name-tokens`, this.options.url);
3683
+ if (request.name !== void 0) {
3684
+ url.searchParams.set("name", request.name);
3685
+ } else if (request.domainId !== void 0) {
3686
+ url.searchParams.set("domainId", request.domainId);
3687
+ }
3688
+ const response = await fetch(url);
3689
+ let responseData;
3690
+ try {
3691
+ responseData = await response.json();
3692
+ } catch {
3693
+ throw new Error("Malformed response data: invalid JSON");
3694
+ }
3695
+ if (!response.ok) {
3696
+ let errorResponse;
3697
+ try {
3698
+ errorResponse = deserializeErrorResponse(responseData);
3699
+ } catch {
3700
+ console.log("Name Tokens API: handling a known server error.");
3701
+ }
3702
+ if (typeof errorResponse !== "undefined") {
3703
+ throw new Error(`Fetching ENSNode Name Tokens Failed: ${errorResponse.message}`);
3704
+ }
3705
+ }
3706
+ return deserializedNameTokensResponse(responseData);
3707
+ }
3708
+ };
3709
+
3710
+ // src/ensv2/ids-lib.ts
3711
+ var import_viem16 = require("viem");
3712
+ var makeRegistryId = (accountId) => formatAccountId(accountId);
3713
+ var makeENSv1DomainId = (node) => node;
3714
+ var makeENSv2DomainId = (registry, canonicalId) => formatAssetId({
3715
+ assetNamespace: AssetNamespaces.ERC1155,
3716
+ contract: registry,
3717
+ tokenId: canonicalId
3718
+ });
3719
+ var maskLower32Bits = (num) => num ^ num & 0xffffffffn;
3720
+ var getCanonicalId = (input) => {
3721
+ if (typeof input === "bigint") return maskLower32Bits(input);
3722
+ return getCanonicalId((0, import_viem16.hexToBigInt)(input));
3723
+ };
3724
+ var makePermissionsId = (contract) => formatAccountId(contract);
3725
+ var makePermissionsResourceId = (contract, resource) => `${makePermissionsId(contract)}/${resource}`;
3726
+ var makePermissionsUserId = (contract, resource, user) => `${makePermissionsId(contract)}/${resource}/${user}`;
3727
+ var makeResolverId = (contract) => formatAccountId(contract);
3728
+ var makeResolverRecordsId = (resolver, node) => `${makeResolverId(resolver)}/${node}`;
3729
+ var makeLatestRegistrationId = (domainId) => `${domainId}/latest`;
3730
+ var makeRegistrationId = (domainId, index = 0) => `${domainId}/${index}`;
3731
+ var makeLatestRenewalId = (domainId, registrationIndex) => `${makeRegistrationId(domainId, registrationIndex)}/latest`;
3732
+ var makeRenewalId = (domainId, registrationIndex, index = 0) => `${makeRegistrationId(domainId, registrationIndex)}/${index}`;
3733
+
3734
+ // src/identity/identity.ts
3735
+ var import_datasources10 = require("@ensnode/datasources");
3736
+
3737
+ // src/identity/types.ts
3738
+ var ResolutionStatusIds = {
3739
+ /**
3740
+ * Represents that the `Identity` is not resolved yet.
3741
+ */
3742
+ Unresolved: "unresolved",
3743
+ /**
3744
+ * Represents that resolution of the `Identity` resulted in a named identity.
3745
+ */
3746
+ Named: "named",
3747
+ /**
3748
+ * Represents that resolution of the `Identity` resulted in an unnamed identity.
3749
+ */
3750
+ Unnamed: "unnamed",
3751
+ /**
3752
+ * Represents that attempted resolution of the `Identity` resulted in an error
3753
+ * and therefore it is unknown if the `Identity` resolves to a named or unnamed identity.
3754
+ */
3755
+ Unknown: "unknown"
3756
+ };
3757
+
3758
+ // src/identity/identity.ts
3759
+ function buildUnresolvedIdentity(address, namespaceId, chainId) {
3760
+ return {
3761
+ resolutionStatus: ResolutionStatusIds.Unresolved,
3762
+ chainId: chainId ?? (0, import_datasources10.getENSRootChainId)(namespaceId),
3763
+ address
3764
+ };
3765
+ }
3766
+ function isResolvedIdentity(identity) {
3767
+ return identity.resolutionStatus !== ResolutionStatusIds.Unresolved;
3768
+ }
3769
+
3770
+ // src/resolution/ensip19-chainid.ts
3771
+ var import_chains = require("viem/chains");
3772
+ var import_datasources11 = require("@ensnode/datasources");
3773
+ var getResolvePrimaryNameChainIdParam = (chainId, namespaceId) => {
3774
+ const ensRootChainId = (0, import_datasources11.getENSRootChainId)(namespaceId);
3775
+ return chainId === ensRootChainId ? import_chains.mainnet.id : chainId;
3776
+ };
3777
+ var translateDefaultableChainIdToChainId = (chainId, namespaceId) => {
3778
+ return chainId === DEFAULT_EVM_CHAIN_ID ? (0, import_datasources11.getENSRootChainId)(namespaceId) : chainId;
3779
+ };
3780
+
3781
+ // src/resolution/resolver-records-selection.ts
3782
+ var isSelectionEmpty = (selection) => !selection.name && !selection.addresses?.length && !selection.texts?.length;
3783
+
3784
+ // src/shared/cache/lru-cache.ts
3785
+ var LruCache = class {
3786
+ _cache = /* @__PURE__ */ new Map();
3787
+ _capacity;
3788
+ /**
3789
+ * Create a new LRU cache with the given capacity.
3790
+ *
3791
+ * @param capacity The maximum number of items in the cache. If set to 0, the cache is effectively disabled.
3792
+ * @throws Error if capacity is not a non-negative integer.
3793
+ */
3794
+ constructor(capacity) {
3795
+ if (!Number.isInteger(capacity)) {
3796
+ throw new Error(
3797
+ `LruCache requires capacity to be an integer but a capacity of ${capacity} was requested.`
3798
+ );
3799
+ }
3800
+ if (capacity < 0) {
3801
+ throw new Error(
3802
+ `LruCache requires a non-negative capacity but a capacity of ${capacity} was requested.`
3803
+ );
3804
+ }
3805
+ this._capacity = capacity;
3806
+ }
3807
+ set(key, value) {
3808
+ this._cache.set(key, value);
3809
+ if (this._cache.size > this._capacity) {
3810
+ const oldestKey = this._cache.keys().next().value;
3811
+ this._cache.delete(oldestKey);
3812
+ }
3813
+ }
3814
+ get(key) {
3815
+ const value = this._cache.get(key);
3816
+ if (value) {
3817
+ this._cache.delete(key);
3818
+ this._cache.set(key, value);
3819
+ }
3820
+ return value;
3821
+ }
3822
+ clear() {
3823
+ this._cache.clear();
3824
+ }
3825
+ get size() {
3826
+ return this._cache.size;
3827
+ }
3828
+ get capacity() {
3829
+ return this._capacity;
3830
+ }
3831
+ };
3832
+
3833
+ // src/shared/cache/swr-cache.ts
3834
+ var import_date_fns = require("date-fns");
3835
+ var import_getUnixTime = require("date-fns/getUnixTime");
3836
+
3837
+ // src/shared/datetime.ts
3838
+ function durationBetween(start, end) {
3839
+ return deserializeDuration(end - start, "Duration");
3840
+ }
3841
+ function addDuration(timestamp, duration) {
3842
+ return deserializeUnixTimestamp(timestamp + duration, "UnixTimestamp");
3843
+ }
3844
+
3845
+ // src/shared/cache/swr-cache.ts
3846
+ var SWRCache = class {
3847
+ constructor(options) {
3848
+ this.options = options;
3849
+ if (options.proactiveRevalidationInterval) {
3850
+ this.backgroundInterval = setInterval(
3851
+ () => this.revalidate(),
3852
+ (0, import_date_fns.secondsToMilliseconds)(options.proactiveRevalidationInterval)
3853
+ );
3854
+ }
3855
+ if (options.proactivelyInitialize) this.revalidate();
3856
+ }
3857
+ cache = null;
3858
+ inProgressRevalidate = null;
3859
+ backgroundInterval = null;
3860
+ async revalidate() {
3861
+ if (!this.inProgressRevalidate) {
3862
+ this.inProgressRevalidate = this.options.fn().then((result) => {
3863
+ this.cache = {
3864
+ result,
3865
+ updatedAt: (0, import_getUnixTime.getUnixTime)(/* @__PURE__ */ new Date())
3866
+ };
3867
+ }).catch((error) => {
3868
+ if (!this.cache) {
3869
+ this.cache = {
3870
+ // ensure thrown value is always an Error instance
3871
+ result: error instanceof Error ? error : new Error(String(error)),
3872
+ updatedAt: (0, import_getUnixTime.getUnixTime)(/* @__PURE__ */ new Date())
3873
+ };
3874
+ }
3875
+ }).finally(() => {
3876
+ this.inProgressRevalidate = null;
3877
+ });
3878
+ }
3879
+ return this.inProgressRevalidate;
3880
+ }
3881
+ /**
3882
+ * Read the most recently cached result from the `SWRCache`.
3883
+ *
3884
+ * @returns a `ValueType` that was most recently successfully returned by `fn` or `Error` if `fn`
3885
+ * has never successfully returned.
3886
+ */
3887
+ async read() {
3888
+ if (!this.cache) await this.revalidate();
3889
+ if (!this.cache) throw new Error("never");
3890
+ if (durationBetween(this.cache.updatedAt, (0, import_getUnixTime.getUnixTime)(/* @__PURE__ */ new Date())) > this.options.ttl) {
3891
+ this.revalidate();
3892
+ }
3893
+ return this.cache.result;
3894
+ }
3895
+ /**
3896
+ * Destroys the background revalidation interval, if exists.
3897
+ */
3898
+ destroy() {
3899
+ if (this.backgroundInterval) {
3900
+ clearInterval(this.backgroundInterval);
3901
+ this.backgroundInterval = null;
3902
+ }
3903
+ }
3904
+ };
3905
+
3906
+ // src/shared/cache/ttl-cache.ts
3907
+ var import_getUnixTime2 = require("date-fns/getUnixTime");
3908
+ var TtlCache = class {
3909
+ _cache = /* @__PURE__ */ new Map();
3910
+ _ttl;
3911
+ /**
3912
+ * Create a new TTL cache with the given TTL.
3856
3913
  *
3857
- * const response = await client.nameTokens({
3858
- * domainId: "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835" // namehash('vitalik.eth')
3859
- * })
3860
- * ```
3914
+ * @param ttl Time-to-live duration in seconds. Items expire after this duration.
3861
3915
  */
3862
- async nameTokens(request) {
3863
- const url = new URL(`/api/name-tokens`, this.options.url);
3864
- if (request.name !== void 0) {
3865
- url.searchParams.set("name", request.name);
3866
- } else if (request.domainId !== void 0) {
3867
- url.searchParams.set("domainId", request.domainId);
3916
+ constructor(ttl) {
3917
+ this._ttl = ttl;
3918
+ }
3919
+ _cleanup() {
3920
+ const now = (0, import_getUnixTime2.getUnixTime)(/* @__PURE__ */ new Date());
3921
+ for (const [key, entry] of this._cache.entries()) {
3922
+ if (entry.expiresAt <= now) {
3923
+ this._cache.delete(key);
3924
+ }
3868
3925
  }
3869
- const response = await fetch(url);
3870
- let responseData;
3871
- try {
3872
- responseData = await response.json();
3873
- } catch {
3874
- throw new Error("Malformed response data: invalid JSON");
3926
+ }
3927
+ set(key, value) {
3928
+ this._cleanup();
3929
+ const expiresAt = addDuration((0, import_getUnixTime2.getUnixTime)(/* @__PURE__ */ new Date()), this._ttl);
3930
+ this._cache.set(key, { value, expiresAt });
3931
+ }
3932
+ get(key) {
3933
+ this._cleanup();
3934
+ const entry = this._cache.get(key);
3935
+ if (!entry) {
3936
+ return void 0;
3875
3937
  }
3876
- if (!response.ok) {
3877
- let errorResponse;
3878
- try {
3879
- errorResponse = deserializeErrorResponse(responseData);
3880
- } catch {
3881
- console.log("Name Tokens API: handling a known server error.");
3882
- }
3883
- if (typeof errorResponse !== "undefined") {
3884
- throw new Error(`Fetching ENSNode Name Tokens Failed: ${errorResponse.message}`);
3885
- }
3938
+ if (entry.expiresAt <= (0, import_getUnixTime2.getUnixTime)(/* @__PURE__ */ new Date())) {
3939
+ this._cache.delete(key);
3940
+ return void 0;
3886
3941
  }
3887
- return deserializedNameTokensResponse(responseData);
3942
+ return entry.value;
3943
+ }
3944
+ clear() {
3945
+ this._cache.clear();
3946
+ }
3947
+ get size() {
3948
+ this._cleanup();
3949
+ return this._cache.size;
3950
+ }
3951
+ get capacity() {
3952
+ return Number.MAX_SAFE_INTEGER;
3953
+ }
3954
+ has(key) {
3955
+ this._cleanup();
3956
+ const entry = this._cache.get(key);
3957
+ if (!entry) {
3958
+ return false;
3959
+ }
3960
+ if (entry.expiresAt <= (0, import_getUnixTime2.getUnixTime)(/* @__PURE__ */ new Date())) {
3961
+ this._cache.delete(key);
3962
+ return false;
3963
+ }
3964
+ return true;
3965
+ }
3966
+ delete(key) {
3967
+ return this._cache.delete(key);
3888
3968
  }
3889
3969
  };
3890
3970
 
3891
- // src/ensv2/ids-lib.ts
3892
- var import_viem19 = require("viem");
3893
- var makeRegistryId = (accountId) => formatAccountId(accountId);
3894
- var makeENSv1DomainId = (node) => node;
3895
- var makeENSv2DomainId = (registry, canonicalId) => formatAssetId({
3896
- assetNamespace: AssetNamespaces.ERC1155,
3897
- contract: registry,
3898
- tokenId: canonicalId
3899
- });
3900
- var maskLower32Bits = (num) => num ^ num & 0xffffffffn;
3901
- var getCanonicalId = (input) => {
3902
- if (typeof input === "bigint") return maskLower32Bits(input);
3903
- return getCanonicalId((0, import_viem19.hexToBigInt)(input));
3904
- };
3905
- var makePermissionsId = (contract) => formatAccountId(contract);
3906
- var makePermissionsResourceId = (contract, resource) => `${makePermissionsId(contract)}/${resource}`;
3907
- var makePermissionsUserId = (contract, resource, user) => `${makePermissionsId(contract)}/${resource}/${user}`;
3908
- var makeResolverId = (contract) => formatAccountId(contract);
3909
- var makeResolverRecordsId = (resolver, node) => `${makeResolverId(resolver)}/${node}`;
3910
- var makeLatestRegistrationId = (domainId) => `${domainId}/latest`;
3911
- var makeRegistrationId = (domainId, index = 0) => `${domainId}/${index}`;
3912
- var makeLatestRenewalId = (domainId, registrationIndex) => `${makeRegistrationId(domainId, registrationIndex)}/latest`;
3913
- var makeRenewalId = (domainId, registrationIndex, index = 0) => `${makeRegistrationId(domainId, registrationIndex)}/${index}`;
3971
+ // src/shared/interpretation/interpret-address.ts
3972
+ var import_viem17 = require("viem");
3973
+ var interpretAddress = (owner) => (0, import_viem17.isAddressEqual)(import_viem17.zeroAddress, owner) ? null : owner;
3914
3974
 
3915
- // src/identity/identity.ts
3916
- var import_datasources11 = require("@ensnode/datasources");
3975
+ // src/shared/interpretation/interpret-record-values.ts
3976
+ var import_viem18 = require("viem");
3917
3977
 
3918
- // src/identity/types.ts
3919
- var ResolutionStatusIds = {
3920
- /**
3921
- * Represents that the `Identity` is not resolved yet.
3922
- */
3923
- Unresolved: "unresolved",
3924
- /**
3925
- * Represents that resolution of the `Identity` resulted in a named identity.
3926
- */
3927
- Named: "named",
3928
- /**
3929
- * Represents that resolution of the `Identity` resulted in an unnamed identity.
3930
- */
3931
- Unnamed: "unnamed",
3932
- /**
3933
- * Represents that attempted resolution of the `Identity` resulted in an error
3934
- * and therefore it is unknown if the `Identity` resolves to a named or unnamed identity.
3935
- */
3936
- Unknown: "unknown"
3937
- };
3978
+ // src/shared/null-bytes.ts
3979
+ var hasNullByte = (value) => value.indexOf("\0") !== -1;
3980
+ var stripNullBytes = (value) => value.replaceAll("\0", "");
3938
3981
 
3939
- // src/identity/identity.ts
3940
- function buildUnresolvedIdentity(address, namespaceId, chainId) {
3941
- return {
3942
- resolutionStatus: ResolutionStatusIds.Unresolved,
3943
- chainId: chainId ?? (0, import_datasources11.getENSRootChainId)(namespaceId),
3944
- address
3945
- };
3982
+ // src/shared/interpretation/interpret-record-values.ts
3983
+ function interpretNameRecordValue(value) {
3984
+ if (value === "") return null;
3985
+ if (!isNormalizedName(value)) return null;
3986
+ return value;
3946
3987
  }
3947
- function isResolvedIdentity(identity) {
3948
- return identity.resolutionStatus !== ResolutionStatusIds.Unresolved;
3988
+ function interpretAddressRecordValue(value) {
3989
+ if (hasNullByte(value)) return null;
3990
+ if (value === "") return null;
3991
+ if (value === "0x") return null;
3992
+ if (!(0, import_viem18.isAddress)(value)) return value;
3993
+ if ((0, import_viem18.isAddressEqual)(value, import_viem18.zeroAddress)) return null;
3994
+ return asLowerCaseAddress(value);
3995
+ }
3996
+ function interpretTextRecordKey(key) {
3997
+ if (hasNullByte(key)) return null;
3998
+ if (key === "") return null;
3999
+ return key;
4000
+ }
4001
+ function interpretTextRecordValue(value) {
4002
+ if (hasNullByte(value)) return null;
4003
+ if (value === "") return null;
4004
+ return value;
3949
4005
  }
3950
4006
 
3951
- // src/resolution/ensip19-chainid.ts
3952
- var import_chains = require("viem/chains");
4007
+ // src/shared/interpretation/interpret-tokenid.ts
4008
+ var interpretTokenIdAsLabelHash = (tokenId) => uint256ToHex32(tokenId);
4009
+ var interpretTokenIdAsNode = (tokenId) => uint256ToHex32(tokenId);
4010
+
4011
+ // src/shared/interpretation/interpreted-names-and-labels.ts
4012
+ var import_viem20 = require("viem");
4013
+ var import_ens10 = require("viem/ens");
4014
+
4015
+ // src/shared/labelhash.ts
4016
+ var import_viem19 = require("viem");
4017
+ var labelhashLiteralLabel = (label) => (0, import_viem19.keccak256)((0, import_viem19.stringToBytes)(label));
4018
+
4019
+ // src/shared/interpretation/interpreted-names-and-labels.ts
4020
+ function literalLabelToInterpretedLabel(label) {
4021
+ if (isNormalizedLabel(label)) return label;
4022
+ return encodeLabelHash(labelhashLiteralLabel(label));
4023
+ }
4024
+ function literalLabelsToInterpretedName(labels) {
4025
+ return labels.map(literalLabelToInterpretedLabel).join(".");
4026
+ }
4027
+ function interpretedLabelsToInterpretedName(labels) {
4028
+ return labels.join(".");
4029
+ }
4030
+ function literalLabelsToLiteralName(labels) {
4031
+ return labels.join(".");
4032
+ }
4033
+ function interpretedNameToInterpretedLabels(name) {
4034
+ return name.split(".");
4035
+ }
4036
+ function encodedLabelToLabelhash(label) {
4037
+ if (label.length !== 66) return null;
4038
+ if (label.indexOf("[") !== 0) return null;
4039
+ if (label.indexOf("]") !== 65) return null;
4040
+ const hash = `0x${label.slice(1, 65)}`;
4041
+ if (!(0, import_viem20.isHex)(hash)) return null;
4042
+ return hash;
4043
+ }
4044
+ function isInterpetedLabel(label) {
4045
+ if (label.startsWith("[")) {
4046
+ const labelHash = encodedLabelToLabelhash(label);
4047
+ if (labelHash === null) return false;
4048
+ }
4049
+ return isNormalizedLabel(label);
4050
+ }
4051
+ function isInterpretedName(name) {
4052
+ return name.split(".").every(isInterpetedLabel);
4053
+ }
4054
+ function interpretedNameToLabelHashPath(name) {
4055
+ return interpretedNameToInterpretedLabels(name).map((label) => {
4056
+ if (!isInterpetedLabel(label)) {
4057
+ throw new Error(
4058
+ `Invariant(interpretedNameToLabelHashPath): Expected InterpretedLabel, received '${label}'.`
4059
+ );
4060
+ }
4061
+ const maybeLabelHash = encodedLabelToLabelhash(label);
4062
+ if (maybeLabelHash !== null) return maybeLabelHash;
4063
+ return (0, import_ens10.labelhash)(label);
4064
+ }).toReversed();
4065
+ }
4066
+
4067
+ // src/shared/root-registry.ts
3953
4068
  var import_datasources12 = require("@ensnode/datasources");
3954
- var getResolvePrimaryNameChainIdParam = (chainId, namespaceId) => {
3955
- const ensRootChainId = (0, import_datasources12.getENSRootChainId)(namespaceId);
3956
- return chainId === ensRootChainId ? import_chains.mainnet.id : chainId;
3957
- };
3958
- var translateDefaultableChainIdToChainId = (chainId, namespaceId) => {
3959
- return chainId === DEFAULT_EVM_CHAIN_ID ? (0, import_datasources12.getENSRootChainId)(namespaceId) : chainId;
3960
- };
4069
+ var getENSv1Registry = (namespace) => getDatasourceContract(namespace, import_datasources12.DatasourceNames.ENSRoot, "ENSv1Registry");
4070
+ var isENSv1Registry = (namespace, contract) => accountIdEqual(getENSv1Registry(namespace), contract);
4071
+ var getENSv2RootRegistry = (namespace) => getDatasourceContract(namespace, import_datasources12.DatasourceNames.ENSv2Root, "RootRegistry");
4072
+ var getENSv2RootRegistryId = (namespace) => makeRegistryId(getENSv2RootRegistry(namespace));
4073
+ var isENSv2RootRegistry = (namespace, contract) => accountIdEqual(getENSv2RootRegistry(namespace), contract);
3961
4074
 
3962
- // src/resolution/resolver-records-selection.ts
3963
- var isSelectionEmpty = (selection) => !selection.name && !selection.addresses?.length && !selection.texts?.length;
4075
+ // src/shared/url.ts
4076
+ function isHttpProtocol(url) {
4077
+ return ["http:", "https:"].includes(url.protocol);
4078
+ }
4079
+ function isWebSocketProtocol(url) {
4080
+ return ["ws:", "wss:"].includes(url.protocol);
4081
+ }
3964
4082
 
3965
4083
  // src/tracing/ens-protocol-tracing.ts
3966
4084
  var PROTOCOL_ATTRIBUTE_PREFIX = "ens";