@ensnode/ensnode-sdk 0.34.0 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -48,6 +48,8 @@ const { names } = await client.resolvePrimaryNames("0x179A862703a4adfb29896552DF
48
48
 
49
49
  Resolves records for an ENS name (Forward Resolution), via ENSNode, which implements Protocol Acceleration for indexed names.
50
50
 
51
+ The returned `name` field, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name). If the name record returned by the resolver is not normalized, `null` is returned as if no name record was set.
52
+
51
53
  - `name`: The ENS Name whose records to resolve
52
54
  - `selection`: Optional selection of Resolver records:
53
55
  - `addresses`: Array of coin types to resolve addresses for
@@ -85,6 +87,8 @@ console.log(records);
85
87
 
86
88
  Resolves the primary name of the provided `address` on the specified `chainId`, via ENSNode, which implements Protocol Acceleration for indexed names. If the `address` specifies a valid [ENSIP-19 Default Name](https://docs.ens.domains/ensip/19/#default-primary-name), the Default Name will be returned. You _may_ query the Default EVM Chain Id (`0`) in order to determine the `address`'s Default Name directly.
87
89
 
90
+ The returned Primary Name, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name). If the primary name set for the address is not normalized, `null` is returned as if no primary name was set.
91
+
88
92
  - `address`: The Address whose Primary Name to resolve
89
93
  - `chainId`: The chain id within which to query the address' ENSIP-19 Multichain Primary Name
90
94
  - `options`: (optional) additional options
@@ -112,6 +116,8 @@ const { name } = await client.resolvePrimaryName("0x179A862703a4adfb29896552DF9e
112
116
 
113
117
  Resolves the primary names of the provided `address` on the specified chainIds, via ENSNode, which implements Protocol Acceleration for indexed names. If the `address` specifies a valid [ENSIP-19 Default Name](https://docs.ens.domains/ensip/19/#default-primary-name), the Default Name will be returned for all chainIds for which there is not a chain-specific Primary Name. To avoid misuse, you _may not_ query the Default EVM Chain Id (`0`) directly, and should rely on the aforementioned per-chain defaulting behavior.
114
118
 
119
+ Each returned Primary Name, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name). If the primary name set for the address on any chain is not normalized, `null` is returned for that chain as if no primary name was set.
120
+
115
121
  - `address`: The Address whose Primary Names to resolve
116
122
  - `options`: (optional) additional options
117
123
  - `chainIds`: The chain ids within which to query the address' ENSIP-19 Multichain Primary Name (default: all ENSIP-19 supported chains)
package/dist/index.d.ts CHANGED
@@ -298,13 +298,52 @@ declare function deserializeBlockrange(maybeBlockrange: Partial<Blockrange>, val
298
298
  declare function deserializeBlockRef(maybeBlockRef: Partial<BlockRef>, valueLabel?: string): BlockRef;
299
299
  declare function deserializeDuration(maybeDuration: string, valueLabel?: string): Duration;
300
300
 
301
- declare function isNormalized(name: Name): boolean;
301
+ /**
302
+ * Determines whether the Name is normalized.
303
+ *
304
+ * @param name - The Name to check for normalization
305
+ * @returns True if the name is normalized according to ENS normalization rules, false otherwise
306
+ */
307
+ declare function isNormalizedName(name: Name): boolean;
308
+ /**
309
+ * Determines whether the Label is normalized.
310
+ *
311
+ * @param label - The Label to check for normalization
312
+ * @returns True if the label is normalized according to ENS normalization rules, false otherwise
313
+ */
314
+ declare function isNormalizedLabel(label: Label): boolean;
302
315
 
303
316
  /**
304
317
  * Determines where the provided AccountId values represent the same address on the same chain.
305
318
  */
306
319
  declare const accountIdEqual: (a: AccountId, b: AccountId) => boolean;
307
320
 
321
+ /**
322
+ * Transforms a Literal Label into an Interpreted Label.
323
+ *
324
+ * @see https://ensnode.io/docs/reference/terminology#literal-label
325
+ * @see https://ensnode.io/docs/reference/terminology#interpreted-label
326
+ *
327
+ * @param label - The Literal Label string to interpret
328
+ * @returns The provided label if it is normalized, else the EncodedLabelHash of the label
329
+ */
330
+ declare function interpretLiteralLabel(label: Label): Label | EncodedLabelHash;
331
+ /**
332
+ * Transforms a Literal Name into an Interpreted Name.
333
+ *
334
+ * @see https://ensnode.io/docs/reference/terminology#literal-name
335
+ * @see https://ensnode.io/docs/reference/terminology#interpreted-name
336
+ *
337
+ * If the name provided to this function contains empty-string labels (i.e 'this..name'),
338
+ * then the empty string labels will be Interpreted. Empty-string is not a normalizable name, so the
339
+ * label will be replaced with its Encoded LabelHash representation (i.e. )
340
+ *
341
+ * @param name - The Literal Name string to interpret
342
+ * @returns The provided name if it is normalized, else converts each label in name that is not a
343
+ * normalized label into an Interpreted Label
344
+ */
345
+ declare function interpretLiteralName(name: Name): Name;
346
+
308
347
  /**
309
348
  * The ETH coinType.
310
349
  *
@@ -395,6 +434,16 @@ declare function parseReverseName(name: Name): {
395
434
  coinType: CoinType;
396
435
  } | null;
397
436
 
437
+ /**
438
+ * Formats a LabelHash as an Encoded LabelHash.
439
+ *
440
+ * @see https://ensnode.io/docs/reference/terminology#encoded-labelhash
441
+ *
442
+ * @param labelHash - A 32-byte hash string starting with '0x'
443
+ * @returns The encoded label hash in format `[hash_without_0x_prefix]`
444
+ */
445
+ declare const encodeLabelHash: (labelHash: LabelHash) => EncodedLabelHash;
446
+
398
447
  /**
399
448
  * A label set ID identifies a set of labels that can be used for deterministic healing.
400
449
  * A label set allows clients to deterministically heal their state against a server,
@@ -547,12 +596,33 @@ interface ENSIndexerPublicConfig {
547
596
  * provide safe use of indexed resolver record values (in appropriate
548
597
  * contexts).
549
598
  *
550
- * Note that enabling {@link indexAdditionalResolverRecords} results in
551
- * indexed data becoming a _superset_ of the Subgraph. For exact data-level
552
- * backwards compatibility with the ENS Subgraph,
599
+ * Note that enabling {@link indexAdditionalResolverRecords} results in indexed data becoming a
600
+ * _superset_ of the Subgraph. For exact data-level backwards compatibility with the ENS Subgraph,
553
601
  * {@link indexAdditionalResolverRecords} should be `false`.
554
602
  */
555
603
  indexAdditionalResolverRecords: boolean;
604
+ /**
605
+ * Controls ENSIndexer's handling of Literal Labels and Literal Names
606
+ * This configuration only applies to the Subgraph datamodel and Subgraph Compatible GraphQL API responses.
607
+ *
608
+ * When set to true, all Literal Labels and Literal Names encountered by ENSIndexer will be Interpreted.
609
+ * - https://ensnode.io/docs/reference/terminology#interpreted-label
610
+ * - https://ensnode.io/docs/reference/terminology#interpreted-name
611
+ *
612
+ * That is,
613
+ * 1) all Labels stored and returned by ENSIndexer will either be normalized or represented as an Encoded
614
+ * LabelHash, and
615
+ * 2) all Names stored and returned by ENSIndexer will either be normalized or consist of Labels that
616
+ * may be represented as an Encoded LabelHash of the Literal Label value found onchain.
617
+ *
618
+ * When set to false, ENSIndexer will store and return Literal Labels and Literal Names without further
619
+ * interpretation.
620
+ * - https://ensnode.io/docs/reference/terminology#literal-label
621
+ * - https://ensnode.io/docs/reference/terminology#literal-name
622
+ *
623
+ * NOTE: {@link replaceUnnormalized} must be `false` for subgraph compatible indexing behavior.
624
+ */
625
+ replaceUnnormalized: boolean;
556
626
  /**
557
627
  * Indexed Chain IDs
558
628
  *
@@ -602,12 +672,11 @@ interface SerializedENSIndexerPublicConfig extends Omit<ENSIndexerPublicConfig,
602
672
  declare function deserializeENSIndexerPublicConfig(maybeConfig: SerializedENSIndexerPublicConfig, valueLabel?: string): ENSIndexerPublicConfig;
603
673
 
604
674
  /**
605
- * Subgraph compatibility
675
+ * Determines if the provided `config` produces an index equivalent to the ENS Subgraph.
606
676
  *
607
- * Tells if indexer config guarantees data to be indexed while
608
- * maintaining full subgraph-compatibility.
677
+ * @see https://ensnode.io/docs/reference/subgraph-compatibility/
609
678
  */
610
- declare function isSubgraphCompatible(config: Pick<ENSIndexerPublicConfig, "plugins" | "healReverseAddresses" | "indexAdditionalResolverRecords" | "labelSet">): boolean;
679
+ declare function isSubgraphCompatible(config: Pick<ENSIndexerPublicConfig, "plugins" | "healReverseAddresses" | "indexAdditionalResolverRecords" | "replaceUnnormalized" | "labelSet">): boolean;
611
680
 
612
681
  /**
613
682
  * Serializes a {@link ChainConfig} object.
@@ -691,7 +760,7 @@ declare const makeDependencyInfoSchema: (valueLabel?: string) => z.ZodObject<{
691
760
  ensRainbowSchema: z.ZodInt;
692
761
  }, z.core.$strict>;
693
762
  declare function invariant_reverseResolversPluginNeedsResolverRecords(ctx: ZodCheckFnInput<Pick<ENSIndexerPublicConfig, "plugins" | "indexAdditionalResolverRecords">>): void;
694
- declare function invariant_isSubgraphCompatibleRequirements(ctx: ZodCheckFnInput<Pick<ENSIndexerPublicConfig, "plugins" | "isSubgraphCompatible" | "healReverseAddresses" | "indexAdditionalResolverRecords" | "labelSet">>): void;
763
+ declare function invariant_isSubgraphCompatibleRequirements(ctx: ZodCheckFnInput<Pick<ENSIndexerPublicConfig, "plugins" | "isSubgraphCompatible" | "healReverseAddresses" | "indexAdditionalResolverRecords" | "replaceUnnormalized" | "labelSet">>): void;
695
764
  /**
696
765
  * ENSIndexer Public Config Schema
697
766
  *
@@ -707,6 +776,7 @@ declare const makeENSIndexerPublicConfigSchema: (valueLabel?: string) => z.ZodOb
707
776
  }, z.core.$strip>;
708
777
  healReverseAddresses: z.ZodBoolean;
709
778
  indexAdditionalResolverRecords: z.ZodBoolean;
779
+ replaceUnnormalized: z.ZodBoolean;
710
780
  indexedChainIds: z.ZodPipe<z.ZodArray<z.ZodInt>, z.ZodTransform<Set<number>, number[]>>;
711
781
  isSubgraphCompatible: z.ZodBoolean;
712
782
  namespace: z.ZodEnum<{
@@ -1570,6 +1640,9 @@ declare class ENSNodeClient {
1570
1640
  /**
1571
1641
  * Resolves records for an ENS name (Forward Resolution).
1572
1642
  *
1643
+ * The returned `name` field, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name).
1644
+ * If the name record returned by the resolver is not normalized, `null` is returned as if no name record was set.
1645
+ *
1573
1646
  * @param name The ENS Name whose records to resolve
1574
1647
  * @param selection selection of Resolver records
1575
1648
  * @param options additional options
@@ -1605,6 +1678,9 @@ declare class ENSNodeClient {
1605
1678
  * the Default Name will be returned. You _may_ query the Default EVM Chain Id (`0`) in order to
1606
1679
  * determine the `address`'s Default Name directly.
1607
1680
  *
1681
+ * The returned Primary Name, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name).
1682
+ * If the primary name set for the address is not normalized, `null` is returned as if no primary name was set.
1683
+ *
1608
1684
  * @param address The Address whose Primary Name to resolve
1609
1685
  * @param chainId The chain id within which to query the address' ENSIP-19 Multichain Primary Name
1610
1686
  * @param options additional options
@@ -1637,6 +1713,9 @@ declare class ENSNodeClient {
1637
1713
  * Primary Name. To avoid misuse, you _may not_ query the Default EVM Chain Id (`0`) directly, and
1638
1714
  * should rely on the aforementioned per-chain defaulting behavior.
1639
1715
  *
1716
+ * Each returned Primary Name, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name).
1717
+ * If the primary name set for the address on any chain is not normalized, `null` is returned for that chain as if no primary name was set.
1718
+ *
1640
1719
  * @param address The Address whose Primary Names to resolve
1641
1720
  * @param options additional options
1642
1721
  * @param options.chainIds The set of chain ids within which to query the address' ENSIP-19
@@ -1715,4 +1794,4 @@ declare class ClientError extends Error {
1715
1794
  static fromErrorResponse({ message, details }: ErrorResponse): ClientError;
1716
1795
  }
1717
1796
 
1718
- export { ATTR_PROTOCOL_NAME, ATTR_PROTOCOL_STEP, ATTR_PROTOCOL_STEP_RESULT, type AcceleratableRequest, type AcceleratableResponse, type AccountId, BASENAMES_NODE, type BlockNumber, type BlockRef, type Blockrange, type Cache, type ChainId, type ChainIdString, type ChainIndexingActiveStatus, type ChainIndexingBackfillStatus, type ChainIndexingCompletedStatus, type ChainIndexingConfig, type ChainIndexingDefiniteConfig, type ChainIndexingFollowingStatus, type ChainIndexingIndefiniteConfig, type ChainIndexingStandbyStatus, type ChainIndexingStatus, type ChainIndexingStatusForBackfillOverallStatus, type ChainIndexingStatusId, ChainIndexingStatusIds, type ChainIndexingStrategyId, ChainIndexingStrategyIds, type ChainIndexingUnstartedStatus, ClientError, type ClientOptions, type ConfigResponse, DEFAULT_ENSNODE_API_URL, DEFAULT_EVM_CHAIN_ID, DEFAULT_EVM_COIN_TYPE, type Datetime, type DatetimeISO8601, type DeepPartial, DefaultRecordsSelection, type DependencyInfo, type Duration, type ENSIndexerOverallIndexingBackfillStatus, type ENSIndexerOverallIndexingCompletedStatus, type ENSIndexerOverallIndexingErrorStatus, type ENSIndexerOverallIndexingFollowingStatus, type ENSIndexerOverallIndexingStatus, type ENSIndexerOverallIndexingUnstartedStatus, type ENSIndexerPublicConfig, ENSNodeClient, ETH_COIN_TYPE, ETH_NODE, type EncodedLabelHash, type EnsRainbowClientLabelSet, type EnsRainbowServerLabelSet, type ErrorResponse, type ForwardResolutionArgs, ForwardResolutionProtocolStep, type ForwardResolutionResult, type IndexingStatusRequest, type IndexingStatusResponse, IndexingStatusResponseCodes, LINEANAMES_NODE, type Label, type LabelHash, type LabelSetId, type LabelSetVersion, LruCache, type MultichainPrimaryNameResolutionArgs, type MultichainPrimaryNameResolutionResult, type Name, type Node, type OverallIndexingStatusId, OverallIndexingStatusIds, PROTOCOL_ATTRIBUTE_PREFIX, PluginName, type ProtocolSpan, type ProtocolSpanTreeNode, type ProtocolTrace, REVERSE_ROOT_NODES, ROOT_NODE, type ResolvePrimaryNameRequest, type ResolvePrimaryNameResponse, type ResolvePrimaryNamesRequest, type ResolvePrimaryNamesResponse, type ResolveRecordsRequest, type ResolveRecordsResponse, type ResolverRecordsResponse, type ResolverRecordsResponseBase, type ResolverRecordsSelection, type ReverseResolutionArgs, ReverseResolutionProtocolStep, type ReverseResolutionResult, type RpcUrl, type SerializedENSIndexerOverallIndexingBackfillStatus, type SerializedENSIndexerOverallIndexingCompletedStatus, type SerializedENSIndexerOverallIndexingErrorStatus, type SerializedENSIndexerOverallIndexingFollowingStatus, type SerializedENSIndexerOverallIndexingStatus, type SerializedENSIndexerOverallIndexingUnstartedStatus, type SerializedENSIndexerPublicConfig, type SerializedIndexedChainIds, TraceableENSProtocol, type TraceableRequest, type TraceableResponse, type UnixTimestamp, type UrlString, accountIdEqual, addrReverseLabel, bigintToCoinType, buildEnsRainbowClientLabelSet, buildLabelSetId, buildLabelSetVersion, checkChainIndexingStatusesForBackfillOverallStatus, checkChainIndexingStatusesForCompletedOverallStatus, checkChainIndexingStatusesForFollowingOverallStatus, checkChainIndexingStatusesForUnstartedOverallStatus, coinTypeReverseLabel, coinTypeToEvmChainId, createIndexingConfig, deserializeBlockNumber, deserializeBlockRef, deserializeBlockrange, deserializeChainId, deserializeDatetime, deserializeDuration, deserializeENSIndexerIndexingStatus, deserializeENSIndexerPublicConfig, deserializeErrorResponse, deserializeUrl, evmChainIdToCoinType, getActiveChains, getNameHierarchy, getOmnichainIndexingCursor, getOverallApproxRealtimeDistance, getOverallIndexingStatus, getStandbyChains, getTimestampForHighestOmnichainKnownBlock, getTimestampForLowestOmnichainStartBlock, invariant_isSubgraphCompatibleRequirements, invariant_reverseResolversPluginNeedsResolverRecords, isLabelIndexable, isNormalized, isSelectionEmpty, isSubgraphCompatible, labelHashToBytes, makeDatabaseSchemaNameSchema, makeDependencyInfoSchema, makeENSIndexerPublicConfigSchema, makeFullyPinnedLabelSetSchema, makeIndexedChainIdsSchema, makeLabelSetIdSchema, makeLabelSetVersionSchema, makePluginsListSchema, makeSubdomainNode, maybeHealLabelByReverseAddress, parseNonNegativeInteger, parseReverseName, reverseName, serializeChainId, serializeChainIndexingStatuses, serializeDatetime, serializeENSIndexerIndexingStatus, serializeENSIndexerPublicConfig, serializeIndexedChainIds, serializeUrl, sortAscChainStatusesByStartBlock, uint256ToHex32, uniq, validateSupportedLabelSetAndVersion };
1797
+ export { ATTR_PROTOCOL_NAME, ATTR_PROTOCOL_STEP, ATTR_PROTOCOL_STEP_RESULT, type AcceleratableRequest, type AcceleratableResponse, type AccountId, BASENAMES_NODE, type BlockNumber, type BlockRef, type Blockrange, type Cache, type ChainId, type ChainIdString, type ChainIndexingActiveStatus, type ChainIndexingBackfillStatus, type ChainIndexingCompletedStatus, type ChainIndexingConfig, type ChainIndexingDefiniteConfig, type ChainIndexingFollowingStatus, type ChainIndexingIndefiniteConfig, type ChainIndexingStandbyStatus, type ChainIndexingStatus, type ChainIndexingStatusForBackfillOverallStatus, type ChainIndexingStatusId, ChainIndexingStatusIds, type ChainIndexingStrategyId, ChainIndexingStrategyIds, type ChainIndexingUnstartedStatus, ClientError, type ClientOptions, type ConfigResponse, DEFAULT_ENSNODE_API_URL, DEFAULT_EVM_CHAIN_ID, DEFAULT_EVM_COIN_TYPE, type Datetime, type DatetimeISO8601, type DeepPartial, DefaultRecordsSelection, type DependencyInfo, type Duration, type ENSIndexerOverallIndexingBackfillStatus, type ENSIndexerOverallIndexingCompletedStatus, type ENSIndexerOverallIndexingErrorStatus, type ENSIndexerOverallIndexingFollowingStatus, type ENSIndexerOverallIndexingStatus, type ENSIndexerOverallIndexingUnstartedStatus, type ENSIndexerPublicConfig, ENSNodeClient, ETH_COIN_TYPE, ETH_NODE, type EncodedLabelHash, type EnsRainbowClientLabelSet, type EnsRainbowServerLabelSet, type ErrorResponse, type ForwardResolutionArgs, ForwardResolutionProtocolStep, type ForwardResolutionResult, type IndexingStatusRequest, type IndexingStatusResponse, IndexingStatusResponseCodes, LINEANAMES_NODE, type Label, type LabelHash, type LabelSetId, type LabelSetVersion, LruCache, type MultichainPrimaryNameResolutionArgs, type MultichainPrimaryNameResolutionResult, type Name, type Node, type OverallIndexingStatusId, OverallIndexingStatusIds, PROTOCOL_ATTRIBUTE_PREFIX, PluginName, type ProtocolSpan, type ProtocolSpanTreeNode, type ProtocolTrace, REVERSE_ROOT_NODES, ROOT_NODE, type ResolvePrimaryNameRequest, type ResolvePrimaryNameResponse, type ResolvePrimaryNamesRequest, type ResolvePrimaryNamesResponse, type ResolveRecordsRequest, type ResolveRecordsResponse, type ResolverRecordsResponse, type ResolverRecordsResponseBase, type ResolverRecordsSelection, type ReverseResolutionArgs, ReverseResolutionProtocolStep, type ReverseResolutionResult, type RpcUrl, type SerializedENSIndexerOverallIndexingBackfillStatus, type SerializedENSIndexerOverallIndexingCompletedStatus, type SerializedENSIndexerOverallIndexingErrorStatus, type SerializedENSIndexerOverallIndexingFollowingStatus, type SerializedENSIndexerOverallIndexingStatus, type SerializedENSIndexerOverallIndexingUnstartedStatus, type SerializedENSIndexerPublicConfig, type SerializedIndexedChainIds, TraceableENSProtocol, type TraceableRequest, type TraceableResponse, type UnixTimestamp, type UrlString, accountIdEqual, addrReverseLabel, bigintToCoinType, buildEnsRainbowClientLabelSet, buildLabelSetId, buildLabelSetVersion, checkChainIndexingStatusesForBackfillOverallStatus, checkChainIndexingStatusesForCompletedOverallStatus, checkChainIndexingStatusesForFollowingOverallStatus, checkChainIndexingStatusesForUnstartedOverallStatus, coinTypeReverseLabel, coinTypeToEvmChainId, createIndexingConfig, deserializeBlockNumber, deserializeBlockRef, deserializeBlockrange, deserializeChainId, deserializeDatetime, deserializeDuration, deserializeENSIndexerIndexingStatus, deserializeENSIndexerPublicConfig, deserializeErrorResponse, deserializeUrl, encodeLabelHash, evmChainIdToCoinType, getActiveChains, getNameHierarchy, getOmnichainIndexingCursor, getOverallApproxRealtimeDistance, getOverallIndexingStatus, getStandbyChains, getTimestampForHighestOmnichainKnownBlock, getTimestampForLowestOmnichainStartBlock, interpretLiteralLabel, interpretLiteralName, invariant_isSubgraphCompatibleRequirements, invariant_reverseResolversPluginNeedsResolverRecords, isLabelIndexable, isNormalizedLabel, isNormalizedName, isSelectionEmpty, isSubgraphCompatible, labelHashToBytes, makeDatabaseSchemaNameSchema, makeDependencyInfoSchema, makeENSIndexerPublicConfigSchema, makeFullyPinnedLabelSetSchema, makeIndexedChainIdsSchema, makeLabelSetIdSchema, makeLabelSetVersionSchema, makePluginsListSchema, makeSubdomainNode, maybeHealLabelByReverseAddress, parseNonNegativeInteger, parseReverseName, reverseName, serializeChainId, serializeChainIndexingStatuses, serializeDatetime, serializeENSIndexerIndexingStatus, serializeENSIndexerPublicConfig, serializeIndexedChainIds, serializeUrl, sortAscChainStatusesByStartBlock, uint256ToHex32, uniq, validateSupportedLabelSetAndVersion };
package/dist/index.js CHANGED
@@ -124,6 +124,28 @@ function parseReverseName(name) {
124
124
  }
125
125
  }
126
126
 
127
+ // src/ens/is-normalized.ts
128
+ import { normalize } from "viem/ens";
129
+ function isNormalizedName(name) {
130
+ try {
131
+ return name === normalize(name);
132
+ } catch {
133
+ return false;
134
+ }
135
+ }
136
+ function isNormalizedLabel(label) {
137
+ if (label === "") return false;
138
+ if (label.includes(".")) return false;
139
+ try {
140
+ return label === normalize(label);
141
+ } catch {
142
+ return false;
143
+ }
144
+ }
145
+
146
+ // src/ens/encode-labelhash.ts
147
+ var encodeLabelHash = (labelHash) => `[${labelHash.slice(2)}]`;
148
+
127
149
  // src/ensindexer/config/deserialize.ts
128
150
  import { prettifyError as prettifyError2 } from "zod/v4";
129
151
 
@@ -322,22 +344,23 @@ ${prettifyError(parsed.error)}
322
344
  return parsed.data;
323
345
  }
324
346
 
325
- // src/shared/is-normalized.ts
326
- import { normalize } from "viem/ens";
327
- function isNormalized(name) {
328
- try {
329
- return name === normalize(name);
330
- } catch {
331
- return false;
332
- }
333
- }
334
-
335
347
  // src/shared/account-id.ts
336
348
  import { isAddressEqual } from "viem";
337
349
  var accountIdEqual = (a, b) => {
338
350
  return a.chainId === b.chainId && isAddressEqual(a.address, b.address);
339
351
  };
340
352
 
353
+ // src/shared/interpretation.ts
354
+ import { labelhash as labelhash2 } from "viem";
355
+ function interpretLiteralLabel(label) {
356
+ if (isNormalizedLabel(label)) return label;
357
+ return encodeLabelHash(labelhash2(label));
358
+ }
359
+ function interpretLiteralName(name) {
360
+ if (isNormalizedName(name)) return name;
361
+ return name.split(".").map(interpretLiteralLabel).join(".");
362
+ }
363
+
341
364
  // src/ensindexer/config/types.ts
342
365
  var PluginName = /* @__PURE__ */ ((PluginName2) => {
343
366
  PluginName2["Subgraph"] = "subgraph";
@@ -353,7 +376,7 @@ var PluginName = /* @__PURE__ */ ((PluginName2) => {
353
376
  // src/ensindexer/config/helpers.ts
354
377
  function isSubgraphCompatible(config) {
355
378
  const onlySubgraphPluginActivated = config.plugins.length === 1 && config.plugins[0] === "subgraph" /* Subgraph */;
356
- const indexingBehaviorIsSubgraphCompatible = !config.healReverseAddresses && !config.indexAdditionalResolverRecords;
379
+ const indexingBehaviorIsSubgraphCompatible = !config.healReverseAddresses && !config.indexAdditionalResolverRecords && !config.replaceUnnormalized;
357
380
  const labelSetIsSubgraphCompatible = config.labelSet.labelSetId === "subgraph" && config.labelSet.labelSetVersion === 0;
358
381
  return onlySubgraphPluginActivated && indexingBehaviorIsSubgraphCompatible && labelSetIsSubgraphCompatible;
359
382
  }
@@ -427,7 +450,7 @@ function invariant_reverseResolversPluginNeedsResolverRecords(ctx) {
427
450
  function invariant_isSubgraphCompatibleRequirements(ctx) {
428
451
  const { value: config } = ctx;
429
452
  if (config.isSubgraphCompatible !== isSubgraphCompatible(config)) {
430
- const message = config.isSubgraphCompatible ? `'isSubgraphCompatible' requires only the '${"subgraph" /* Subgraph */}' plugin to be active, both 'indexAdditionalResolverRecords' and 'healReverseAddresses' must be set to 'false', and labelSet must be {labelSetId: "subgraph", labelSetVersion: 0}` : `Both 'indexAdditionalResolverRecords' and 'healReverseAddresses' were set to 'false', the only active plugin was the '${"subgraph" /* Subgraph */}' plugin, and labelSet was {labelSetId: "subgraph", labelSetVersion: 0}. The 'isSubgraphCompatible' must be set to 'true'`;
453
+ const message = config.isSubgraphCompatible ? `'isSubgraphCompatible' requires only the '${"subgraph" /* Subgraph */}' plugin to be active, 'indexAdditionalResolverRecords', 'healReverseAddresses', and 'replaceUnnormalized' must be set to 'false', and labelSet must be {labelSetId: "subgraph", labelSetVersion: 0}` : `'indexAdditionalResolverRecords', 'healReverseAddresses', and 'replaceUnnormalized' were set to 'false', the only active plugin was the '${"subgraph" /* Subgraph */}' plugin, and labelSet was {labelSetId: "subgraph", labelSetVersion: 0}. The 'isSubgraphCompatible' must be set to 'true'`;
431
454
  ctx.issues.push({
432
455
  code: "custom",
433
456
  input: config,
@@ -443,6 +466,7 @@ var makeENSIndexerPublicConfigSchema = (valueLabel = "ENSIndexerPublicConfig") =
443
466
  indexAdditionalResolverRecords: z2.boolean({
444
467
  error: `${valueLabel}.indexAdditionalResolverRecords`
445
468
  }),
469
+ replaceUnnormalized: z2.boolean({ error: `${valueLabel}.replaceUnnormalized` }),
446
470
  indexedChainIds: makeIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),
447
471
  isSubgraphCompatible: z2.boolean({ error: `${valueLabel}.isSubgraphCompatible` }),
448
472
  namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),
@@ -476,6 +500,7 @@ function serializeENSIndexerPublicConfig(config) {
476
500
  databaseSchemaName,
477
501
  healReverseAddresses,
478
502
  indexAdditionalResolverRecords,
503
+ replaceUnnormalized,
479
504
  isSubgraphCompatible: isSubgraphCompatible2,
480
505
  namespace,
481
506
  plugins,
@@ -489,6 +514,7 @@ function serializeENSIndexerPublicConfig(config) {
489
514
  databaseSchemaName,
490
515
  healReverseAddresses,
491
516
  indexAdditionalResolverRecords,
517
+ replaceUnnormalized,
492
518
  isSubgraphCompatible: isSubgraphCompatible2,
493
519
  namespace,
494
520
  plugins,
@@ -1082,6 +1108,9 @@ var ENSNodeClient = class _ENSNodeClient {
1082
1108
  /**
1083
1109
  * Resolves records for an ENS name (Forward Resolution).
1084
1110
  *
1111
+ * The returned `name` field, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name).
1112
+ * If the name record returned by the resolver is not normalized, `null` is returned as if no name record was set.
1113
+ *
1085
1114
  * @param name The ENS Name whose records to resolve
1086
1115
  * @param selection selection of Resolver records
1087
1116
  * @param options additional options
@@ -1137,6 +1166,9 @@ var ENSNodeClient = class _ENSNodeClient {
1137
1166
  * the Default Name will be returned. You _may_ query the Default EVM Chain Id (`0`) in order to
1138
1167
  * determine the `address`'s Default Name directly.
1139
1168
  *
1169
+ * The returned Primary Name, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name).
1170
+ * If the primary name set for the address is not normalized, `null` is returned as if no primary name was set.
1171
+ *
1140
1172
  * @param address The Address whose Primary Name to resolve
1141
1173
  * @param chainId The chain id within which to query the address' ENSIP-19 Multichain Primary Name
1142
1174
  * @param options additional options
@@ -1180,6 +1212,9 @@ var ENSNodeClient = class _ENSNodeClient {
1180
1212
  * Primary Name. To avoid misuse, you _may not_ query the Default EVM Chain Id (`0`) directly, and
1181
1213
  * should rely on the aforementioned per-chain defaulting behavior.
1182
1214
  *
1215
+ * Each returned Primary Name, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name).
1216
+ * If the primary name set for the address on any chain is not normalized, `null` is returned for that chain as if no primary name was set.
1217
+ *
1183
1218
  * @param address The Address whose Primary Names to resolve
1184
1219
  * @param options additional options
1185
1220
  * @param options.chainIds The set of chain ids within which to query the address' ENSIP-19
@@ -1409,6 +1444,7 @@ export {
1409
1444
  deserializeENSIndexerPublicConfig,
1410
1445
  deserializeErrorResponse,
1411
1446
  deserializeUrl,
1447
+ encodeLabelHash,
1412
1448
  evmChainIdToCoinType,
1413
1449
  getActiveChains,
1414
1450
  getNameHierarchy,
@@ -1418,10 +1454,13 @@ export {
1418
1454
  getStandbyChains,
1419
1455
  getTimestampForHighestOmnichainKnownBlock,
1420
1456
  getTimestampForLowestOmnichainStartBlock,
1457
+ interpretLiteralLabel,
1458
+ interpretLiteralName,
1421
1459
  invariant_isSubgraphCompatibleRequirements,
1422
1460
  invariant_reverseResolversPluginNeedsResolverRecords,
1423
1461
  isLabelIndexable,
1424
- isNormalized,
1462
+ isNormalizedLabel,
1463
+ isNormalizedName,
1425
1464
  isSelectionEmpty,
1426
1465
  isSubgraphCompatible,
1427
1466
  labelHashToBytes,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ens/constants.ts","../src/ens/subname-helpers.ts","../src/ens/coin-type.ts","../src/ens/reverse-name.ts","../src/ens/names.ts","../src/ens/types.ts","../src/ens/parse-reverse-name.ts","../src/ensindexer/config/deserialize.ts","../src/ensindexer/config/zod-schemas.ts","../src/shared/cache.ts","../src/shared/collections.ts","../src/shared/serialize.ts","../src/shared/deserialize.ts","../src/shared/zod-schemas.ts","../src/shared/is-normalized.ts","../src/shared/account-id.ts","../src/ensindexer/config/types.ts","../src/ensindexer/config/helpers.ts","../src/ensindexer/config/serialize.ts","../src/ensindexer/config/labelset-utils.ts","../src/ensindexer/config/label-utils.ts","../src/ensindexer/config/parsing.ts","../src/ensindexer/indexing-status/deserialize.ts","../src/ensindexer/indexing-status/zod-schemas.ts","../src/shared/block-ref.ts","../src/ensindexer/indexing-status/types.ts","../src/ensindexer/indexing-status/helpers.ts","../src/ensindexer/indexing-status/serialize.ts","../src/tracing/index.ts","../src/api/helpers.ts","../src/api/zod-schemas.ts","../src/api/types.ts","../src/client-error.ts","../src/client.ts","../src/resolution/resolver-records-selection.ts","../src/resolution/default-records-selection.ts"],"sourcesContent":["import { namehash } from \"viem\";\n\nimport type { Node } from \"./types\";\n\nexport const ROOT_NODE: Node = namehash(\"\");\nexport const ETH_NODE = namehash(\"eth\");\nexport const BASENAMES_NODE = namehash(\"base.eth\");\nexport const LINEANAMES_NODE = namehash(\"linea.eth\");\n\n/**\n * A set of nodes whose children are used for reverse resolution.\n *\n * Useful for identifying if a domain is used for reverse resolution.\n * See apps/ensindexer/src/handlers/Registry.ts for context.\n */\nexport const REVERSE_ROOT_NODES: Set<Node> = new Set([namehash(\"addr.reverse\")]);\n","import { Address, Hex, concat, isAddress, isHash, keccak256, toHex } from \"viem\";\n\nimport { labelhash } from \"viem/ens\";\nimport { addrReverseLabel } from \"./reverse-name\";\nimport type { Label, LabelHash, Node } from \"./types\";\n\n/**\n * Implements one step of the namehash algorithm, combining `labelHash` with `node` to produce\n * the `node` of a given subdomain. Note that the order of the arguments is 'reversed' (as compared to\n * the actual concatenation) in order to improve readability (i.e. read as [labelHash].[node]).\n */\nexport const makeSubdomainNode = (labelHash: LabelHash, node: Node): Node =>\n keccak256(concat([node, labelHash]));\n\n/**\n * Attempt to heal the labelHash of an addr.reverse subname using an address that might be related to the subname.\n *\n * @throws if maybeReverseAddress is not a valid Address\n * @throws if labelHash is not a valid Labelhash\n *\n * @returns the original label if healed, otherwise null\n */\nexport const maybeHealLabelByReverseAddress = ({\n maybeReverseAddress,\n labelHash,\n}: {\n /** The address that is possibly associated with the addr.reverse subname */\n maybeReverseAddress: Address;\n\n /** The labelhash of the addr.reverse subname */\n labelHash: LabelHash;\n}): string | null => {\n // check if required arguments are valid\n if (!isAddress(maybeReverseAddress)) {\n throw new Error(\n `Invalid reverse address: '${maybeReverseAddress}'. Must be a valid EVM Address.`,\n );\n }\n\n if (!isHash(labelHash)) {\n throw new Error(\n `Invalid labelHash: '${labelHash}'. Must start with '0x' and represent 32 bytes.`,\n );\n }\n\n // derive the assumed label from the normalized address\n const assumedLabel = addrReverseLabel(maybeReverseAddress);\n\n // if labelHash of the assumed label matches the provided labelHash, heal\n if (labelhash(assumedLabel) === labelHash) return assumedLabel;\n\n // otherwise, healing did not succeed\n // TODO: log the event args for analysis and debugging\n return null;\n};\n\n/**\n * Encodes a uint256 bigint as hex string sized to 32 bytes.\n * Uses include, in the context of ENS, decoding the uint256-encoded tokenId of NFT-issuing contracts\n * into Node or LabelHash, which is a common behavior in the ENS ecosystem.\n * (see NameWrapper, ETHRegistrarController)\n */\nexport const uint256ToHex32 = (num: bigint): Hex => toHex(num, { size: 32 });\n\n/**\n * These characters are prohibited in normalized ENS names per the ENSIP-15\n * standard (https://docs.ens.domains/ensip/15). Names containing labels with\n * one or more of these characters are unusable by any app implementing\n * ENSIP-15 (e.g., via https://github.com/adraffy/ens-normalize.js\n * or https://github.com/namehash/ens-normalize-python).\n *\n * While many other characters (beyond these 4) are not supported by\n * ENSIP-15, only the following 4 characters are classified as \"unindexable\" due\n * to specific indexing concerns.\n *\n * Onchain ENS contracts do not enforce ENSIP-15 normalization for reasons\n * including the gas costs of enforcement. This allows unnormalized labels\n * containing these characters to exist onchain. Such labels must be handled\n * carefully by indexers to avoid conflicts.\n *\n * Some indexed labels are \"unknown\" (or \"unindexable\") but still require a\n * representation within indexed data. For this purpose, a special \"unknown\n * label\" format is defined (an EncodedLabelHash) that represents these labels in the format of\n * \"[{labelHash}]\" where {labelHash} is the labelHash of the unknown label.\n * When an indexed label is in this format it is necessary to distinguish an\n * \"unknown\" label containing a labelHash, from an unnormalized label literal\n * that is formatted to appear like an \"unknown\" label. For example, if the\n * unnormalized label literal\n * \"[24695ee963d29f0f52edfdea1e830d2fcfc9052d5ba70b194bddd0afbbc89765]\"\n * is indexed, it will be considered \"unindexable\" (due to the square bracket\n * characters) and therefore be represented as the following \"unknown\" label instead\n * \"[80968d00b78a91f47b233eaa213576293d16dadcbbdceb257bca94b08451ba7f]\"\n * which encodes the labelHash of the unnormalized label literal in\n * square brackets.\n */\nconst UNINDEXABLE_LABEL_CHARACTERS = [\n \"\\0\", // null byte: PostgreSQL does not allow storing this character in text fields.\n \".\", // conflicts with ENS label separator logic.\n \"[\", // conflicts with \"unknown label\" representations.\n \"]\", // conflicts with \"unknown label\" representations.\n];\n\nconst UNINDEXABLE_LABEL_CHARACTER_CODES = new Set(\n UNINDEXABLE_LABEL_CHARACTERS.map((char) => char.charCodeAt(0)),\n);\n\n/**\n * Check if any characters in `label` are \"unindexable\".\n *\n * Related logic in ENS Subgraph:\n * https://github.com/ensdomains/ens-subgraph/blob/c844791/src/utils.ts#L68\n *\n * @param label - The label to check. Note:\n * A `null` value for `label` represents an unhealable labelhash.\n *\n * @returns `true` if the label is indexable, `false` otherwise.\n */\nexport const isLabelIndexable = (label: Label | null): label is Label => {\n if (!label) return false;\n\n for (let i = 0; i < label.length; i++) {\n if (UNINDEXABLE_LABEL_CHARACTER_CODES.has(label.charCodeAt(i))) return false;\n }\n\n return true;\n};\n","import type { CoinType, EvmCoinType } from \"@ensdomains/address-encoder\";\nimport {\n coinTypeToEvmChainId as _coinTypeToEvmChainId,\n evmChainIdToCoinType as _evmChainIdToCoinType,\n} from \"@ensdomains/address-encoder/utils\";\nimport { ChainId } from \"../shared\";\n\n// re-export CoinType and EvmCoinType from @ensdomains/address-encoder\n// so consumers don't need it as a dependency\nexport type { CoinType, EvmCoinType } from \"@ensdomains/address-encoder\";\n\n/**\n * The ETH coinType.\n *\n * @see https://docs.ens.domains/ensip/9\n */\nexport const ETH_COIN_TYPE: CoinType = 60;\n\n/**\n * The 'default' chainId corresponding to the below {@link DEFAULT_EVM_COIN_TYPE} in the context of\n * ENSIP-19.\n *\n * @see https://docs.ens.domains/ensip/19\n */\nexport const DEFAULT_EVM_CHAIN_ID: ChainId = 0;\n\n/**\n * ENSIP-19 EVM CoinType representing the 'default' coinType for EVM chains in ENS.\n *\n * @see https://docs.ens.domains/ensip/19/#reverse-resolution\n */\nexport const DEFAULT_EVM_COIN_TYPE = 0x8000_0000 as EvmCoinType;\n\n/**\n * Converts a CoinType to an EVM Chain Id.\n *\n * NOTE: for whatever reason @ensdomains/address-encoder#coinTypeToEvmChainId doesn't handle the\n * mainnet case so we implement that here\n *\n * @see https://docs.ens.domains/ensip/11/\n */\nexport const coinTypeToEvmChainId = (coinType: CoinType): ChainId => {\n if (coinType === ETH_COIN_TYPE) return 1;\n return _coinTypeToEvmChainId(coinType);\n};\n\n/**\n * Converts an EVM Chain Id to a CoinType.\n *\n * NOTE: for whatever reason @ensdomains/address-encoder#evmChainIdToCoinType doesn't handle the\n * mainnet case so we implement that here\n */\nexport const evmChainIdToCoinType = (chainId: ChainId): CoinType => {\n if (chainId === 1) return ETH_COIN_TYPE;\n return _evmChainIdToCoinType(chainId);\n};\n\n/**\n * Converts a bigint value representing a CoinType into a valid CoinType.\n *\n * This is useful when onchain events emit coinTypes as bigint but we want to constrain them to\n * the CoinType type.\n *\n * @throws if `value` is too large to fit in Number.MAX_SAFE_INTEGER\n */\nexport const bigintToCoinType = (value: bigint): CoinType => {\n if (value > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new Error(`'${value}' cannot represent as CoinType, it is too large.`);\n }\n\n return Number(value) as CoinType;\n};\n","import { Address } from \"viem\";\n\nimport { CoinType, DEFAULT_EVM_COIN_TYPE, ETH_COIN_TYPE } from \"./coin-type\";\nimport type { Label, Name } from \"./types\";\n\n/**\n * Gets the Label used for the reverse names of subnames as per ENSIP-11 & ENSIP-19.\n *\n * @see https://docs.ens.domains/ensip/19/#reverse-resolution\n */\nexport const addrReverseLabel = (address: Address): Label => address.slice(2).toLowerCase();\n\n/**\n * Converts `coinType` to prefix-free hex string.\n *\n * @see https://docs.ens.domains/ensip/19\n */\nexport const coinTypeReverseLabel = (coinType: CoinType): Label => coinType.toString(16);\n\n/**\n * Gets the reverse name for an address according to ENSIP-11 & ENSIP-19.\n *\n * @see https://docs.ens.domains/ensip/11#specification\n * @see https://docs.ens.domains/ensip/19#specification\n *\n * @param address - The address to get the reverse name for\n * @param coinType - The coin type to use for the reverse name\n * @returns The reverse name for the address\n *\n * @example\n * ```ts\n * reverseName(\"0x1234\", BigInt(ETH_COIN_TYPE)) // \"1234.addr.reverse\"\n * reverseName(\"0x1234\", BigInt(0x80000000)) // \"1234.default.reverse\"\n * reverseName(\"0x1234\", BigInt(0x5678)) // \"1234.5678.reverse\"\n * ```\n */\nexport function reverseName(address: Address, coinType: CoinType): Name {\n const label = addrReverseLabel(address);\n\n const middle = (() => {\n switch (coinType) {\n case ETH_COIN_TYPE:\n return \"addr\";\n case DEFAULT_EVM_COIN_TYPE:\n return \"default\";\n default:\n return coinTypeReverseLabel(coinType);\n }\n })();\n\n return `${label}.${middle}.reverse`;\n}\n","import type { Name } from \"./types\";\n\n/**\n * Constructs a name hierarchy from a given Name.\n * i.e. sub.example.eth -> [sub.example.eth, example.eth, eth]\n */\nexport const getNameHierarchy = (name: Name): Name[] =>\n name.split(\".\").map((_, i, labels) => labels.slice(i).join(\".\"));\n","import type { Hex } from \"viem\";\n\n// re-export ENSNamespaceIds and ENSNamespaceId from @ensnode/datasources\n// so consumers don't need it as a dependency\nexport { ENSNamespaceIds } from \"@ensnode/datasources\";\nexport type { ENSNamespaceId } from \"@ensnode/datasources\";\n\n/**\n * A hash value that uniquely identifies a single ENS name.\n * Result of `namehash` function as specified in ENSIP-1.\n *\n * @example\n * ```\n * namehash(\"vitalik.eth\") === \"0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835\"\n * ```\n * @link https://docs.ens.domains/ensip/1#namehash-algorithm\n */\nexport type Node = Hex;\n\n/**\n * A Name represents a human-readable ENS name.\n *\n * ex: vitalik.eth\n */\nexport type Name = string;\n\n/**\n * A LabelHash is the result of the labelhash function (which is just keccak256) on a Label.\n *\n * @link https://docs.ens.domains/terminology#labelhash\n */\nexport type LabelHash = Hex;\n\n/**\n * A Label is a single part of an ENS Name.\n *\n * @link https://docs.ens.domains/terminology#label\n */\nexport type Label = string;\n\n/**\n * An EncodedLabelHash is a specially formatted unnormalized Label that should be interpreted as a\n * LabelHash literal, particularly for use within an ENS Name.\n *\n * @example [abcd]\n * @example [abcd].example.eth\n */\nexport type EncodedLabelHash = `[${string}]`;\n","import { Address, getAddress, hexToBigInt } from \"viem\";\nimport { CoinType, DEFAULT_EVM_COIN_TYPE, ETH_COIN_TYPE, bigintToCoinType } from \"./coin-type\";\nimport { Label, Name } from \"./types\";\n\n/**\n * Matches an ENSIP-19 Reverse Name\n *\n * @see https://github.com/ensdomains/ens-contracts/blob/20e34971fd55f9e3b3cf4a5825d52e1504d36493/contracts/utils/ENSIP19.sol#L70\n */\nconst REVERSE_NAME_REGEX = /^([0-9a-fA-F]+)\\.([0-9a-f]{1,64}|addr|default)\\.reverse$/;\n\n/**\n * Parses an address label (hex sans prefix) into an Address.\n *\n * @throws if address is invalid\n */\nconst parseAddressLabel = (addressLabel: Label): Address => getAddress(`0x${addressLabel}`);\n\n/**\n * Parses a coinType label (hex sans prefix) into an EVMCoinType.\n *\n * @throws if coinType is invalid\n */\nconst parseCoinTypeLabel = (coinTypeLabel: Label): CoinType => {\n if (coinTypeLabel === \"default\") return DEFAULT_EVM_COIN_TYPE;\n if (coinTypeLabel === \"addr\") return ETH_COIN_TYPE;\n\n return bigintToCoinType(hexToBigInt(`0x${coinTypeLabel}`));\n};\n\n/**\n * Parse the address and coinType out of an ENSIP-19 reverse name.\n */\nexport function parseReverseName(name: Name): { address: Address; coinType: CoinType } | null {\n const match = name.match(REVERSE_NAME_REGEX);\n if (!match) return null;\n\n try {\n const [, addressLabel, coinTypeLabel] = match;\n if (!addressLabel) return null;\n if (!coinTypeLabel) return null;\n\n return {\n address: parseAddressLabel(addressLabel),\n coinType: parseCoinTypeLabel(coinTypeLabel),\n };\n } catch {\n // either of the parse methods threw, unable to parse reverse name\n return null;\n }\n}\n","import { prettifyError } from \"zod/v4\";\nimport type { SerializedENSIndexerPublicConfig } from \"./serialized-types\";\nimport type { ENSIndexerPublicConfig } from \"./types\";\nimport { makeENSIndexerPublicConfigSchema } from \"./zod-schemas\";\n\n/**\n * Serialize a {@link ENSIndexerPublicConfig} object.\n */\nexport function deserializeENSIndexerPublicConfig(\n maybeConfig: SerializedENSIndexerPublicConfig,\n valueLabel?: string,\n): ENSIndexerPublicConfig {\n const schema = makeENSIndexerPublicConfigSchema(valueLabel);\n const parsed = schema.safeParse(maybeConfig);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ENSIndexerPublicConfig:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n","/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport z from \"zod/v4\";\nimport { uniq } from \"../../shared\";\nimport {\n ZodCheckFnInput,\n makeChainIdSchema,\n makeENSNamespaceIdSchema,\n makeNonNegativeIntegerSchema,\n makePositiveIntegerSchema,\n makeUrlSchema,\n} from \"../../shared/zod-schemas\";\nimport { isSubgraphCompatible } from \"./helpers\";\nimport { PluginName } from \"./types\";\nimport type { ENSIndexerPublicConfig } from \"./types\";\n\n/**\n * Makes a schema for parsing {@link IndexedChainIds}.\n */\nexport const makeIndexedChainIdsSchema = (valueLabel: string = \"Indexed Chain IDs\") =>\n z\n .array(makeChainIdSchema(valueLabel), {\n error: `${valueLabel} must be an array.`,\n })\n .min(1, { error: `${valueLabel} list must include at least one element.` })\n .transform((v) => new Set(v));\n\n/**\n * Makes a schema for parsing a list of {@link PluginName} items.\n *\n * The list is guaranteed to include at least one item exists, and no duplicates.\n */\nexport const makePluginsListSchema = (valueLabel: string = \"Plugins\") =>\n z\n .array(\n z.enum(PluginName, {\n error: `${valueLabel} must be a list with at least one valid plugin name. Valid plugins are: ${Object.values(\n PluginName,\n ).join(\", \")}`,\n }),\n )\n .min(1, {\n error: `${valueLabel} must be a list with at least one valid plugin name. Valid plugins are: ${Object.values(\n PluginName,\n ).join(\", \")}`,\n })\n .refine((arr) => arr.length === uniq(arr).length, {\n error: `${valueLabel} cannot contain duplicate values.`,\n });\n\n/**\n * Makes a schema for parsing a name for a database schema.\n *\n * The name is guaranteed to be a non-empty string.\n */\nexport const makeDatabaseSchemaNameSchema = (valueLabel: string = \"Database schema name\") =>\n z\n .string({ error: `${valueLabel} must be a string` })\n .trim()\n .nonempty({\n error: `${valueLabel} is required and must be a non-empty string.`,\n });\n\n/**\n * Makes a schema for parsing a label set ID.\n *\n * The label set ID is guaranteed to be a string between 1-50 characters\n * containing only lowercase letters (a-z) and hyphens (-).\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set ID\", \"LABEL_SET_ID\")\n */\nexport const makeLabelSetIdSchema = (valueLabel: string) => {\n return z\n .string({ error: `${valueLabel} must be a string` })\n .min(1, { error: `${valueLabel} must be 1-50 characters long` })\n .max(50, { error: `${valueLabel} must be 1-50 characters long` })\n .regex(/^[a-z-]+$/, {\n error: `${valueLabel} can only contain lowercase letters (a-z) and hyphens (-)`,\n });\n};\n\n/**\n * Makes a schema for parsing a label set version.\n *\n * The label set version is guaranteed to be a non-negative integer.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set version\", \"LABEL_SET_VERSION\")\n\n */\nexport const makeLabelSetVersionSchema = (valueLabel: string) => {\n return z.coerce\n .number({ error: `${valueLabel} must be an integer.` })\n .pipe(makeNonNegativeIntegerSchema(valueLabel));\n};\n\n/**\n * Makes a schema for parsing a label set where both label set ID and label set version are required.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set\", \"LABEL_SET\")\n */\nexport const makeFullyPinnedLabelSetSchema = (valueLabel: string = \"Label set\") => {\n let valueLabelLabelSetId = valueLabel;\n let valueLabelLabelSetVersion = valueLabel;\n if (valueLabel == \"LABEL_SET\") {\n valueLabelLabelSetId = \"LABEL_SET_ID\";\n valueLabelLabelSetVersion = \"LABEL_SET_VERSION\";\n } else {\n valueLabelLabelSetId = valueLabel + \".labelSetId\";\n valueLabelLabelSetVersion = valueLabel + \".labelSetVersion\";\n }\n return z.object({\n labelSetId: makeLabelSetIdSchema(valueLabelLabelSetId),\n labelSetVersion: makeLabelSetVersionSchema(valueLabelLabelSetVersion),\n });\n};\n\nconst makeNonEmptyStringSchema = (valueLabel: string = \"Value\") =>\n z.string().nonempty({ error: `${valueLabel} must be a non-empty string.` });\n\nexport const makeDependencyInfoSchema = (valueLabel: string = \"Value\") =>\n z.strictObject(\n {\n nodejs: makeNonEmptyStringSchema(),\n ponder: makeNonEmptyStringSchema(),\n ensRainbow: makeNonEmptyStringSchema(),\n ensRainbowSchema: makePositiveIntegerSchema(),\n },\n {\n error: `${valueLabel} must be a valid DependencyInfo object.`,\n },\n );\n\n// Invariant: ReverseResolvers plugin requires indexAdditionalResolverRecords\nexport function invariant_reverseResolversPluginNeedsResolverRecords(\n ctx: ZodCheckFnInput<Pick<ENSIndexerPublicConfig, \"plugins\" | \"indexAdditionalResolverRecords\">>,\n) {\n const { value: config } = ctx;\n\n const reverseResolversPluginActive = config.plugins.includes(PluginName.ReverseResolvers);\n\n if (reverseResolversPluginActive && !config.indexAdditionalResolverRecords) {\n ctx.issues.push({\n code: \"custom\",\n input: config,\n message: `The '${PluginName.ReverseResolvers}' plugin requires 'indexAdditionalResolverRecords' to be 'true'.`,\n });\n }\n}\n\n// Invariant: isSubgraphCompatible requires Subgraph plugin only, no extra indexing features, and subgraph label set\nexport function invariant_isSubgraphCompatibleRequirements(\n ctx: ZodCheckFnInput<\n Pick<\n ENSIndexerPublicConfig,\n | \"plugins\"\n | \"isSubgraphCompatible\"\n | \"healReverseAddresses\"\n | \"indexAdditionalResolverRecords\"\n | \"labelSet\"\n >\n >,\n) {\n const { value: config } = ctx;\n\n if (config.isSubgraphCompatible !== isSubgraphCompatible(config)) {\n const message = config.isSubgraphCompatible\n ? `'isSubgraphCompatible' requires only the '${PluginName.Subgraph}' plugin to be active, both 'indexAdditionalResolverRecords' and 'healReverseAddresses' must be set to 'false', and labelSet must be {labelSetId: \"subgraph\", labelSetVersion: 0}`\n : `Both 'indexAdditionalResolverRecords' and 'healReverseAddresses' were set to 'false', the only active plugin was the '${PluginName.Subgraph}' plugin, and labelSet was {labelSetId: \"subgraph\", labelSetVersion: 0}. The 'isSubgraphCompatible' must be set to 'true'`;\n\n ctx.issues.push({\n code: \"custom\",\n input: config,\n message,\n });\n }\n}\n\n/**\n * ENSIndexer Public Config Schema\n *\n * Makes a Zod schema definition for validating all important settings used\n * during runtime of the ENSIndexer instance.\n */\nexport const makeENSIndexerPublicConfigSchema = (valueLabel: string = \"ENSIndexerPublicConfig\") =>\n z\n .object({\n ensAdminUrl: makeUrlSchema(`${valueLabel}.ensAdminUrl`),\n ensNodePublicUrl: makeUrlSchema(`${valueLabel}.ensNodePublicUrl`),\n labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`),\n healReverseAddresses: z.boolean({ error: `${valueLabel}.healReverseAddresses` }),\n indexAdditionalResolverRecords: z.boolean({\n error: `${valueLabel}.indexAdditionalResolverRecords`,\n }),\n indexedChainIds: makeIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),\n isSubgraphCompatible: z.boolean({ error: `${valueLabel}.isSubgraphCompatible` }),\n namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),\n plugins: makePluginsListSchema(`${valueLabel}.plugins`),\n databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),\n dependencyInfo: makeDependencyInfoSchema(`${valueLabel}.dependencyInfo`),\n })\n /**\n * Validations\n *\n * All required data validations must be performed below.\n */\n .check(invariant_reverseResolversPluginNeedsResolverRecords)\n .check(invariant_isSubgraphCompatibleRequirements);\n","/**\n * Cache that maps from string -> ValueType.\n */\nexport interface Cache<KeyType extends string, ValueType> {\n /**\n * Store a value in the cache with the given key.\n *\n * @param key Cache key\n * @param value Value to store\n */\n set(key: KeyType, value: ValueType): void;\n\n /**\n * Retrieve a value from the cache with the given key.\n *\n * @param key Cache key\n * @returns The cached value if it exists, otherwise undefined\n */\n get(key: KeyType): ValueType | undefined;\n\n /**\n * Clear the cache.\n */\n clear(): void;\n\n /**\n * The current number of items in the cache. Always a non-negative integer.\n */\n get size(): number;\n\n /**\n * The maximum number of items in the cache. Always a non-negative integer that is >= size().\n */\n get capacity(): number;\n}\n\n/**\n * Cache that maps from string -> ValueType with a LRU (least recently used) eviction policy.\n *\n * `get` and `set` are O(1) operations.\n *\n * @link https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU\n */\nexport class LruCache<KeyType extends string, ValueType> implements Cache<KeyType, ValueType> {\n private readonly _cache = new Map<string, ValueType>();\n private readonly _capacity: number;\n\n /**\n * Create a new LRU cache with the given capacity.\n *\n * @param capacity The maximum number of items in the cache. If set to 0, the cache is effectively disabled.\n * @throws Error if capacity is not a non-negative integer.\n */\n public constructor(capacity: number) {\n if (!Number.isInteger(capacity)) {\n throw new Error(\n `LruCache requires capacity to be an integer but a capacity of ${capacity} was requested.`,\n );\n }\n\n if (capacity < 0) {\n throw new Error(\n `LruCache requires a non-negative capacity but a capacity of ${capacity} was requested.`,\n );\n }\n\n this._capacity = capacity;\n }\n\n public set(key: string, value: ValueType) {\n this._cache.set(key, value);\n\n if (this._cache.size > this._capacity) {\n // oldestKey is guaranteed to be defined\n const oldestKey = this._cache.keys().next().value as string;\n this._cache.delete(oldestKey);\n }\n }\n\n public get(key: string) {\n const value = this._cache.get(key);\n if (value) {\n // The key is already in the cache, move it to the end (most recent)\n this._cache.delete(key);\n this._cache.set(key, value);\n }\n return value;\n }\n\n public clear() {\n this._cache.clear();\n }\n\n public get size() {\n return this._cache.size;\n }\n\n public get capacity() {\n return this._capacity;\n }\n}\n","/**\n * Filter out duplicates.\n */\nexport const uniq = <T>(arr: T[]): T[] => [...new Set(arr)];\n","import type { ChainIdString, DatetimeISO8601, UrlString } from \"./serialized-types\";\nimport type { ChainId, Datetime } from \"./types\";\n\n/**\n * Serializes a {@link ChainId} value into its string representation.\n */\nexport function serializeChainId(chainId: ChainId): ChainIdString {\n return chainId.toString();\n}\n\n/**\n * Serializes a {@link Datetime} value into its string representation.\n */\nexport function serializeDatetime(datetime: Datetime): DatetimeISO8601 {\n return datetime.toISOString();\n}\n\n/**\n * Serializes a {@link URL} value into its string representation.\n */\nexport function serializeUrl(url: URL): UrlString {\n return url.toString();\n}\n","import { prettifyError } from \"zod/v4\";\nimport type { ChainIdString, UrlString } from \"./serialized-types\";\nimport type { BlockNumber, BlockRef, Blockrange, ChainId, Datetime, Duration } from \"./types\";\nimport {\n makeBlockNumberSchema,\n makeBlockRefSchema,\n makeBlockrangeSchema,\n makeChainIdStringSchema,\n makeDatetimeSchema,\n makeDurationSchema,\n makeUnixTimestampSchema,\n makeUrlSchema,\n} from \"./zod-schemas\";\n\nexport function deserializeChainId(maybeChainId: ChainIdString, valueLabel?: string): ChainId {\n const schema = makeChainIdStringSchema(valueLabel);\n const parsed = schema.safeParse(maybeChainId);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ChainId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeDatetime(maybeDatetime: string, valueLabel?: string): Datetime {\n const schema = makeDatetimeSchema(valueLabel);\n const parsed = schema.safeParse(maybeDatetime);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Datetime:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeUnixTimestamp(maybeTimestamp: number, valueLabel?: string) {\n const schema = makeUnixTimestampSchema(valueLabel);\n const parsed = schema.safeParse(maybeTimestamp);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Unix Timestamp:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeUrl(maybeUrl: UrlString, valueLabel?: string): URL {\n const schema = makeUrlSchema(valueLabel);\n const parsed = schema.safeParse(maybeUrl);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize URL:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockNumber(maybeBlockNumber: number, valueLabel?: string): BlockNumber {\n const schema = makeBlockNumberSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockNumber);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize BlockNumber:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockrange(maybeBlockrange: Partial<Blockrange>, valueLabel?: string) {\n const schema = makeBlockrangeSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockrange);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Blockrange:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockRef(\n maybeBlockRef: Partial<BlockRef>,\n valueLabel?: string,\n): BlockRef {\n const schema = makeBlockRefSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockRef);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize BlockRef:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeDuration(maybeDuration: string, valueLabel?: string): Duration {\n const schema = makeDurationSchema(valueLabel);\n const parsed = schema.safeParse(maybeDuration);\n\n if (parsed.error) {\n throw new RangeError(`Cannot deserialize Duration:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n","/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport z from \"zod/v4\";\nimport { ENSNamespaceIds } from \"../ens\";\nimport type { BlockRef, Datetime, Duration, UnixTimestamp } from \"./types\";\n\n/**\n * Zod `.check()` function input.\n */\nexport type ZodCheckFnInput<T> = z.core.ParsePayload<T>;\n\n/**\n * Parses a string value as a boolean.\n */\nexport const makeBooleanStringSchema = (valueLabel: string = \"Value\") =>\n z\n .string()\n .pipe(\n z.enum([\"true\", \"false\"], {\n error: `${valueLabel} must be 'true' or 'false'.`,\n }),\n )\n .transform((val) => val === \"true\");\n\n/**\n * Parses a numeric value as an integer.\n */\nexport const makeIntegerSchema = (valueLabel: string = \"Value\") =>\n z.int({\n error: `${valueLabel} must be an integer.`,\n });\n\n/**\n * Parses a numeric value as a positive integer.\n */\nexport const makePositiveIntegerSchema = (valueLabel: string = \"Value\") =>\n makeIntegerSchema(valueLabel).positive({\n error: `${valueLabel} must be a positive integer (>0).`,\n });\n\n/**\n * Parses a numeric value as a non-negative integer.\n */\nexport const makeNonNegativeIntegerSchema = (valueLabel: string = \"Value\") =>\n makeIntegerSchema(valueLabel).nonnegative({\n error: `${valueLabel} must be a non-negative integer (>=0).`,\n });\n\n/**\n * Parses a numeric value as {@link Duration}\n */\nexport const makeDurationSchema = (valueLabel: string = \"Value\") =>\n z.coerce\n .number({\n error: `${valueLabel} must be a number.`,\n })\n .pipe(makeNonNegativeIntegerSchema(valueLabel));\n\n/**\n * Parses Chain ID\n *\n * {@link ChainId}\n */\nexport const makeChainIdSchema = (valueLabel: string = \"Chain ID\") =>\n makePositiveIntegerSchema(valueLabel);\n\n/**\n * Parses a string representation of {@link ChainId}.\n */\nexport const makeChainIdStringSchema = (valueLabel: string = \"Chain ID String\") =>\n z\n .string({ error: `${valueLabel} must be a string representing a chain ID.` })\n .pipe(z.coerce.number({ error: `${valueLabel} must represent a positive integer (>0).` }))\n .pipe(makeChainIdSchema(`The numeric value represented by ${valueLabel}`));\n\n/**\n * Parses an ISO 8601 string representations of {@link Datetime}\n */\nexport const makeDatetimeSchema = (valueLabel: string = \"Datetime string\") =>\n z.iso\n .datetime({ error: `${valueLabel} must be a string in ISO 8601 format.` })\n .transform((v) => new Date(v));\n\n/**\n * Parses value as {@link UnixTimestamp}.\n */\nexport const makeUnixTimestampSchema = (valueLabel: string = \"Timestamp\") =>\n makeIntegerSchema(valueLabel);\n\n/**\n * Parses a string representations of {@link URL}\n */\nexport const makeUrlSchema = (valueLabel: string = \"Value\") =>\n z\n .url({\n error: `${valueLabel} must be a valid URL string (e.g., http://localhost:8080 or https://example.com).`,\n })\n .transform((v) => new URL(v));\n\n/**\n * Parses a string representation of a comma separated list.\n */\nexport const makeCommaSeparatedList = (valueLabel: string = \"Value\") =>\n z\n .string({ error: `${valueLabel} must be a comma separated list.` })\n .transform((val) => val.split(\",\").filter(Boolean))\n .refine((val) => val.length > 0, {\n error: `${valueLabel} must be a comma separated list with at least one value.`,\n });\n\n/**\n * Parses a numeric value as a block number.\n */\nexport const makeBlockNumberSchema = (valueLabel: string = \"Block number\") =>\n makeNonNegativeIntegerSchema(valueLabel);\n\n/**\n * Parses an object value as the {@link Blockrange} object.\n */\nexport const makeBlockrangeSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject(\n {\n startBlock: makeBlockNumberSchema(`${valueLabel}.startBlock`).optional(),\n endBlock: makeBlockNumberSchema(`${valueLabel}.endBlock`).optional(),\n },\n {\n error: `${valueLabel} must be a valid Blockrange object.`,\n },\n )\n .refine(\n (v) => {\n if (v.startBlock && v.endBlock) {\n return v.startBlock <= v.endBlock;\n }\n\n return true;\n },\n { error: `${valueLabel}: startBlock must be before or equal to endBlock` },\n );\n\n/**\n * Parses an object value as the {@link BlockRef} object.\n */\nexport const makeBlockRefSchema = (valueLabel: string = \"Value\") =>\n z.strictObject(\n {\n timestamp: makeUnixTimestampSchema(`${valueLabel}.timestamp`),\n number: makeBlockNumberSchema(`${valueLabel}.number`),\n },\n {\n error: `${valueLabel} must be a valid BlockRef object.`,\n },\n );\n\n/**\n * Parses a string value as ENSNamespaceId.\n */\nexport const makeENSNamespaceIdSchema = (valueLabel: string = \"ENSNamespaceId\") =>\n z.enum(ENSNamespaceIds, {\n error() {\n return `Invalid ${valueLabel}. Supported ENS namespace IDs are: ${Object.keys(ENSNamespaceIds).join(\", \")}`;\n },\n });\n\n/**\n * Parses a numeric value as a port number.\n */\nexport const makePortSchema = (valueLabel: string = \"Port\") =>\n makePositiveIntegerSchema(valueLabel).max(65535, {\n error: `${valueLabel} must be an integer between 1 and 65535.`,\n });\n","import { normalize } from \"viem/ens\";\n\nimport type { Name } from \"../ens\";\n\nexport function isNormalized(name: Name) {\n try {\n return name === normalize(name);\n } catch {\n return false;\n }\n}\n","import { isAddressEqual } from \"viem\";\nimport { AccountId } from \"./types\";\n\n/**\n * Determines where the provided AccountId values represent the same address on the same chain.\n */\nexport const accountIdEqual = (a: AccountId, b: AccountId): boolean => {\n return a.chainId === b.chainId && isAddressEqual(a.address, b.address);\n};\n","import { ENSNamespaceId } from \"@ensnode/datasources\";\n\nimport type { EnsRainbowClientLabelSet } from \"../../ensrainbow\";\nimport { ChainId } from \"../../shared\";\n\n/**\n * A PluginName is a unique id for a 'plugin': we use the notion of\n * 'plugins' to describe bundles of indexing logic.\n */\nexport enum PluginName {\n Subgraph = \"subgraph\",\n Basenames = \"basenames\",\n Lineanames = \"lineanames\",\n ThreeDNS = \"threedns\",\n ReverseResolvers = \"reverse-resolvers\",\n Referrals = \"referrals\",\n TokenScope = \"tokenscope\",\n}\n\n/**\n * Information about ENSIndexer's dependencies.\n */\nexport interface DependencyInfo {\n /** Node.js runtime version */\n nodejs: string;\n\n /** Ponder framework version */\n ponder: string;\n\n /** ENSRainbow service version */\n ensRainbow: string;\n\n /** ENSRainbow schema version */\n ensRainbowSchema: number;\n}\n\n/**\n * Complete public configuration object for ENSIndexer.\n *\n * We use parameter types to maintain fields layout and documentation across\n * the domain model and its serialized counterpart.\n */\nexport interface ENSIndexerPublicConfig {\n /**\n * The ENS namespace that ENSNode operates in the context of.\n *\n * See {@link ENSNamespaceIds} for available namespace identifiers.\n */\n namespace: ENSNamespaceId;\n\n /**\n * An ENSAdmin URL\n *\n * The ENSNode root api route `/` redirects to {@link ensAdminUrl},\n * configuring ENSAdmin with an entry for this instance of ENSNode,\n * identified by {@link ensNodePublicUrl}.\n *\n * @see https://ensnode.io/ensadmin/overview/what-is-ensadmin\n */\n ensAdminUrl: URL;\n\n /**\n * The publicly accessible endpoint of the ENSNode API\n * (ex: http://localhost:42069).\n *\n * ENSAdmin will use this url to connect to the ENSNode api for querying\n * state about the ENSNode instance.\n */\n ensNodePublicUrl: URL;\n\n /**\n * The \"fully pinned\" label set reference that ENSIndexer will request ENSRainbow use for deterministic label healing across time. This label set reference is \"fully pinned\" as it requires both the labelSetId and labelSetVersion fields to be defined.\n */\n labelSet: Required<EnsRainbowClientLabelSet>;\n\n /**\n * A Postgres database schema name. This instance of ENSIndexer will write\n * indexed data to the tables in this schema.\n *\n * Invariants:\n * - Must be a non-empty string that is a valid Postgres database schema\n * identifier.\n */\n databaseSchemaName: string;\n\n /**\n * A set of {@link PluginName}s indicating which plugins to activate.\n *\n * Invariants:\n * - A set of valid {@link PluginName}s with at least one value\n */\n plugins: PluginName[];\n\n /**\n * Enable or disable healing of addr.reverse subnames.\n * If this is set to true, ENSIndexer will attempt to heal subnames of\n * addr.reverse.\n */\n healReverseAddresses: boolean;\n\n /**\n * Enable or disable the indexing of Resolver record values.\n * If this is set to false, ENSIndexer will apply subgraph-backwards\n * compatible logic that only tracks the keys of Resolver records.\n * If this is set to true, ENSIndexer will track both the keys and the values\n * of Resolver records.\n *\n * WARNING: Special care must be taken when interacting with indexed resolver\n * record values. It is unsafe to naively assume that indexed resolver record\n * values are equivalent to the resolver record values that would be returned\n * through dynamic lookups via the ENS protocol. For example, if a resolver\n * implements CCIP-Read, the resolver records may not be discoverable through\n * onchain indexing. This feature is under R&D. At this time we do not\n * recommend anyone directly use indexed resolver record values in their\n * applications. Features are planned in the ENSNode roadmap that will\n * provide safe use of indexed resolver record values (in appropriate\n * contexts).\n *\n * Note that enabling {@link indexAdditionalResolverRecords} results in\n * indexed data becoming a _superset_ of the Subgraph. For exact data-level\n * backwards compatibility with the ENS Subgraph,\n * {@link indexAdditionalResolverRecords} should be `false`.\n */\n indexAdditionalResolverRecords: boolean;\n\n /**\n * Indexed Chain IDs\n *\n * Includes the {@link ChainId} for each chain being indexed.\n */\n indexedChainIds: Set<ChainId>;\n\n /**\n * A flag derived from the built config indicating whether ENSIndexer is operating in a\n * subgraph-compatible way. This flag is true if:\n * a) only the subgraph plugin is activated,\n * b) healReverseAddresess is false, and\n * c) indexRecordValues is false\n *\n * If {@link isSubgraphCompatible} is true, ENSIndexer will:\n * 1) use subgraph-compatible IDs for entities and events\n * 2) limit indexing behavior to subgraph indexing semantics\n */\n isSubgraphCompatible: boolean;\n\n /**\n * Information about the ENSIndexer instance dependencies.\n */\n dependencyInfo: DependencyInfo;\n}\n","import { type ENSIndexerPublicConfig, PluginName } from \"./types\";\n\n/**\n * Subgraph compatibility\n *\n * Tells if indexer config guarantees data to be indexed while\n * maintaining full subgraph-compatibility.\n */\nexport function isSubgraphCompatible(\n config: Pick<\n ENSIndexerPublicConfig,\n \"plugins\" | \"healReverseAddresses\" | \"indexAdditionalResolverRecords\" | \"labelSet\"\n >,\n): boolean {\n // 1. only the subgraph plugin is active\n const onlySubgraphPluginActivated =\n config.plugins.length === 1 && config.plugins[0] === PluginName.Subgraph;\n\n // 2. healReverseAddresses = false\n // 3. indexAdditionalResolverRecords = false\n const indexingBehaviorIsSubgraphCompatible =\n !config.healReverseAddresses && !config.indexAdditionalResolverRecords;\n\n // 4. label set id must be \"subgraph\" and version must be 0\n const labelSetIsSubgraphCompatible =\n config.labelSet.labelSetId === \"subgraph\" && config.labelSet.labelSetVersion === 0;\n\n return (\n onlySubgraphPluginActivated &&\n indexingBehaviorIsSubgraphCompatible &&\n labelSetIsSubgraphCompatible\n );\n}\n","import { ChainId } from \"../../shared\";\nimport { serializeUrl } from \"../../shared/serialize\";\nimport { SerializedENSIndexerPublicConfig, SerializedIndexedChainIds } from \"./serialized-types\";\nimport { ENSIndexerPublicConfig } from \"./types\";\n\n/**\n * Serializes a {@link ChainConfig} object.\n */\nexport function serializeIndexedChainIds(indexedChainIds: Set<ChainId>): SerializedIndexedChainIds {\n return Array.from(indexedChainIds);\n}\n/**\n * Serialize a {@link ENSIndexerPublicConfig} object.\n */\nexport function serializeENSIndexerPublicConfig(\n config: ENSIndexerPublicConfig,\n): SerializedENSIndexerPublicConfig {\n const {\n ensAdminUrl,\n ensNodePublicUrl,\n labelSet,\n indexedChainIds,\n databaseSchemaName,\n healReverseAddresses,\n indexAdditionalResolverRecords,\n isSubgraphCompatible,\n namespace,\n plugins,\n dependencyInfo,\n } = config;\n\n return {\n ensAdminUrl: serializeUrl(ensAdminUrl),\n ensNodePublicUrl: serializeUrl(ensNodePublicUrl),\n labelSet,\n indexedChainIds: serializeIndexedChainIds(indexedChainIds),\n databaseSchemaName,\n healReverseAddresses,\n indexAdditionalResolverRecords,\n isSubgraphCompatible,\n namespace,\n plugins,\n dependencyInfo,\n } satisfies SerializedENSIndexerPublicConfig;\n}\n","import {\n type EnsRainbowClientLabelSet,\n type EnsRainbowServerLabelSet,\n type LabelSetId,\n type LabelSetVersion,\n} from \"../../ensrainbow\";\nimport { makeLabelSetIdSchema, makeLabelSetVersionSchema } from \"./zod-schemas\";\n\n/**\n * Builds a valid LabelSetId from a string.\n * @param maybeLabelSetId - The string to validate and convert to a LabelSetId.\n * @returns A valid LabelSetId.\n * @throws If the input string is not a valid LabelSetId.\n */\nexport function buildLabelSetId(maybeLabelSetId: string): LabelSetId {\n return makeLabelSetIdSchema(\"LabelSetId\").parse(maybeLabelSetId);\n}\n\n/**\n * Builds a valid LabelSetVersion from a number or string.\n * @param maybeLabelSetVersion - The number or string to validate and convert to a LabelSetVersion.\n * @returns A valid LabelSetVersion.\n * @throws If the input is not a valid LabelSetVersion.\n */\nexport function buildLabelSetVersion(maybeLabelSetVersion: number | string): LabelSetVersion {\n return makeLabelSetVersionSchema(\"LabelSetVersion\").parse(maybeLabelSetVersion);\n}\n\n/**\n * Builds an EnsRainbowClientLabelSet.\n * @param labelSetId - The label set ID.\n * @param labelSetVersion - The label set version.\n * @returns A valid EnsRainbowClientLabelSet object.\n * @throws If `labelSetVersion` is defined without `labelSetId`.\n */\nexport function buildEnsRainbowClientLabelSet(\n labelSetId?: LabelSetId,\n labelSetVersion?: LabelSetVersion,\n): EnsRainbowClientLabelSet {\n if (labelSetVersion !== undefined && labelSetId === undefined) {\n throw new Error(\"When a labelSetVersion is defined, labelSetId must also be defined.\");\n }\n\n return { labelSetId, labelSetVersion };\n}\n\n/**\n * Validates that the server's label set is compatible with the client's requested label set.\n * @param serverSet - The label set provided by the server.\n * @param clientSet - The label set requested by the client.\n * @throws If the server set is not compatible with the client set.\n */\nexport function validateSupportedLabelSetAndVersion(\n serverSet: EnsRainbowServerLabelSet,\n clientSet: EnsRainbowClientLabelSet,\n): void {\n if (clientSet.labelSetId === undefined) {\n // Client did not specify a label set, so any server set is acceptable.\n return;\n }\n\n if (serverSet.labelSetId !== clientSet.labelSetId) {\n throw new Error(\n `Server label set ID \"${serverSet.labelSetId}\" does not match client's requested label set ID \"${clientSet.labelSetId}\".`,\n );\n }\n\n if (\n clientSet.labelSetVersion !== undefined &&\n serverSet.highestLabelSetVersion < clientSet.labelSetVersion\n ) {\n throw new Error(\n `Server highest label set version ${serverSet.highestLabelSetVersion} is less than client's requested version ${clientSet.labelSetVersion} for label set ID \"${clientSet.labelSetId}\".`,\n );\n }\n}\n","import { ByteArray, hexToBytes } from \"viem\";\nimport type { LabelHash } from \"../../ens\";\n\n/**\n * Converts a Labelhash to bytes, with validation\n * @param labelHash The Labelhash to convert\n * @returns A ByteArray containing the bytes\n * @throws Error if `labelHash` is not a valid 32-byte hex string\n */\nexport function labelHashToBytes(labelHash: LabelHash): ByteArray {\n try {\n if (labelHash.length !== 66) {\n throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);\n }\n if (labelHash !== labelHash.toLowerCase()) {\n throw new Error(\"Labelhash must be in lowercase\");\n }\n if (!labelHash.startsWith(\"0x\")) {\n throw new Error(\"Labelhash must be 0x-prefixed\");\n }\n const bytes = hexToBytes(labelHash);\n if (bytes.length !== 32) {\n // should be redundant but keeping it for the principle of defensive programming\n throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);\n }\n return bytes;\n } catch (e) {\n if (e instanceof Error) {\n throw e;\n }\n throw new Error(\"Invalid hex format\");\n }\n}\n","/**\n * Parses a string into a non-negative integer.\n * @param input The string to parse\n * @returns The parsed non-negative integer\n * @throws Error if the input is not a valid non-negative integer\n */\nexport function parseNonNegativeInteger(maybeNumber: string): number {\n const trimmed = maybeNumber.trim();\n\n // Check for empty strings\n if (!trimmed) {\n throw new Error(\"Input cannot be empty\");\n }\n\n // Check for -0\n if (trimmed === \"-0\") {\n throw new Error(\"Negative zero is not a valid non-negative integer\");\n }\n\n const num = Number(maybeNumber);\n\n // Check if it's not a number\n if (Number.isNaN(num)) {\n throw new Error(`\"${maybeNumber}\" is not a valid number`);\n }\n\n // Check if it's not finite\n if (!Number.isFinite(num)) {\n throw new Error(`\"${maybeNumber}\" is not a finite number`);\n }\n\n // Check if it's not an integer\n if (!Number.isInteger(num)) {\n throw new Error(`\"${maybeNumber}\" is not an integer`);\n }\n\n // Check if it's negative\n if (num < 0) {\n throw new Error(`\"${maybeNumber}\" is not a non-negative integer`);\n }\n\n return num;\n}\n","import { prettifyError } from \"zod/v4\";\nimport { SerializedENSIndexerOverallIndexingStatus } from \"./serialized-types\";\nimport { ENSIndexerOverallIndexingStatus } from \"./types\";\nimport { makeENSIndexerIndexingStatusSchema } from \"./zod-schemas\";\n\n/**\n * Serialize a {@link ENSIndexerOverallIndexingStatus} object.\n */\nexport function deserializeENSIndexerIndexingStatus(\n maybeStatus: SerializedENSIndexerOverallIndexingStatus,\n valueLabel?: string,\n): ENSIndexerOverallIndexingStatus {\n const schema = makeENSIndexerIndexingStatusSchema(valueLabel);\n const parsed = schema.safeParse(maybeStatus);\n\n if (parsed.error) {\n throw new Error(\n `Cannot deserialize ENSIndexerIndexingStatus:\\n${prettifyError(parsed.error)}\\n`,\n );\n }\n\n return parsed.data;\n}\n","/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport z from \"zod/v4\";\nimport { ChainId, deserializeChainId } from \"../../shared\";\nimport * as blockRef from \"../../shared/block-ref\";\nimport {\n makeBlockRefSchema,\n makeChainIdStringSchema,\n makeDurationSchema,\n makeUnixTimestampSchema,\n} from \"../../shared/zod-schemas\";\nimport {\n checkChainIndexingStatusesForBackfillOverallStatus,\n checkChainIndexingStatusesForCompletedOverallStatus,\n checkChainIndexingStatusesForFollowingOverallStatus,\n checkChainIndexingStatusesForUnstartedOverallStatus,\n getOverallApproxRealtimeDistance,\n getOverallIndexingStatus,\n getStandbyChains,\n} from \"./helpers\";\nimport {\n ChainIndexingBackfillStatus,\n ChainIndexingCompletedStatus,\n ChainIndexingConfig,\n ChainIndexingFollowingStatus,\n ChainIndexingStatus,\n ChainIndexingStatusForBackfillOverallStatus,\n ChainIndexingStatusIds,\n ChainIndexingStrategyIds,\n ChainIndexingUnstartedStatus,\n ENSIndexerOverallIndexingBackfillStatus,\n ENSIndexerOverallIndexingCompletedStatus,\n ENSIndexerOverallIndexingErrorStatus,\n ENSIndexerOverallIndexingFollowingStatus,\n ENSIndexerOverallIndexingUnstartedStatus,\n OverallIndexingStatusIds,\n} from \"./types\";\n\n/**\n * Makes Zod schema for {@link ChainIndexingConfig} type.\n */\nconst makeChainIndexingConfigSchema = (valueLabel: string = \"Value\") =>\n z.discriminatedUnion(\"strategy\", [\n z.strictObject({\n strategy: z.literal(ChainIndexingStrategyIds.Indefinite),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: z.null(),\n }),\n z.strictObject({\n strategy: z.literal(ChainIndexingStrategyIds.Definite),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n ]);\n\n/**\n * Makes Zod schema for {@link ChainIndexingUnstartedStatus} type.\n */\nexport const makeChainIndexingUnstartedStatusSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject({\n status: z.literal(ChainIndexingStatusIds.Unstarted),\n config: makeChainIndexingConfigSchema(valueLabel),\n })\n .refine(\n ({ config }) =>\n config.endBlock === null || blockRef.isBeforeOrEqualTo(config.startBlock, config.endBlock),\n {\n error: `config.startBlock must be before or same as config.endBlock.`,\n },\n );\n\n/**\n * Makes Zod schema for {@link ChainIndexingBackfillStatus} type.\n */\nexport const makeChainIndexingBackfillStatusSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject({\n status: z.literal(ChainIndexingStatusIds.Backfill),\n config: makeChainIndexingConfigSchema(valueLabel),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n latestSyncedBlock: makeBlockRefSchema(valueLabel),\n backfillEndBlock: makeBlockRefSchema(valueLabel),\n })\n .refine(\n ({ config, latestIndexedBlock }) =>\n blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock),\n {\n error: `config.startBlock must be before or same as latestIndexedBlock.`,\n },\n )\n .refine(\n ({ latestIndexedBlock, latestSyncedBlock }) =>\n blockRef.isBeforeOrEqualTo(latestIndexedBlock, latestSyncedBlock),\n {\n error: `latestIndexedBlock must be before or same as latestSyncedBlock.`,\n },\n )\n .refine(\n ({ latestSyncedBlock, backfillEndBlock }) =>\n blockRef.isBeforeOrEqualTo(latestSyncedBlock, backfillEndBlock),\n {\n error: `latestSyncedBlock must be before or same as backfillEndBlock.`,\n },\n )\n .refine(\n ({ config, backfillEndBlock }) =>\n config.endBlock === null || blockRef.isEqualTo(backfillEndBlock, config.endBlock),\n {\n error: `backfillEndBlock must be the same as config.endBlock.`,\n },\n );\n\n/**\n * Makes Zod schema for {@link ChainIndexingFollowingStatus} type.\n */\nexport const makeChainIndexingFollowingStatusSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject({\n status: z.literal(ChainIndexingStatusIds.Following),\n config: z.strictObject({\n strategy: z.literal(ChainIndexingStrategyIds.Indefinite),\n startBlock: makeBlockRefSchema(valueLabel),\n }),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n latestKnownBlock: makeBlockRefSchema(valueLabel),\n approxRealtimeDistance: makeDurationSchema(valueLabel),\n })\n .refine(\n ({ config, latestIndexedBlock }) =>\n blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock),\n {\n error: `config.startBlock must be before or same as latestIndexedBlock.`,\n },\n )\n .refine(\n ({ latestIndexedBlock, latestKnownBlock }) =>\n blockRef.isBeforeOrEqualTo(latestIndexedBlock, latestKnownBlock),\n {\n error: `latestIndexedBlock must be before or same as latestKnownBlock.`,\n },\n );\n\n/**\n * Makes Zod schema for {@link ChainIndexingCompletedStatus} type.\n */\nexport const makeChainIndexingCompletedStatusSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject({\n status: z.literal(ChainIndexingStatusIds.Completed),\n config: z.strictObject({\n strategy: z.literal(ChainIndexingStrategyIds.Definite),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n })\n .refine(\n ({ config, latestIndexedBlock }) =>\n blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock),\n {\n error: `config.startBlock must be before or same as latestIndexedBlock.`,\n },\n )\n .refine(\n ({ config, latestIndexedBlock }) =>\n blockRef.isBeforeOrEqualTo(latestIndexedBlock, config.endBlock),\n {\n error: `latestIndexedBlock must be before or same as config.endBlock.`,\n },\n );\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatus}\n */\nexport const makeChainIndexingStatusSchema = (valueLabel: string = \"Value\") =>\n z.discriminatedUnion(\"status\", [\n makeChainIndexingUnstartedStatusSchema(valueLabel),\n makeChainIndexingBackfillStatusSchema(valueLabel),\n makeChainIndexingFollowingStatusSchema(valueLabel),\n makeChainIndexingCompletedStatusSchema(valueLabel),\n ]);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatus} per chain.\n */\nexport const makeChainIndexingStatusesSchema = (valueLabel: string = \"Value\") =>\n z\n .record(makeChainIdStringSchema(), makeChainIndexingStatusSchema(valueLabel), {\n error: \"Chains configuration must be an object mapping valid chain IDs to their configs.\",\n })\n .transform((serializedChainsIndexingStatus) => {\n const chainsIndexingStatus = new Map<ChainId, ChainIndexingStatus>();\n\n for (const [chainIdString, chainStatus] of Object.entries(serializedChainsIndexingStatus)) {\n chainsIndexingStatus.set(deserializeChainId(chainIdString), chainStatus);\n }\n\n return chainsIndexingStatus;\n });\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingUnstartedStatus}\n */\nconst makeUnstartedOverallStatusSchema = (valueLabel?: string) =>\n z\n .strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.Unstarted),\n chains: makeChainIndexingStatusesSchema(valueLabel)\n .refine(\n (chains) =>\n checkChainIndexingStatusesForUnstartedOverallStatus(Array.from(chains.values())),\n {\n error: `${valueLabel} at least one chain must be in \"unstarted\" status and\neach chain has to have a status of either \"unstarted\", or \"completed\"`,\n },\n )\n .transform((chains) => chains as Map<ChainId, ChainIndexingUnstartedStatus>),\n })\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return getOverallIndexingStatus(chains) === indexingStatus.overallStatus;\n },\n { error: `${valueLabel} is an invalid overallStatus.` },\n );\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingBackfillStatus}\n */\nconst makeBackfillOverallStatusSchema = (valueLabel?: string) =>\n z\n .strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.Backfill),\n chains: makeChainIndexingStatusesSchema(valueLabel)\n .refine(\n (chains) =>\n checkChainIndexingStatusesForBackfillOverallStatus(Array.from(chains.values())),\n {\n error: `${valueLabel} at least one chain must be in \"backfill\" status and\neach chain has to have a status of either \"unstarted\", \"backfill\" or \"completed\"`,\n },\n )\n .transform((chains) => chains as Map<ChainId, ChainIndexingStatusForBackfillOverallStatus>),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return getOverallIndexingStatus(chains) === indexingStatus.overallStatus;\n },\n { error: `${valueLabel} is an invalid overallStatus.` },\n )\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n const standbyChainStartBlocks = getStandbyChains(chains).map(\n (chain) => chain.config.startBlock.timestamp,\n );\n\n const standbyChainEarliestStartBlocks = Math.min(...standbyChainStartBlocks);\n\n return indexingStatus.omnichainIndexingCursor <= standbyChainEarliestStartBlocks;\n },\n {\n error:\n \"omnichainIndexingCursor must be lower than or equal to the earliest config.startBlock across all standby chains\",\n },\n );\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingCompletedStatus}\n */\nconst makeCompletedOverallStatusSchema = (valueLabel?: string) =>\n z\n .strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.Completed),\n chains: makeChainIndexingStatusesSchema(valueLabel)\n .refine(\n (chains) =>\n checkChainIndexingStatusesForCompletedOverallStatus(Array.from(chains.values())),\n {\n error: `${valueLabel} all chains must have \"completed\" status`,\n },\n )\n .transform((chains) => chains as Map<ChainId, ChainIndexingCompletedStatus>),\n })\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return getOverallIndexingStatus(chains) === indexingStatus.overallStatus;\n },\n { error: `${valueLabel} is an invalid overallStatus.` },\n );\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingFollowingStatus}\n */\nconst makeFollowingOverallStatusSchema = (valueLabel?: string) =>\n z\n .strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.Following),\n chains: makeChainIndexingStatusesSchema(valueLabel),\n overallApproxRealtimeDistance: makeDurationSchema(valueLabel),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return getOverallIndexingStatus(chains) === indexingStatus.overallStatus;\n },\n { error: `${valueLabel} is an invalid overallStatus.` },\n )\n .refine(\n (indexingStatus) =>\n checkChainIndexingStatusesForFollowingOverallStatus(\n Array.from(indexingStatus.chains.values()),\n ),\n {\n error: `${valueLabel} at least one chain must be in \"following\" status`,\n },\n )\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return (\n getOverallApproxRealtimeDistance(chains) === indexingStatus.overallApproxRealtimeDistance\n );\n },\n { error: `${valueLabel} is an invalid overallApproxRealtimeDistance.` },\n )\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n const standbyChainStartBlocks = getStandbyChains(chains).map(\n (chain) => chain.config.startBlock.timestamp,\n );\n\n const standbyChainEarliestStartBlocks = Math.min(...standbyChainStartBlocks);\n\n return indexingStatus.omnichainIndexingCursor <= standbyChainEarliestStartBlocks;\n },\n {\n error:\n \"omnichainIndexingCursor must be lower than or equal to the earliest config.startBlock across all standby chains\",\n },\n );\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingErrorStatus}\n */\nconst makeErrorSchemaOverallStatusSchema = (valueLabel?: string) =>\n z.strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.IndexerError),\n });\n\n/**\n * ENSIndexer Overall Indexing Status Schema\n *\n * Makes a Zod schema definition for validating indexing status\n * across all chains indexed by ENSIndexer instance.\n */\nexport const makeENSIndexerIndexingStatusSchema = (\n valueLabel: string = \"ENSIndexerIndexingStatus\",\n) =>\n z.discriminatedUnion(\"overallStatus\", [\n makeUnstartedOverallStatusSchema(valueLabel),\n makeBackfillOverallStatusSchema(valueLabel),\n makeCompletedOverallStatusSchema(valueLabel),\n makeFollowingOverallStatusSchema(valueLabel),\n makeErrorSchemaOverallStatusSchema(valueLabel),\n ]);\n","import type { BlockRef } from \"./types\";\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is before blockB.\n */\nexport function isBefore(blockA: BlockRef, blockB: BlockRef) {\n return blockA.number < blockB.number && blockA.timestamp < blockB.timestamp;\n}\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is equal to blockB.\n */\nexport function isEqualTo(blockA: BlockRef, blockB: BlockRef) {\n return blockA.number === blockB.number && blockA.timestamp === blockB.timestamp;\n}\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is before or equal to blockB.\n */\nexport function isBeforeOrEqualTo(blockA: BlockRef, blockB: BlockRef) {\n return isBefore(blockA, blockB) || isEqualTo(blockA, blockB);\n}\n","import type { BlockRef, ChainId, Duration, UnixTimestamp } from \"../../shared\";\n\nexport const ChainIndexingStatusIds = {\n Unstarted: \"unstarted\",\n Backfill: \"backfill\",\n Following: \"following\",\n Completed: \"completed\",\n} as const;\n\n/**\n * ChainIndexingStatusId is the derived string union of possible Chain Indexing Status identifiers.\n */\nexport type ChainIndexingStatusId =\n (typeof ChainIndexingStatusIds)[keyof typeof ChainIndexingStatusIds];\n\nexport const OverallIndexingStatusIds = {\n Unstarted: \"unstarted\",\n Backfill: \"backfill\",\n Following: \"following\",\n Completed: \"completed\",\n IndexerError: \"indexer-error\",\n} as const;\n\n/**\n * OverallIndexingStatusId is the derived string union of possible Overall Indexing Status identifiers.\n */\nexport type OverallIndexingStatusId =\n (typeof OverallIndexingStatusIds)[keyof typeof OverallIndexingStatusIds];\n\nexport const ChainIndexingStrategyIds = {\n Indefinite: \"indefinite\",\n Definite: \"definite\",\n} as const;\n\n/**\n * ChainIndexingStrategyIds is the derived string union of possible Chain Indexing Strategy identifiers.\n */\nexport type ChainIndexingStrategyId =\n (typeof ChainIndexingStrategyIds)[keyof typeof ChainIndexingStrategyIds];\n\n/**\n * Chain Indexing Indefinite Config\n *\n * Configures a chain to be indexed for an indefinite range.\n */\nexport interface ChainIndexingIndefiniteConfig {\n /**\n * Chain indexing strategy.\n */\n strategy: typeof ChainIndexingStrategyIds.Indefinite;\n\n /**\n * The block where indexing of the chain starts.\n *\n * An indexed chain always has its `startBlock` defined.\n */\n startBlock: BlockRef;\n\n /**\n * Indefinite chain indexing configs always have a null `endBlock`.\n */\n endBlock?: null;\n}\n\n/**\n * Chain Indexing Definite Config\n *\n * Configures a chain to be indexed for a definite range.\n *\n * Invariants:\n * - `startBlock` is always before or the same as `endBlock`\n */\nexport interface ChainIndexingDefiniteConfig {\n /**\n * Chain indexing strategy.\n */\n strategy: typeof ChainIndexingStrategyIds.Definite;\n\n /**\n * The block where indexing of the chain starts.\n *\n * `startBlock` must always be defined.\n */\n startBlock: BlockRef;\n\n /**\n * The block where indexing of the chain ends.\n *\n * Definite chain indexing configs always have a defined `endBlock`.\n */\n endBlock: BlockRef;\n}\n\n/**\n * Chain Indexing Config\n *\n * Configuration of an indexed chain.\n */\nexport type ChainIndexingConfig = ChainIndexingIndefiniteConfig | ChainIndexingDefiniteConfig;\n\n/**\n * Chain Indexing Status: Unstarted\n *\n * Notes:\n * - The \"unstarted\" status applies when using omnichain ordering and\n * the omnichainIndexingCursor from the overall indexing status <= config.startBlock.timestamp.\n */\nexport interface ChainIndexingUnstartedStatus {\n status: typeof ChainIndexingStatusIds.Unstarted;\n config: ChainIndexingConfig;\n}\n\n/**\n * Chain Indexing Status: Backfill\n *\n * During a backfill, special performance optimizations are applied to\n * index all blocks between config.startBlock and backfillEndBlock\n * as fast as possible.\n *\n * Notes:\n * - The backfillEndBlock is either config.endBlock (if present) or\n * the latest block on the chain when the ENSIndexer process started up.\n * Note how this means the backfillEndBlock is always a \"fixed target\".\n * - When latestIndexedBlock reaches backfillEndBlock, the backfill is complete.\n * The moment backfill is complete the status does not immediately transition.\n * Instead, internal processing is completed for a period of time while\n * the status remains \"backfill\". After this internal processing is completed\n * the status will change to \"following\" or \"completed\" depending on\n * the configured indexing strategy. If the strategy is indefinite,\n * changes to \"following\", else if the strategy is definite, changes to\n * \"completed\".\n *\n * Invariants:\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always before or the same as `latestSyncedBlock`\n * - `latestSyncedBlock` is always before or the same as `backfillEndBlock`\n * - `backfillEndBlock` is the same as `config.endBlock` if and only if\n * the config is definite.\n */\nexport interface ChainIndexingBackfillStatus {\n status: typeof ChainIndexingStatusIds.Backfill;\n config: ChainIndexingConfig;\n\n /**\n * The block that was most recently indexed.\n */\n latestIndexedBlock: BlockRef;\n\n /**\n * The \"highest\" block that has been synced into RPC cache. Backfill indexing\n * is accelerated by cached RPC calls through this block height.\n */\n latestSyncedBlock: BlockRef;\n\n /**\n * The block that is the target for finishing the backfill.\n */\n backfillEndBlock: BlockRef;\n}\n\n/**\n * Chain Indexing Status: Following\n *\n * Following occurs after the backfill of a chain is completed and represents\n * the process of indefinitely following (and indexing!) new blocks as they are\n * added to the indexed chain across time.\n *\n * Invariants:\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always before or the same as `latestKnownBlock`\n */\nexport interface ChainIndexingFollowingStatus {\n status: typeof ChainIndexingStatusIds.Following;\n\n config: ChainIndexingIndefiniteConfig;\n\n /**\n * The block that was most recently indexed.\n */\n latestIndexedBlock: BlockRef;\n\n /**\n * The \"highest\" block that has been fetched by RPC calls and stored in\n * the RPC cache as part of the indexing process.\n */\n latestKnownBlock: BlockRef;\n\n /**\n * The number of seconds between `latestIndexedBlock.timestamp` and\n * the current time in ENSIndexer. This represents the upper-bound worst case\n * distance approximation between the latest block on the chain (independent\n * of it becoming known to us) and the latest block that has completed\n * indexing. The true distance to the latest block on the chain will be less\n * if the latest block on the chain was not issued at the current second.\n */\n approxRealtimeDistance: Duration;\n}\n\n/**\n * Chain Indexing Status: Completed\n *\n * Indexing of a chain is completed after the backfill when the chain is\n * not configured to be indefinitely indexed.\n *\n * Invariants:\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always the same as `config.endBlock`.\n */\nexport interface ChainIndexingCompletedStatus {\n status: typeof ChainIndexingStatusIds.Completed;\n config: ChainIndexingDefiniteConfig;\n\n /**\n * The block that was most recently indexed.\n */\n latestIndexedBlock: BlockRef;\n}\n\n/**\n * Chain Indexing Status\n *\n * Use the `status` field to determine the correct type interpretation at runtime.\n */\nexport type ChainIndexingStatus =\n | ChainIndexingUnstartedStatus\n | ChainIndexingBackfillStatus\n | ChainIndexingFollowingStatus\n | ChainIndexingCompletedStatus;\n\n/**\n * Chain Indexing Status: Active\n *\n * Represents a chain where indexing is currently active.\n * The `latestIndexedBlock` field will be available.\n */\nexport type ChainIndexingActiveStatus = ChainIndexingBackfillStatus | ChainIndexingFollowingStatus;\n\n/**\n * Chain Indexing Status: Standby\n *\n * Represents a chain where indexing is currently on standby (not happening).\n * The `latestIndexedBlock` field will not be available.\n */\nexport type ChainIndexingStandbyStatus =\n | ChainIndexingUnstartedStatus\n | ChainIndexingCompletedStatus;\n\n/**\n * ENSIndexer Overall Indexing Status: Unstarted\n *\n * Describes the current state of indexing operations across all indexed chains\n * when the overall indexing status is {@link OverallIndexingStatusIds.Unstarted}.\n */\nexport interface ENSIndexerOverallIndexingUnstartedStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.Unstarted;\n\n /**\n * Indexing Status for each chain.\n *\n * Each chain is guaranteed to have the \"unstarted\" status.\n * It's impossible for any chain to have status other than \"unstarted\".\n */\n chains: Map<ChainId, ChainIndexingUnstartedStatus>;\n}\n\n/**\n * Chain Indexing Status allowed when overall status is 'backfill'.\n */\nexport type ChainIndexingStatusForBackfillOverallStatus =\n | ChainIndexingUnstartedStatus\n | ChainIndexingBackfillStatus\n | ChainIndexingCompletedStatus;\n\n/**\n * ENSIndexer Overall Indexing Status: Backfill\n *\n * Describes the current state of indexing operations across all indexed chains\n * when the overall indexing status is {@link OverallIndexingStatusIds.Backfill}.\n */\nexport interface ENSIndexerOverallIndexingBackfillStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.Backfill;\n\n /**\n * Omnichain Indexing Cursor\n *\n * Identifies the timestamp of the progress of omnichain indexing across\n * all chains in {@link ChainIndexingBackfillStatus} status.\n *\n * Invariants:\n * - the cursor value is guaranteed to be lower than or equal to\n * the timestamp of the earliest `config.startBlock` across all chains\n * in {@link ChainIndexingStandbyStatus} status.\n */\n omnichainIndexingCursor: UnixTimestamp;\n\n /**\n * Indexing Status for each chain.\n *\n * At least one chain is guaranteed to be in the \"backfill\" status.\n * Each chain is guaranteed to have a status of either \"unstarted\",\n * \"backfill\" or \"completed\". It's impossible for any chain to be\n * in the \"following\" status.\n */\n chains: Map<ChainId, ChainIndexingStatusForBackfillOverallStatus>;\n}\n\n/**\n * ENSIndexer Overall Indexing Status: Completed\n *\n * Describes the final state of indexing operations across all indexed chains\n * when all indexed chains are configured for a definite indexing strategy and\n * all indexing of that definite range is completed.\n */\nexport interface ENSIndexerOverallIndexingCompletedStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.Completed;\n\n /**\n * Indexing Status for each chain.\n *\n * Each chain is guaranteed to have the \"completed\" status.\n * It's impossible for any chain to have status other than \"completed\".\n */\n chains: Map<ChainId, ChainIndexingCompletedStatus>;\n}\n\n/**\n * ENSIndexer Overall Indexing Status: Following\n *\n * Describes the state when the overall indexing status is\n * {@link OverallIndexingStatusIds.Following}.\n */\nexport interface ENSIndexerOverallIndexingFollowingStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.Following;\n\n /**\n * Omnichain Indexing Cursor\n *\n * Identifies the timestamp of the progress of omnichain indexing across\n * all chains in {@link ChainIndexingActiveStatus} status.\n *\n * Invariants:\n * - the cursor value is guaranteed to be lower than or equal to\n * the timestamp of the earliest `config.startBlock` across all chains\n * in {@link ChainIndexingStandbyStatus} status.\n */\n omnichainIndexingCursor: UnixTimestamp;\n\n /**\n * Indexing Status for each chain.\n *\n * At least one chain is guaranteed to be in the \"following\" status.\n * Each chain is guaranteed to have a status of either \"unstarted\",\n * \"backfill\", \"following\" or \"completed\".\n */\n chains: Map<ChainId, ChainIndexingStatus>;\n\n /**\n * The maximum\n * {@link ChainIndexingFollowingStatus.approxRealtimeDistance} value\n * across all chains with status: 'following'.\n */\n overallApproxRealtimeDistance: Duration;\n}\n\n/**\n * ENSIndexer Overall Indexing Status: Error\n *\n * Describes the state when ENSIndexer failed to return the indexing status for\n * all indexed chains.\n *\n * This state suggests an error with the \"primary\" ENSIndexer.\n */\nexport interface ENSIndexerOverallIndexingErrorStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.IndexerError;\n}\n\n/**\n * ENSIndexer Overall Indexing Status\n *\n * Describes the overall state of indexing operations.\n */\nexport type ENSIndexerOverallIndexingStatus =\n | ENSIndexerOverallIndexingUnstartedStatus\n | ENSIndexerOverallIndexingBackfillStatus\n | ENSIndexerOverallIndexingCompletedStatus\n | ENSIndexerOverallIndexingFollowingStatus\n | ENSIndexerOverallIndexingErrorStatus;\n","import { BlockRef, ChainId, Duration, UnixTimestamp } from \"../../shared\";\nimport {\n ChainIndexingActiveStatus,\n ChainIndexingCompletedStatus,\n ChainIndexingConfig,\n ChainIndexingDefiniteConfig,\n ChainIndexingIndefiniteConfig,\n ChainIndexingStandbyStatus,\n ChainIndexingStatus,\n ChainIndexingStatusForBackfillOverallStatus,\n ChainIndexingStatusIds,\n ChainIndexingStrategyIds,\n ChainIndexingUnstartedStatus,\n OverallIndexingStatusId,\n OverallIndexingStatusIds,\n} from \"./types\";\n\n/**\n * Get {@link OverallIndexingStatusId} based on indexed chains' statuses.\n *\n * This function decides what is the current overall indexing status,\n * based on provided chain indexing statuses. The fact that chain indexing\n * statuses were provided to this function guarantees there was no indexer\n * error, and that the overall indexing status is never\n * an {@link OverallIndexingStatusIds.IndexerError}\n */\nexport function getOverallIndexingStatus(\n chains: ChainIndexingStatus[],\n): Exclude<OverallIndexingStatusId, typeof OverallIndexingStatusIds.IndexerError> {\n const chainStatuses = chains.map((chain) => chain.status);\n\n let overallStatus: OverallIndexingStatusId;\n\n if (chainStatuses.some((chainStatus) => chainStatus === ChainIndexingStatusIds.Following)) {\n overallStatus = OverallIndexingStatusIds.Following;\n } else if (chainStatuses.some((chainStatus) => chainStatus === ChainIndexingStatusIds.Backfill)) {\n overallStatus = OverallIndexingStatusIds.Backfill;\n } else if (\n chainStatuses.some((chainStatus) => chainStatus === ChainIndexingStatusIds.Unstarted)\n ) {\n overallStatus = OverallIndexingStatusIds.Unstarted;\n } else {\n overallStatus = OverallIndexingStatusIds.Completed;\n }\n\n return overallStatus;\n}\n\n/**\n * Get overall approximate realtime distance across all indexed chains.\n *\n * @throws an error if none of the indexed chains was in the 'following' status.\n */\nexport function getOverallApproxRealtimeDistance(chains: ChainIndexingStatus[]): Duration {\n const chainApproxRealtimeDistances = chains\n .filter((chain) => chain.status === ChainIndexingStatusIds.Following)\n .map((chain) => chain.approxRealtimeDistance);\n\n if (chainApproxRealtimeDistances.length === 0) {\n throw new Error(\n `The overall approximate realtime distance value is undefined if no indexed chain is in the '${OverallIndexingStatusIds.Following}' status`,\n );\n }\n\n const approxRealtimeDistance = Math.max(...chainApproxRealtimeDistances);\n\n return approxRealtimeDistance;\n}\n\n/**\n * Get lowest of the highest end block across all chains which status is\n * {@link ChainIndexingStatus}.\n */\nexport function getTimestampForLowestOmnichainStartBlock(\n chains: ChainIndexingStatus[],\n): UnixTimestamp {\n const earliestKnownBlockTimestamps: UnixTimestamp[] = chains.map(\n (chain) => chain.config.startBlock.timestamp,\n );\n\n return Math.min(...earliestKnownBlockTimestamps);\n}\n\n/**\n * Get timestamp of the highest known block across all chains which status is\n * {@link ChainIndexingStatusForBackfillOverallStatus}.\n */\nexport function getTimestampForHighestOmnichainKnownBlock(\n chains: ChainIndexingStatus[],\n): UnixTimestamp {\n const latestKnownBlockTimestamps: UnixTimestamp[] = [];\n\n for (const chain of chains) {\n switch (chain.status) {\n case ChainIndexingStatusIds.Unstarted:\n if (chain.config.endBlock) {\n latestKnownBlockTimestamps.push(chain.config.endBlock.timestamp);\n }\n break;\n\n case ChainIndexingStatusIds.Backfill:\n latestKnownBlockTimestamps.push(chain.backfillEndBlock.timestamp);\n\n break;\n\n case ChainIndexingStatusIds.Completed:\n latestKnownBlockTimestamps.push(chain.latestIndexedBlock.timestamp);\n break;\n\n case ChainIndexingStatusIds.Following:\n latestKnownBlockTimestamps.push(chain.latestKnownBlock.timestamp);\n break;\n }\n }\n\n return Math.max(...latestKnownBlockTimestamps);\n}\n\n/**\n * Get Omnichain Indexing Cursor across all chains which status is\n * {@link ChainIndexingActiveStatus}.\n */\nexport function getOmnichainIndexingCursor(chains: ChainIndexingActiveStatus[]): UnixTimestamp {\n return Math.min(...chains.map((chain) => chain.latestIndexedBlock.timestamp));\n}\n\n/**\n * Get all chains which status is {@link ChainIndexingActiveStatus}.\n */\nexport function getActiveChains(chains: ChainIndexingStatus[]): ChainIndexingActiveStatus[] {\n return chains.filter(\n (chain) =>\n chain.status === ChainIndexingStatusIds.Backfill ||\n chain.status === ChainIndexingStatusIds.Following,\n );\n}\n\n/**\n * Get all chains which status is {@link ChainIndexingStandbyStatus}.\n */\nexport function getStandbyChains(chains: ChainIndexingStatus[]): ChainIndexingStandbyStatus[] {\n return chains.filter(\n (chain) =>\n chain.status === ChainIndexingStatusIds.Unstarted ||\n chain.status === ChainIndexingStatusIds.Completed,\n );\n}\n\n/**\n * Create {@link ChainIndexingConfig} for given block refs.\n *\n * @param startBlock required block ref\n * @param endBlock optional block ref\n */\nexport function createIndexingConfig(\n startBlock: BlockRef,\n endBlock: BlockRef | null,\n): ChainIndexingConfig {\n if (endBlock) {\n return {\n strategy: ChainIndexingStrategyIds.Definite,\n startBlock,\n endBlock,\n } satisfies ChainIndexingDefiniteConfig;\n }\n\n return {\n strategy: ChainIndexingStrategyIds.Indefinite,\n startBlock,\n endBlock: null,\n } satisfies ChainIndexingIndefiniteConfig;\n}\n\n/**\n * Check if Chain Indexing Statuses fit the 'unstarted' overall status\n * requirements:\n * - All chains are guaranteed to have a status of \"unstarted\".\n *\n * Note: This function narrows the {@link ChainIndexingStatus} type to\n * {@link ChainIndexingUnstartedStatus}.\n */\nexport function checkChainIndexingStatusesForUnstartedOverallStatus(\n chains: ChainIndexingStatus[],\n): chains is ChainIndexingUnstartedStatus[] {\n return chains.every((chain) => chain.status === ChainIndexingStatusIds.Unstarted);\n}\n\n/**\n * Check if Chain Indexing Statuses fit the 'backfill' overall status\n * requirements:\n * - At least one chain is guaranteed to be in the \"backfill\" status.\n * - Each chain is guaranteed to have a status of either \"unstarted\",\n * \"backfill\" or \"completed\".\n *\n * Note: This function narrows the {@linkChainIndexingStatus} type to\n * {@link ChainIndexingStatusForBackfillOverallStatus}.\n */\nexport function checkChainIndexingStatusesForBackfillOverallStatus(\n chains: ChainIndexingStatus[],\n): chains is ChainIndexingStatusForBackfillOverallStatus[] {\n const atLeastOneChainInTargetStatus = chains.some(\n (chain) => chain.status === ChainIndexingStatusIds.Backfill,\n );\n const otherChainsHaveValidStatuses = chains.every(\n (chain) =>\n chain.status === ChainIndexingStatusIds.Unstarted ||\n chain.status === ChainIndexingStatusIds.Backfill ||\n chain.status === ChainIndexingStatusIds.Completed,\n );\n\n return atLeastOneChainInTargetStatus && otherChainsHaveValidStatuses;\n}\n\n/**\n * Checks if Chain Indexing Statuses fit the 'completed' overall status\n * requirements:\n * - All chains are guaranteed to have a status of \"completed\".\n *\n * Note: This function narrows the {@linkChainIndexingStatus} type to\n * {@link ChainIndexingCompletedStatus}.\n */\nexport function checkChainIndexingStatusesForCompletedOverallStatus(\n chains: ChainIndexingStatus[],\n): chains is ChainIndexingCompletedStatus[] {\n const allChainsHaveValidStatuses = chains.every(\n (chain) => chain.status === ChainIndexingStatusIds.Completed,\n );\n\n return allChainsHaveValidStatuses;\n}\n\n/**\n * Checks Chain Indexing Statuses fit the 'following' overall status\n * requirements:\n * - At least one chain is guaranteed to be in the \"following\" status.\n * - Any other chain can have any status.\n */\nexport function checkChainIndexingStatusesForFollowingOverallStatus(\n chains: ChainIndexingStatus[],\n): chains is ChainIndexingStatus[] {\n const allChainsHaveValidStatuses = chains.some(\n (chain) => chain.status === ChainIndexingStatusIds.Following,\n );\n\n return allChainsHaveValidStatuses;\n}\n\n/**\n * Sort a list of [{@link ChainId}, {@link ChainIndexingStatus}] tuples\n * by the omnichain start block timestamp in ascending order.\n */\nexport function sortAscChainStatusesByStartBlock<ChainStatusType extends ChainIndexingStatus>(\n chains: [ChainId, ChainStatusType][],\n): [ChainId, ChainStatusType][] {\n // Sort the chain statuses by the omnichain first block to index timestamp\n chains.sort(\n ([, chainA], [, chainB]) =>\n chainA.config.startBlock.timestamp - chainB.config.startBlock.timestamp,\n );\n\n return chains;\n}\n","import { ChainId, ChainIdString, serializeChainId } from \"../../shared\";\nimport {\n SerializedENSIndexerOverallIndexingBackfillStatus,\n SerializedENSIndexerOverallIndexingCompletedStatus,\n SerializedENSIndexerOverallIndexingErrorStatus,\n SerializedENSIndexerOverallIndexingFollowingStatus,\n SerializedENSIndexerOverallIndexingStatus,\n SerializedENSIndexerOverallIndexingUnstartedStatus,\n} from \"./serialized-types\";\nimport {\n ChainIndexingStatus,\n ENSIndexerOverallIndexingStatus,\n OverallIndexingStatusIds,\n} from \"./types\";\n\n/**\n * Serialize chain indexing statuses.\n */\nexport function serializeChainIndexingStatuses<ChainIndexingStatusType extends ChainIndexingStatus>(\n chainIndexingStatuses: Map<ChainId, ChainIndexingStatusType>,\n): Record<ChainIdString, ChainIndexingStatusType> {\n const serializedChainsIndexingStatuses: Record<ChainIdString, ChainIndexingStatusType> = {};\n\n for (const [chainId, chainIndexingStatus] of chainIndexingStatuses.entries()) {\n serializedChainsIndexingStatuses[serializeChainId(chainId)] = chainIndexingStatus;\n }\n\n return serializedChainsIndexingStatuses;\n}\n\n/**\n * Serialize a {@link ENSIndexerIndexingStatus} object.\n */\nexport function serializeENSIndexerIndexingStatus(\n indexingStatus: ENSIndexerOverallIndexingStatus,\n): SerializedENSIndexerOverallIndexingStatus {\n switch (indexingStatus.overallStatus) {\n case OverallIndexingStatusIds.IndexerError:\n return {\n overallStatus: OverallIndexingStatusIds.IndexerError,\n } satisfies SerializedENSIndexerOverallIndexingErrorStatus;\n\n case OverallIndexingStatusIds.Unstarted:\n return {\n overallStatus: OverallIndexingStatusIds.Unstarted,\n chains: serializeChainIndexingStatuses(indexingStatus.chains),\n } satisfies SerializedENSIndexerOverallIndexingUnstartedStatus;\n\n case OverallIndexingStatusIds.Backfill:\n return {\n overallStatus: OverallIndexingStatusIds.Backfill,\n chains: serializeChainIndexingStatuses(indexingStatus.chains),\n omnichainIndexingCursor: indexingStatus.omnichainIndexingCursor,\n } satisfies SerializedENSIndexerOverallIndexingBackfillStatus;\n\n case OverallIndexingStatusIds.Completed: {\n return {\n overallStatus: OverallIndexingStatusIds.Completed,\n chains: serializeChainIndexingStatuses(indexingStatus.chains),\n } satisfies SerializedENSIndexerOverallIndexingCompletedStatus;\n }\n\n case OverallIndexingStatusIds.Following:\n return {\n overallStatus: OverallIndexingStatusIds.Following,\n chains: serializeChainIndexingStatuses(indexingStatus.chains),\n overallApproxRealtimeDistance: indexingStatus.overallApproxRealtimeDistance,\n omnichainIndexingCursor: indexingStatus.omnichainIndexingCursor,\n } satisfies SerializedENSIndexerOverallIndexingFollowingStatus;\n }\n}\n","/**\n * Identifiers for each traceable ENS protocol.\n */\nexport enum TraceableENSProtocol {\n ForwardResolution = \"forward-resolution\",\n ReverseResolution = \"reverse-resolution\",\n}\n\n/**\n * Encodes the set of well-known steps in the ENS Forward Resolution protocol.\n */\nexport enum ForwardResolutionProtocolStep {\n Operation = \"forward-resolution\",\n FindResolver = \"find-resolver\",\n ActiveResolverExists = \"active-resolver-exists\",\n AccelerateENSIP19ReverseResolver = \"accelerate-ensip-19-reverse-resolver\",\n AccelerateKnownOffchainLookupResolver = \"accelerate-known-offchain-lookup-resolver\",\n AccelerateKnownOnchainStaticResolver = \"accelerate-known-onchain-static-resolver\",\n RequireResolver = \"require-resolver\",\n ExecuteResolveCalls = \"execute-resolve-calls\",\n}\n\n/**\n * Encodes the set of well-known steps in the ENS Reverse Resolution protocol.\n */\nexport enum ReverseResolutionProtocolStep {\n Operation = \"reverse-resolution\",\n ResolveReverseName = \"resolve-reverse-name\",\n NameRecordExists = \"name-record-exists-check\",\n ForwardResolveAddressRecord = \"forward-resolve-address-record\",\n VerifyResolvedAddressMatchesAddress = \"verify-resolved-address-matches-address\",\n}\n\nexport const PROTOCOL_ATTRIBUTE_PREFIX = \"ens\";\nexport const ATTR_PROTOCOL_NAME = `${PROTOCOL_ATTRIBUTE_PREFIX}.protocol`;\nexport const ATTR_PROTOCOL_STEP = `${PROTOCOL_ATTRIBUTE_PREFIX}.protocol.step`;\nexport const ATTR_PROTOCOL_STEP_RESULT = `${PROTOCOL_ATTRIBUTE_PREFIX}.protocol.step.result`;\n\ninterface SpanAttributes {\n [key: string]: unknown;\n}\n\ninterface SpanEvent {\n name: string;\n attributes: SpanAttributes;\n time: number;\n}\n\nexport interface ProtocolSpan {\n scope: string;\n id: string;\n traceId: string;\n parentSpanContext:\n | {\n traceId: string;\n spanId: string;\n }\n | undefined;\n name: string;\n timestamp: number;\n duration: number;\n attributes: SpanAttributes;\n status: { code: number; message?: string };\n events: SpanEvent[];\n}\n\nexport type ProtocolSpanTreeNode = ProtocolSpan & { children: ProtocolSpanTreeNode[] };\nexport type ProtocolTrace = ProtocolSpanTreeNode[];\n","import { prettifyError } from \"zod/v4\";\nimport { ErrorResponse } from \"./types\";\nimport { ErrorResponseSchema } from \"./zod-schemas\";\n\nexport function deserializeErrorResponse(maybeErrorResponse: unknown): ErrorResponse {\n const parsed = ErrorResponseSchema.safeParse(maybeErrorResponse);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ErrorResponse:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n","import z from \"zod/v4\";\n\nexport const ErrorResponseSchema = z.object({\n message: z.string(),\n details: z.optional(z.unknown()),\n});\n","import type { ENSIndexerOverallIndexingStatus, ENSIndexerPublicConfig } from \"../ensindexer\";\nimport type {\n ForwardResolutionArgs,\n MultichainPrimaryNameResolutionArgs,\n MultichainPrimaryNameResolutionResult,\n ResolverRecordsResponse,\n ResolverRecordsSelection,\n ReverseResolutionArgs,\n ReverseResolutionResult,\n} from \"../resolution\";\nimport type { Duration } from \"../shared\";\nimport type { ProtocolTrace } from \"../tracing\";\n\n/**\n * API Error Response Type\n */\nexport interface ErrorResponse {\n message: string;\n details?: unknown; // subject to change\n}\n\nexport interface TraceableRequest {\n trace?: boolean;\n}\n\nexport interface TraceableResponse {\n trace?: ProtocolTrace;\n}\n\nexport interface AcceleratableRequest {\n accelerate?: boolean;\n}\n\nexport interface AcceleratableResponse {\n accelerationAttempted: boolean;\n}\n\n/**\n * Resolve Records Request Type\n */\nexport interface ResolveRecordsRequest<SELECTION extends ResolverRecordsSelection>\n extends ForwardResolutionArgs<SELECTION>,\n AcceleratableRequest,\n TraceableRequest {}\n\n/**\n * Resolve Records Response Type\n */\nexport interface ResolveRecordsResponse<SELECTION extends ResolverRecordsSelection>\n extends AcceleratableResponse,\n TraceableResponse {\n records: ResolverRecordsResponse<SELECTION>;\n}\n\n/**\n * Resolve Primary Name Request Type\n */\nexport interface ResolvePrimaryNameRequest\n extends ReverseResolutionArgs,\n AcceleratableRequest,\n TraceableRequest {}\n\n/**\n * Resolve Primary Name Response Type\n */\nexport interface ResolvePrimaryNameResponse extends AcceleratableResponse, TraceableResponse {\n name: ReverseResolutionResult;\n}\n\nexport interface ResolvePrimaryNamesRequest\n extends MultichainPrimaryNameResolutionArgs,\n AcceleratableRequest,\n TraceableRequest {}\n\nexport interface ResolvePrimaryNamesResponse extends AcceleratableResponse, TraceableResponse {\n names: MultichainPrimaryNameResolutionResult;\n}\n\n/**\n * ENSIndexer Public Config Response\n */\nexport type ConfigResponse = ENSIndexerPublicConfig;\n\n/**\n * ENSIndexer Overall Indexing Status Request\n */\nexport interface IndexingStatusRequest {\n /**\n * Max Realtime Distance (optional)\n *\n * A duration value in seconds, representing the max allowed distance\n * between the latest indexed block of each chain and the “tip” of\n * all indexed chains. Setting this parameter influences the HTTP response\n * code as follows:\n * - Success (200 OK): The latest indexed block of each chain\n * is within the requested distance from realtime.\n * - Service Unavailable (503): The latest indexed block of each chain\n * is NOT within the requested distance from realtime.\n */\n maxRealtimeDistance?: Duration;\n}\n\n/**\n * ENSIndexer Overall Indexing Status Response\n */\nexport type IndexingStatusResponse = ENSIndexerOverallIndexingStatus;\n\n/**\n * ENSIndexer Overall Indexing Status Response Codes\n *\n * Define a custom response code for known responses.\n */\nexport const IndexingStatusResponseCodes = {\n IndexerError: 512,\n RequestedDistanceNotAchievedError: 513,\n} as const;\n","import { ErrorResponse } from \"./api\";\n\nexport class ClientError extends Error {\n details?: unknown;\n\n constructor(message: string, details?: unknown) {\n super(message);\n this.name = \"ClientError\";\n this.details = details;\n }\n\n static fromErrorResponse({ message, details }: ErrorResponse) {\n return new ClientError(message, details);\n }\n}\n","import { deserializeErrorResponse } from \"./api\";\nimport {\n type ConfigResponse,\n type ErrorResponse,\n type IndexingStatusRequest,\n type IndexingStatusResponse,\n IndexingStatusResponseCodes,\n type ResolvePrimaryNameRequest,\n type ResolvePrimaryNameResponse,\n type ResolvePrimaryNamesRequest,\n type ResolvePrimaryNamesResponse,\n type ResolveRecordsRequest,\n type ResolveRecordsResponse,\n} from \"./api/types\";\nimport { ClientError } from \"./client-error\";\nimport {\n type SerializedENSIndexerOverallIndexingStatus,\n type SerializedENSIndexerPublicConfig,\n deserializeENSIndexerIndexingStatus,\n deserializeENSIndexerPublicConfig,\n} from \"./ensindexer\";\nimport { ResolverRecordsSelection } from \"./resolution\";\n\n/**\n * Default ENSNode API endpoint URL\n */\nexport const DEFAULT_ENSNODE_API_URL = \"https://api.alpha.ensnode.io\" as const;\n\n/**\n * Configuration options for ENSNode API client\n */\nexport interface ClientOptions {\n /** The ENSNode API URL */\n url: URL;\n}\n\n/**\n * ENSNode API Client\n *\n * Provides access to the following ENSNode APIs:\n * - Resolution API\n * - 🚧 Configuration API\n * - 🚧 Indexing Status API\n *\n * @example\n * ```typescript\n * // Create client with default options\n * const client = new ENSNodeClient();\n *\n * // Use resolution methods\n * const { records } = await client.resolveRecords(\"jesse.base.eth\", {\n * addresses: [60],\n * texts: [\"avatar\"]\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Custom configuration\n * const client = new ENSNodeClient({\n * url: new URL(\"https://my-ensnode-instance.com\"),\n * });\n * ```\n */\nexport class ENSNodeClient {\n private readonly options: ClientOptions;\n\n static defaultOptions(): ClientOptions {\n return {\n url: new URL(DEFAULT_ENSNODE_API_URL),\n };\n }\n\n constructor(options: Partial<ClientOptions> = {}) {\n this.options = {\n ...ENSNodeClient.defaultOptions(),\n ...options,\n };\n }\n\n getOptions(): Readonly<ClientOptions> {\n return Object.freeze({\n url: new URL(this.options.url.href),\n });\n }\n\n /**\n * Resolves records for an ENS name (Forward Resolution).\n *\n * @param name The ENS Name whose records to resolve\n * @param selection selection of Resolver records\n * @param options additional options\n * @param options.accelerate whether to attempt Protocol Acceleration (default false)\n * @param options.trace whether to include a trace in the response (default false)\n * @returns ResolveRecordsResponse<SELECTION>\n * @throws If the request fails or the ENSNode API returns an error response\n *\n * @example\n * ```typescript\n * const { records } = await client.resolveRecords(\"jesse.base.eth\", {\n * addresses: [60],\n * texts: [\"avatar\", \"com.twitter\"]\n * });\n *\n * console.log(records);\n * // {\n * // addresses: {\n * // 60: \"0xabcd...\"\n * // },\n * // texts: {\n * // avatar: \"https://example.com/image.jpg\",\n * // \"com.twitter\": null, // if not set, for example\n * // }\n * // }\n * ```\n */\n async resolveRecords<SELECTION extends ResolverRecordsSelection>(\n name: ResolveRecordsRequest<SELECTION>[\"name\"],\n selection: ResolveRecordsRequest<SELECTION>[\"selection\"],\n options?: Omit<ResolveRecordsRequest<SELECTION>, \"name\" | \"selection\">,\n ): Promise<ResolveRecordsResponse<SELECTION>> {\n const url = new URL(`/api/resolve/records/${encodeURIComponent(name)}`, this.options.url);\n\n // Add query parameters based on selection\n if (selection.name) {\n url.searchParams.set(\"name\", \"true\");\n }\n\n if (selection.addresses && selection.addresses.length > 0) {\n url.searchParams.set(\"addresses\", selection.addresses.join(\",\"));\n }\n\n if (selection.texts && selection.texts.length > 0) {\n url.searchParams.set(\"texts\", selection.texts.join(\",\"));\n }\n\n if (options?.trace) url.searchParams.set(\"trace\", \"true\");\n if (options?.accelerate) url.searchParams.set(\"accelerate\", \"true\");\n\n const response = await fetch(url);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw ClientError.fromErrorResponse(error);\n }\n\n const data = await response.json();\n return data as ResolveRecordsResponse<SELECTION>;\n }\n\n /**\n * Resolves the primary name of a specified address (Reverse Resolution) on a specific chain.\n *\n * If the `address` specifies a valid [ENSIP-19 Default Name](https://docs.ens.domains/ensip/19/#default-primary-name),\n * the Default Name will be returned. You _may_ query the Default EVM Chain Id (`0`) in order to\n * determine the `address`'s Default Name directly.\n *\n * @param address The Address whose Primary Name to resolve\n * @param chainId The chain id within which to query the address' ENSIP-19 Multichain Primary Name\n * @param options additional options\n * @param options.accelerate whether to attempt Protocol Acceleration (default false)\n * @param options.trace whether to include a trace in the response (default false)\n * @returns ResolvePrimaryNameResponse\n * @throws If the request fails or the ENSNode API returns an error response\n *\n * @example\n * ```typescript\n * // Resolve the address' Primary Name on Ethereum Mainnet\n * const { name } = await client.resolvePrimaryName(\"0x179A862703a4adfb29896552DF9e307980D19285\", 1);\n * // name === 'gregskril.eth'\n *\n * // Resolve the address' Primary Name on Base\n * const { name } = await client.resolvePrimaryName(\"0x179A862703a4adfb29896552DF9e307980D19285\", 8453);\n * // name === 'greg.base.eth'\n *\n * // Resolve the address' Default Primary Name\n * const { name } = await client.resolvePrimaryName(\"0x179A862703a4adfb29896552DF9e307980D19285\", 0);\n * // name === 'gregskril.eth'\n * ```\n */\n async resolvePrimaryName(\n address: ResolvePrimaryNameRequest[\"address\"],\n chainId: ResolvePrimaryNameRequest[\"chainId\"],\n options?: Omit<ResolvePrimaryNameRequest, \"address\" | \"chainId\">,\n ): Promise<ResolvePrimaryNameResponse> {\n const url = new URL(`/api/resolve/primary-name/${address}/${chainId}`, this.options.url);\n\n if (options?.trace) url.searchParams.set(\"trace\", \"true\");\n if (options?.accelerate) url.searchParams.set(\"accelerate\", \"true\");\n\n const response = await fetch(url);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw ClientError.fromErrorResponse(error);\n }\n\n const data = await response.json();\n return data as ResolvePrimaryNameResponse;\n }\n\n /**\n * Resolves the primary names of a specified address across multiple chains.\n *\n * If the `address` specifies a valid [ENSIP-19 Default Name](https://docs.ens.domains/ensip/19/#default-primary-name),\n * the Default Name will be returned for all chainIds for which there is not a chain-specific\n * Primary Name. To avoid misuse, you _may not_ query the Default EVM Chain Id (`0`) directly, and\n * should rely on the aforementioned per-chain defaulting behavior.\n *\n * @param address The Address whose Primary Names to resolve\n * @param options additional options\n * @param options.chainIds The set of chain ids within which to query the address' ENSIP-19\n * Multichain Primary Name (default: all ENSIP-19 supported chains)\n * @param options.accelerate whether to attempt Protocol Acceleration (default: true)\n * @param options.trace whether to include a trace in the response (default: false)\n * @returns ResolvePrimaryNamesResponse\n * @throws If the request fails or the ENSNode API returns an error response\n *\n * @example\n * ```typescript\n * // Resolve the address' Primary Names on all ENSIP-19 supported chain ids\n * const { names } = await client.resolvePrimaryNames(\"0x179A862703a4adfb29896552DF9e307980D19285\");\n *\n * console.log(names);\n * // {\n * // \"1\": \"gregskril.eth\",\n * // \"10\": \"gregskril.eth\",\n * // \"8453\": \"greg.base.eth\", // base-specific Primary Name!\n * // \"42161\": \"gregskril.eth\",\n * // \"59144\": \"gregskril.eth\",\n * // \"534352\": \"gregskril.eth\"\n * // }\n *\n * // Resolve the address' Primary Names on specific chain Ids\n * const { names } = await client.resolvePrimaryNames(\"0xabcd...\", [1, 8453]);\n *\n * console.log(names);\n * // {\n * // \"1\": \"gregskril.eth\",\n * // \"8453\": \"greg.base.eth\", // base-specific Primary Name!\n * // }\n * ```\n */\n async resolvePrimaryNames(\n address: ResolvePrimaryNamesRequest[\"address\"],\n options?: Omit<ResolvePrimaryNamesRequest, \"address\">,\n ): Promise<ResolvePrimaryNamesResponse> {\n const url = new URL(`/api/resolve/primary-names/${address}`, this.options.url);\n\n if (options?.chainIds) url.searchParams.set(\"chainIds\", options.chainIds.join(\",\"));\n if (options?.trace) url.searchParams.set(\"trace\", \"true\");\n if (options?.accelerate) url.searchParams.set(\"accelerate\", \"true\");\n\n const response = await fetch(url);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw ClientError.fromErrorResponse(error);\n }\n\n const data = await response.json();\n return data as ResolvePrimaryNamesResponse;\n }\n\n /**\n * Fetch ENSNode Config\n *\n * Fetch the ENSNode's configuration.\n *\n * @returns {ConfigResponse}\n *\n * @throws if the ENSNode request fails\n * @throws if the ENSNode API returns an error response\n * @throws if the ENSNode response breaks required invariants\n */\n async config(): Promise<ConfigResponse> {\n const url = new URL(`/api/config`, this.options.url);\n\n const response = await fetch(url);\n\n let responseData: unknown;\n\n // ENSNode API should always allow parsing a response as JSON object.\n // If for some reason it's not the case, throw an error.\n try {\n responseData = await response.json();\n } catch {\n throw new Error(\"Malformed response data: invalid JSON\");\n }\n\n if (!response.ok) {\n const errorResponse = deserializeErrorResponse(responseData);\n throw new Error(`Fetching ENSNode Config Failed: ${errorResponse.message}`);\n }\n\n return deserializeENSIndexerPublicConfig(responseData as SerializedENSIndexerPublicConfig);\n }\n\n /**\n * Fetch ENSNode Indexing Status\n *\n * Fetch the ENSNode's multichain indexing status.\n *\n * @param options additional options\n * @param options.maxRealtimeDistance the max allowed distance between the\n * latest indexed block of each chain and the \"tip\" of all indexed chains.\n * Setting this parameter influences the HTTP response code as follows:\n * - Success (200 OK): The latest indexed block of each chain is within the\n * requested distance from realtime.\n * - Service Unavailable (503): The latest indexed block of each chain is NOT\n * within the requested distance from realtime.\n *\n * @returns {IndexingStatusResponse}\n *\n * @throws if the ENSNode request fails\n * @throws if the ENSNode API returns an error response\n * @throws if the ENSNode response breaks required invariants\n */\n async indexingStatus(options?: IndexingStatusRequest): Promise<IndexingStatusResponse> {\n const url = new URL(`/api/indexing-status`, this.options.url);\n\n if (typeof options?.maxRealtimeDistance !== \"undefined\") {\n url.searchParams.set(\"maxRealtimeDistance\", `${options.maxRealtimeDistance}`);\n }\n\n const response = await fetch(url);\n\n let responseData: unknown;\n\n // ENSNode API should always allow parsing a response as JSON object.\n // If for some reason it's not the case, throw an error.\n try {\n responseData = await response.json();\n } catch {\n throw new Error(\"Malformed response data: invalid JSON\");\n }\n\n // handle application errors accordingly\n if (!response.ok) {\n switch (response.status) {\n case IndexingStatusResponseCodes.IndexerError: {\n console.error(\"Indexing Status API: indexer error\");\n return deserializeENSIndexerIndexingStatus(\n responseData as SerializedENSIndexerOverallIndexingStatus,\n );\n }\n\n case IndexingStatusResponseCodes.RequestedDistanceNotAchievedError: {\n console.error(\n \"Indexing Status API: Requested realtime indexing distance not achieved error\",\n );\n return deserializeENSIndexerIndexingStatus(\n responseData as SerializedENSIndexerOverallIndexingStatus,\n );\n }\n\n default: {\n const errorResponse = deserializeErrorResponse(responseData);\n throw new Error(`Fetching ENSNode Indexing Status Failed: ${errorResponse.message}`);\n }\n }\n }\n\n return deserializeENSIndexerIndexingStatus(\n responseData as SerializedENSIndexerOverallIndexingStatus,\n );\n }\n}\n","import type { CoinType } from \"../ens\";\n\n/**\n * Encodes a selection of Resolver records in the context of a specific Name.\n */\nexport interface ResolverRecordsSelection {\n /**\n * Whether to fetch the name's `name` record. This value is primarily used in the context of\n * Reverse Resolution.\n *\n * @see https://docs.ens.domains/ensip/19/#reverse-resolution\n */\n name?: boolean;\n\n /**\n * Which coinTypes to fetch address records for.\n */\n addresses?: CoinType[];\n\n /**\n * Which keys to fetch text records for.\n */\n texts?: string[];\n\n // TODO: include others as/if necessary\n}\n\nexport const isSelectionEmpty = (selection: ResolverRecordsSelection) =>\n !selection.name && !selection.addresses?.length && !selection.texts?.length;\n","import {\n DatasourceNames,\n ENSNamespaceId,\n ENSNamespaceIds,\n maybeGetDatasource,\n} from \"@ensnode/datasources\";\nimport { ETH_COIN_TYPE, evmChainIdToCoinType } from \"../ens\";\nimport { uniq } from \"../shared\";\nimport type { ResolverRecordsSelection } from \"./resolver-records-selection\";\n\nconst getENSIP19SupportedCoinTypes = (namespace: ENSNamespaceId) =>\n uniq(\n [\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverBase),\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverLinea),\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverOptimism),\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverArbitrum),\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverScroll),\n ]\n .filter((ds) => ds !== undefined)\n .map((ds) => ds.chain.id),\n ).map(evmChainIdToCoinType);\n\nconst TEXTS = [\n \"url\",\n \"avatar\",\n \"header\",\n \"description\",\n \"email\",\n \"com.twitter\",\n \"com.farcaster\",\n \"com.github\",\n] as const satisfies string[];\n\nexport const DefaultRecordsSelection = {\n [ENSNamespaceIds.Mainnet]: {\n addresses: [ETH_COIN_TYPE, ...getENSIP19SupportedCoinTypes(ENSNamespaceIds.Mainnet)],\n texts: TEXTS,\n },\n [ENSNamespaceIds.Sepolia]: {\n addresses: [ETH_COIN_TYPE, ...getENSIP19SupportedCoinTypes(ENSNamespaceIds.Sepolia)],\n texts: TEXTS,\n },\n [ENSNamespaceIds.Holesky]: {\n addresses: [ETH_COIN_TYPE, ...getENSIP19SupportedCoinTypes(ENSNamespaceIds.Holesky)],\n texts: TEXTS,\n },\n [ENSNamespaceIds.EnsTestEnv]: {\n addresses: [ETH_COIN_TYPE, ...getENSIP19SupportedCoinTypes(ENSNamespaceIds.EnsTestEnv)],\n texts: TEXTS,\n },\n} as const satisfies Record<ENSNamespaceId, ResolverRecordsSelection>;\n"],"mappings":"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","names":["prettifyError","z","PluginName","z","prettifyError","isSubgraphCompatible","prettifyError","z","z","prettifyError","TraceableENSProtocol","ForwardResolutionProtocolStep","ReverseResolutionProtocolStep","prettifyError","z","prettifyError","ENSNamespaceIds","ENSNamespaceIds"]}
1
+ {"version":3,"sources":["../src/ens/constants.ts","../src/ens/subname-helpers.ts","../src/ens/coin-type.ts","../src/ens/reverse-name.ts","../src/ens/names.ts","../src/ens/types.ts","../src/ens/parse-reverse-name.ts","../src/ens/is-normalized.ts","../src/ens/encode-labelhash.ts","../src/ensindexer/config/deserialize.ts","../src/ensindexer/config/zod-schemas.ts","../src/shared/cache.ts","../src/shared/collections.ts","../src/shared/serialize.ts","../src/shared/deserialize.ts","../src/shared/zod-schemas.ts","../src/shared/account-id.ts","../src/shared/interpretation.ts","../src/ensindexer/config/types.ts","../src/ensindexer/config/helpers.ts","../src/ensindexer/config/serialize.ts","../src/ensindexer/config/labelset-utils.ts","../src/ensindexer/config/label-utils.ts","../src/ensindexer/config/parsing.ts","../src/ensindexer/indexing-status/deserialize.ts","../src/ensindexer/indexing-status/zod-schemas.ts","../src/shared/block-ref.ts","../src/ensindexer/indexing-status/types.ts","../src/ensindexer/indexing-status/helpers.ts","../src/ensindexer/indexing-status/serialize.ts","../src/tracing/index.ts","../src/api/helpers.ts","../src/api/zod-schemas.ts","../src/api/types.ts","../src/client-error.ts","../src/client.ts","../src/resolution/resolver-records-selection.ts","../src/resolution/default-records-selection.ts"],"sourcesContent":["import { namehash } from \"viem\";\n\nimport type { Node } from \"./types\";\n\nexport const ROOT_NODE: Node = namehash(\"\");\nexport const ETH_NODE = namehash(\"eth\");\nexport const BASENAMES_NODE = namehash(\"base.eth\");\nexport const LINEANAMES_NODE = namehash(\"linea.eth\");\n\n/**\n * A set of nodes whose children are used for reverse resolution.\n *\n * Useful for identifying if a domain is used for reverse resolution.\n * See apps/ensindexer/src/handlers/Registry.ts for context.\n */\nexport const REVERSE_ROOT_NODES: Set<Node> = new Set([namehash(\"addr.reverse\")]);\n","import { Address, Hex, concat, isAddress, isHash, keccak256, toHex } from \"viem\";\n\nimport { labelhash } from \"viem/ens\";\nimport { addrReverseLabel } from \"./reverse-name\";\nimport type { Label, LabelHash, Node } from \"./types\";\n\n/**\n * Implements one step of the namehash algorithm, combining `labelHash` with `node` to produce\n * the `node` of a given subdomain. Note that the order of the arguments is 'reversed' (as compared to\n * the actual concatenation) in order to improve readability (i.e. read as [labelHash].[node]).\n */\nexport const makeSubdomainNode = (labelHash: LabelHash, node: Node): Node =>\n keccak256(concat([node, labelHash]));\n\n/**\n * Attempt to heal the labelHash of an addr.reverse subname using an address that might be related to the subname.\n *\n * @throws if maybeReverseAddress is not a valid Address\n * @throws if labelHash is not a valid Labelhash\n *\n * @returns the original label if healed, otherwise null\n */\nexport const maybeHealLabelByReverseAddress = ({\n maybeReverseAddress,\n labelHash,\n}: {\n /** The address that is possibly associated with the addr.reverse subname */\n maybeReverseAddress: Address;\n\n /** The labelhash of the addr.reverse subname */\n labelHash: LabelHash;\n}): string | null => {\n // check if required arguments are valid\n if (!isAddress(maybeReverseAddress)) {\n throw new Error(\n `Invalid reverse address: '${maybeReverseAddress}'. Must be a valid EVM Address.`,\n );\n }\n\n if (!isHash(labelHash)) {\n throw new Error(\n `Invalid labelHash: '${labelHash}'. Must start with '0x' and represent 32 bytes.`,\n );\n }\n\n // derive the assumed label from the normalized address\n const assumedLabel = addrReverseLabel(maybeReverseAddress);\n\n // if labelHash of the assumed label matches the provided labelHash, heal\n if (labelhash(assumedLabel) === labelHash) return assumedLabel;\n\n // otherwise, healing did not succeed\n // TODO: log the event args for analysis and debugging\n return null;\n};\n\n/**\n * Encodes a uint256 bigint as hex string sized to 32 bytes.\n * Uses include, in the context of ENS, decoding the uint256-encoded tokenId of NFT-issuing contracts\n * into Node or LabelHash, which is a common behavior in the ENS ecosystem.\n * (see NameWrapper, ETHRegistrarController)\n */\nexport const uint256ToHex32 = (num: bigint): Hex => toHex(num, { size: 32 });\n\n/**\n * These characters are prohibited in normalized ENS names per the ENSIP-15\n * standard (https://docs.ens.domains/ensip/15). Names containing labels with\n * one or more of these characters are unusable by any app implementing\n * ENSIP-15 (e.g., via https://github.com/adraffy/ens-normalize.js\n * or https://github.com/namehash/ens-normalize-python).\n *\n * While many other characters (beyond these 4) are not supported by\n * ENSIP-15, only the following 4 characters are classified as \"unindexable\" due\n * to specific indexing concerns.\n *\n * Onchain ENS contracts do not enforce ENSIP-15 normalization for reasons\n * including the gas costs of enforcement. This allows unnormalized labels\n * containing these characters to exist onchain. Such labels must be handled\n * carefully by indexers to avoid conflicts.\n *\n * Some indexed labels are \"unknown\" (or \"unindexable\") but still require a\n * representation within indexed data. For this purpose, a special \"unknown\n * label\" format is defined (an EncodedLabelHash) that represents these labels in the format of\n * \"[{labelHash}]\" where {labelHash} is the labelHash of the unknown label.\n * When an indexed label is in this format it is necessary to distinguish an\n * \"unknown\" label containing a labelHash, from an unnormalized label literal\n * that is formatted to appear like an \"unknown\" label. For example, if the\n * unnormalized label literal\n * \"[24695ee963d29f0f52edfdea1e830d2fcfc9052d5ba70b194bddd0afbbc89765]\"\n * is indexed, it will be considered \"unindexable\" (due to the square bracket\n * characters) and therefore be represented as the following \"unknown\" label instead\n * \"[80968d00b78a91f47b233eaa213576293d16dadcbbdceb257bca94b08451ba7f]\"\n * which encodes the labelHash of the unnormalized label literal in\n * square brackets.\n */\nconst UNINDEXABLE_LABEL_CHARACTERS = [\n \"\\0\", // null byte: PostgreSQL does not allow storing this character in text fields.\n \".\", // conflicts with ENS label separator logic.\n \"[\", // conflicts with \"unknown label\" representations.\n \"]\", // conflicts with \"unknown label\" representations.\n];\n\nconst UNINDEXABLE_LABEL_CHARACTER_CODES = new Set(\n UNINDEXABLE_LABEL_CHARACTERS.map((char) => char.charCodeAt(0)),\n);\n\n/**\n * Check if any characters in `label` are \"unindexable\".\n *\n * Related logic in ENS Subgraph:\n * https://github.com/ensdomains/ens-subgraph/blob/c844791/src/utils.ts#L68\n *\n * @param label - The label to check. Note:\n * A `null` value for `label` represents an unhealable labelhash.\n *\n * @returns `true` if the label is indexable, `false` otherwise.\n */\nexport const isLabelIndexable = (label: Label | null): label is Label => {\n if (!label) return false;\n\n for (let i = 0; i < label.length; i++) {\n if (UNINDEXABLE_LABEL_CHARACTER_CODES.has(label.charCodeAt(i))) return false;\n }\n\n return true;\n};\n","import type { CoinType, EvmCoinType } from \"@ensdomains/address-encoder\";\nimport {\n coinTypeToEvmChainId as _coinTypeToEvmChainId,\n evmChainIdToCoinType as _evmChainIdToCoinType,\n} from \"@ensdomains/address-encoder/utils\";\nimport { ChainId } from \"../shared\";\n\n// re-export CoinType and EvmCoinType from @ensdomains/address-encoder\n// so consumers don't need it as a dependency\nexport type { CoinType, EvmCoinType } from \"@ensdomains/address-encoder\";\n\n/**\n * The ETH coinType.\n *\n * @see https://docs.ens.domains/ensip/9\n */\nexport const ETH_COIN_TYPE: CoinType = 60;\n\n/**\n * The 'default' chainId corresponding to the below {@link DEFAULT_EVM_COIN_TYPE} in the context of\n * ENSIP-19.\n *\n * @see https://docs.ens.domains/ensip/19\n */\nexport const DEFAULT_EVM_CHAIN_ID: ChainId = 0;\n\n/**\n * ENSIP-19 EVM CoinType representing the 'default' coinType for EVM chains in ENS.\n *\n * @see https://docs.ens.domains/ensip/19/#reverse-resolution\n */\nexport const DEFAULT_EVM_COIN_TYPE = 0x8000_0000 as EvmCoinType;\n\n/**\n * Converts a CoinType to an EVM Chain Id.\n *\n * NOTE: for whatever reason @ensdomains/address-encoder#coinTypeToEvmChainId doesn't handle the\n * mainnet case so we implement that here\n *\n * @see https://docs.ens.domains/ensip/11/\n */\nexport const coinTypeToEvmChainId = (coinType: CoinType): ChainId => {\n if (coinType === ETH_COIN_TYPE) return 1;\n return _coinTypeToEvmChainId(coinType);\n};\n\n/**\n * Converts an EVM Chain Id to a CoinType.\n *\n * NOTE: for whatever reason @ensdomains/address-encoder#evmChainIdToCoinType doesn't handle the\n * mainnet case so we implement that here\n */\nexport const evmChainIdToCoinType = (chainId: ChainId): CoinType => {\n if (chainId === 1) return ETH_COIN_TYPE;\n return _evmChainIdToCoinType(chainId);\n};\n\n/**\n * Converts a bigint value representing a CoinType into a valid CoinType.\n *\n * This is useful when onchain events emit coinTypes as bigint but we want to constrain them to\n * the CoinType type.\n *\n * @throws if `value` is too large to fit in Number.MAX_SAFE_INTEGER\n */\nexport const bigintToCoinType = (value: bigint): CoinType => {\n if (value > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new Error(`'${value}' cannot represent as CoinType, it is too large.`);\n }\n\n return Number(value) as CoinType;\n};\n","import { Address } from \"viem\";\n\nimport { CoinType, DEFAULT_EVM_COIN_TYPE, ETH_COIN_TYPE } from \"./coin-type\";\nimport type { Label, Name } from \"./types\";\n\n/**\n * Gets the Label used for the reverse names of subnames as per ENSIP-11 & ENSIP-19.\n *\n * @see https://docs.ens.domains/ensip/19/#reverse-resolution\n */\nexport const addrReverseLabel = (address: Address): Label => address.slice(2).toLowerCase();\n\n/**\n * Converts `coinType` to prefix-free hex string.\n *\n * @see https://docs.ens.domains/ensip/19\n */\nexport const coinTypeReverseLabel = (coinType: CoinType): Label => coinType.toString(16);\n\n/**\n * Gets the reverse name for an address according to ENSIP-11 & ENSIP-19.\n *\n * @see https://docs.ens.domains/ensip/11#specification\n * @see https://docs.ens.domains/ensip/19#specification\n *\n * @param address - The address to get the reverse name for\n * @param coinType - The coin type to use for the reverse name\n * @returns The reverse name for the address\n *\n * @example\n * ```ts\n * reverseName(\"0x1234\", BigInt(ETH_COIN_TYPE)) // \"1234.addr.reverse\"\n * reverseName(\"0x1234\", BigInt(0x80000000)) // \"1234.default.reverse\"\n * reverseName(\"0x1234\", BigInt(0x5678)) // \"1234.5678.reverse\"\n * ```\n */\nexport function reverseName(address: Address, coinType: CoinType): Name {\n const label = addrReverseLabel(address);\n\n const middle = (() => {\n switch (coinType) {\n case ETH_COIN_TYPE:\n return \"addr\";\n case DEFAULT_EVM_COIN_TYPE:\n return \"default\";\n default:\n return coinTypeReverseLabel(coinType);\n }\n })();\n\n return `${label}.${middle}.reverse`;\n}\n","import type { Name } from \"./types\";\n\n/**\n * Constructs a name hierarchy from a given Name.\n * i.e. sub.example.eth -> [sub.example.eth, example.eth, eth]\n */\nexport const getNameHierarchy = (name: Name): Name[] =>\n name.split(\".\").map((_, i, labels) => labels.slice(i).join(\".\"));\n","import type { Hex } from \"viem\";\n\n// re-export ENSNamespaceIds and ENSNamespaceId from @ensnode/datasources\n// so consumers don't need it as a dependency\nexport { ENSNamespaceIds } from \"@ensnode/datasources\";\nexport type { ENSNamespaceId } from \"@ensnode/datasources\";\n\n/**\n * A hash value that uniquely identifies a single ENS name.\n * Result of `namehash` function as specified in ENSIP-1.\n *\n * @example\n * ```\n * namehash(\"vitalik.eth\") === \"0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835\"\n * ```\n * @link https://docs.ens.domains/ensip/1#namehash-algorithm\n */\nexport type Node = Hex;\n\n/**\n * A Name represents a human-readable ENS name.\n *\n * ex: vitalik.eth\n */\nexport type Name = string;\n\n/**\n * A LabelHash is the result of the labelhash function (which is just keccak256) on a Label.\n *\n * @link https://docs.ens.domains/terminology#labelhash\n */\nexport type LabelHash = Hex;\n\n/**\n * A Label is a single part of an ENS Name.\n *\n * @link https://docs.ens.domains/terminology#label\n */\nexport type Label = string;\n\n/**\n * An EncodedLabelHash is a specially formatted unnormalized Label that should be interpreted as a\n * LabelHash literal, particularly for use within an ENS Name.\n *\n * @example [abcd]\n * @example [abcd].example.eth\n */\nexport type EncodedLabelHash = `[${string}]`;\n","import { Address, getAddress, hexToBigInt } from \"viem\";\nimport { CoinType, DEFAULT_EVM_COIN_TYPE, ETH_COIN_TYPE, bigintToCoinType } from \"./coin-type\";\nimport { Label, Name } from \"./types\";\n\n/**\n * Matches an ENSIP-19 Reverse Name\n *\n * @see https://github.com/ensdomains/ens-contracts/blob/20e34971fd55f9e3b3cf4a5825d52e1504d36493/contracts/utils/ENSIP19.sol#L70\n */\nconst REVERSE_NAME_REGEX = /^([0-9a-fA-F]+)\\.([0-9a-f]{1,64}|addr|default)\\.reverse$/;\n\n/**\n * Parses an address label (hex sans prefix) into an Address.\n *\n * @throws if address is invalid\n */\nconst parseAddressLabel = (addressLabel: Label): Address => getAddress(`0x${addressLabel}`);\n\n/**\n * Parses a coinType label (hex sans prefix) into an EVMCoinType.\n *\n * @throws if coinType is invalid\n */\nconst parseCoinTypeLabel = (coinTypeLabel: Label): CoinType => {\n if (coinTypeLabel === \"default\") return DEFAULT_EVM_COIN_TYPE;\n if (coinTypeLabel === \"addr\") return ETH_COIN_TYPE;\n\n return bigintToCoinType(hexToBigInt(`0x${coinTypeLabel}`));\n};\n\n/**\n * Parse the address and coinType out of an ENSIP-19 reverse name.\n */\nexport function parseReverseName(name: Name): { address: Address; coinType: CoinType } | null {\n const match = name.match(REVERSE_NAME_REGEX);\n if (!match) return null;\n\n try {\n const [, addressLabel, coinTypeLabel] = match;\n if (!addressLabel) return null;\n if (!coinTypeLabel) return null;\n\n return {\n address: parseAddressLabel(addressLabel),\n coinType: parseCoinTypeLabel(coinTypeLabel),\n };\n } catch {\n // either of the parse methods threw, unable to parse reverse name\n return null;\n }\n}\n","import { normalize } from \"viem/ens\";\n\nimport type { Label, Name } from \"./types\";\n\n/**\n * Determines whether the Name is normalized.\n *\n * @param name - The Name to check for normalization\n * @returns True if the name is normalized according to ENS normalization rules, false otherwise\n */\nexport function isNormalizedName(name: Name): boolean {\n try {\n return name === normalize(name);\n } catch {\n return false;\n }\n}\n\n/**\n * Determines whether the Label is normalized.\n *\n * @param label - The Label to check for normalization\n * @returns True if the label is normalized according to ENS normalization rules, false otherwise\n */\nexport function isNormalizedLabel(label: Label): boolean {\n // empty string is not a normalized label\n if (label === \"\") return false;\n\n // normalized labels do not contain periods\n if (label.includes(\".\")) return false;\n\n try {\n return label === normalize(label);\n } catch {\n return false;\n }\n}\n","import type { EncodedLabelHash, LabelHash } from \"./types\";\n\n/**\n * Formats a LabelHash as an Encoded LabelHash.\n *\n * @see https://ensnode.io/docs/reference/terminology#encoded-labelhash\n *\n * @param labelHash - A 32-byte hash string starting with '0x'\n * @returns The encoded label hash in format `[hash_without_0x_prefix]`\n */\nexport const encodeLabelHash = (labelHash: LabelHash): EncodedLabelHash =>\n `[${labelHash.slice(2)}]`;\n","import { prettifyError } from \"zod/v4\";\nimport type { SerializedENSIndexerPublicConfig } from \"./serialized-types\";\nimport type { ENSIndexerPublicConfig } from \"./types\";\nimport { makeENSIndexerPublicConfigSchema } from \"./zod-schemas\";\n\n/**\n * Serialize a {@link ENSIndexerPublicConfig} object.\n */\nexport function deserializeENSIndexerPublicConfig(\n maybeConfig: SerializedENSIndexerPublicConfig,\n valueLabel?: string,\n): ENSIndexerPublicConfig {\n const schema = makeENSIndexerPublicConfigSchema(valueLabel);\n const parsed = schema.safeParse(maybeConfig);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ENSIndexerPublicConfig:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n","/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport z from \"zod/v4\";\nimport { uniq } from \"../../shared\";\nimport {\n ZodCheckFnInput,\n makeChainIdSchema,\n makeENSNamespaceIdSchema,\n makeNonNegativeIntegerSchema,\n makePositiveIntegerSchema,\n makeUrlSchema,\n} from \"../../shared/zod-schemas\";\nimport { isSubgraphCompatible } from \"./helpers\";\nimport { PluginName } from \"./types\";\nimport type { ENSIndexerPublicConfig } from \"./types\";\n\n/**\n * Makes a schema for parsing {@link IndexedChainIds}.\n */\nexport const makeIndexedChainIdsSchema = (valueLabel: string = \"Indexed Chain IDs\") =>\n z\n .array(makeChainIdSchema(valueLabel), {\n error: `${valueLabel} must be an array.`,\n })\n .min(1, { error: `${valueLabel} list must include at least one element.` })\n .transform((v) => new Set(v));\n\n/**\n * Makes a schema for parsing a list of {@link PluginName} items.\n *\n * The list is guaranteed to include at least one item exists, and no duplicates.\n */\nexport const makePluginsListSchema = (valueLabel: string = \"Plugins\") =>\n z\n .array(\n z.enum(PluginName, {\n error: `${valueLabel} must be a list with at least one valid plugin name. Valid plugins are: ${Object.values(\n PluginName,\n ).join(\", \")}`,\n }),\n )\n .min(1, {\n error: `${valueLabel} must be a list with at least one valid plugin name. Valid plugins are: ${Object.values(\n PluginName,\n ).join(\", \")}`,\n })\n .refine((arr) => arr.length === uniq(arr).length, {\n error: `${valueLabel} cannot contain duplicate values.`,\n });\n\n/**\n * Makes a schema for parsing a name for a database schema.\n *\n * The name is guaranteed to be a non-empty string.\n */\nexport const makeDatabaseSchemaNameSchema = (valueLabel: string = \"Database schema name\") =>\n z\n .string({ error: `${valueLabel} must be a string` })\n .trim()\n .nonempty({\n error: `${valueLabel} is required and must be a non-empty string.`,\n });\n\n/**\n * Makes a schema for parsing a label set ID.\n *\n * The label set ID is guaranteed to be a string between 1-50 characters\n * containing only lowercase letters (a-z) and hyphens (-).\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set ID\", \"LABEL_SET_ID\")\n */\nexport const makeLabelSetIdSchema = (valueLabel: string) => {\n return z\n .string({ error: `${valueLabel} must be a string` })\n .min(1, { error: `${valueLabel} must be 1-50 characters long` })\n .max(50, { error: `${valueLabel} must be 1-50 characters long` })\n .regex(/^[a-z-]+$/, {\n error: `${valueLabel} can only contain lowercase letters (a-z) and hyphens (-)`,\n });\n};\n\n/**\n * Makes a schema for parsing a label set version.\n *\n * The label set version is guaranteed to be a non-negative integer.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set version\", \"LABEL_SET_VERSION\")\n\n */\nexport const makeLabelSetVersionSchema = (valueLabel: string) => {\n return z.coerce\n .number({ error: `${valueLabel} must be an integer.` })\n .pipe(makeNonNegativeIntegerSchema(valueLabel));\n};\n\n/**\n * Makes a schema for parsing a label set where both label set ID and label set version are required.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set\", \"LABEL_SET\")\n */\nexport const makeFullyPinnedLabelSetSchema = (valueLabel: string = \"Label set\") => {\n let valueLabelLabelSetId = valueLabel;\n let valueLabelLabelSetVersion = valueLabel;\n if (valueLabel == \"LABEL_SET\") {\n valueLabelLabelSetId = \"LABEL_SET_ID\";\n valueLabelLabelSetVersion = \"LABEL_SET_VERSION\";\n } else {\n valueLabelLabelSetId = valueLabel + \".labelSetId\";\n valueLabelLabelSetVersion = valueLabel + \".labelSetVersion\";\n }\n return z.object({\n labelSetId: makeLabelSetIdSchema(valueLabelLabelSetId),\n labelSetVersion: makeLabelSetVersionSchema(valueLabelLabelSetVersion),\n });\n};\n\nconst makeNonEmptyStringSchema = (valueLabel: string = \"Value\") =>\n z.string().nonempty({ error: `${valueLabel} must be a non-empty string.` });\n\nexport const makeDependencyInfoSchema = (valueLabel: string = \"Value\") =>\n z.strictObject(\n {\n nodejs: makeNonEmptyStringSchema(),\n ponder: makeNonEmptyStringSchema(),\n ensRainbow: makeNonEmptyStringSchema(),\n ensRainbowSchema: makePositiveIntegerSchema(),\n },\n {\n error: `${valueLabel} must be a valid DependencyInfo object.`,\n },\n );\n\n// Invariant: ReverseResolvers plugin requires indexAdditionalResolverRecords\nexport function invariant_reverseResolversPluginNeedsResolverRecords(\n ctx: ZodCheckFnInput<Pick<ENSIndexerPublicConfig, \"plugins\" | \"indexAdditionalResolverRecords\">>,\n) {\n const { value: config } = ctx;\n\n const reverseResolversPluginActive = config.plugins.includes(PluginName.ReverseResolvers);\n\n if (reverseResolversPluginActive && !config.indexAdditionalResolverRecords) {\n ctx.issues.push({\n code: \"custom\",\n input: config,\n message: `The '${PluginName.ReverseResolvers}' plugin requires 'indexAdditionalResolverRecords' to be 'true'.`,\n });\n }\n}\n\n// Invariant: isSubgraphCompatible requires Subgraph plugin only, no extra indexing features, and subgraph label set\nexport function invariant_isSubgraphCompatibleRequirements(\n ctx: ZodCheckFnInput<\n Pick<\n ENSIndexerPublicConfig,\n | \"plugins\"\n | \"isSubgraphCompatible\"\n | \"healReverseAddresses\"\n | \"indexAdditionalResolverRecords\"\n | \"replaceUnnormalized\"\n | \"labelSet\"\n >\n >,\n) {\n const { value: config } = ctx;\n\n if (config.isSubgraphCompatible !== isSubgraphCompatible(config)) {\n const message = config.isSubgraphCompatible\n ? `'isSubgraphCompatible' requires only the '${PluginName.Subgraph}' plugin to be active, 'indexAdditionalResolverRecords', 'healReverseAddresses', and 'replaceUnnormalized' must be set to 'false', and labelSet must be {labelSetId: \"subgraph\", labelSetVersion: 0}`\n : `'indexAdditionalResolverRecords', 'healReverseAddresses', and 'replaceUnnormalized' were set to 'false', the only active plugin was the '${PluginName.Subgraph}' plugin, and labelSet was {labelSetId: \"subgraph\", labelSetVersion: 0}. The 'isSubgraphCompatible' must be set to 'true'`;\n\n ctx.issues.push({\n code: \"custom\",\n input: config,\n message,\n });\n }\n}\n\n/**\n * ENSIndexer Public Config Schema\n *\n * Makes a Zod schema definition for validating all important settings used\n * during runtime of the ENSIndexer instance.\n */\nexport const makeENSIndexerPublicConfigSchema = (valueLabel: string = \"ENSIndexerPublicConfig\") =>\n z\n .object({\n ensAdminUrl: makeUrlSchema(`${valueLabel}.ensAdminUrl`),\n ensNodePublicUrl: makeUrlSchema(`${valueLabel}.ensNodePublicUrl`),\n labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`),\n healReverseAddresses: z.boolean({ error: `${valueLabel}.healReverseAddresses` }),\n indexAdditionalResolverRecords: z.boolean({\n error: `${valueLabel}.indexAdditionalResolverRecords`,\n }),\n replaceUnnormalized: z.boolean({ error: `${valueLabel}.replaceUnnormalized` }),\n indexedChainIds: makeIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),\n isSubgraphCompatible: z.boolean({ error: `${valueLabel}.isSubgraphCompatible` }),\n namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),\n plugins: makePluginsListSchema(`${valueLabel}.plugins`),\n databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),\n dependencyInfo: makeDependencyInfoSchema(`${valueLabel}.dependencyInfo`),\n })\n /**\n * Validations\n *\n * All required data validations must be performed below.\n */\n .check(invariant_reverseResolversPluginNeedsResolverRecords)\n .check(invariant_isSubgraphCompatibleRequirements);\n","/**\n * Cache that maps from string -> ValueType.\n */\nexport interface Cache<KeyType extends string, ValueType> {\n /**\n * Store a value in the cache with the given key.\n *\n * @param key Cache key\n * @param value Value to store\n */\n set(key: KeyType, value: ValueType): void;\n\n /**\n * Retrieve a value from the cache with the given key.\n *\n * @param key Cache key\n * @returns The cached value if it exists, otherwise undefined\n */\n get(key: KeyType): ValueType | undefined;\n\n /**\n * Clear the cache.\n */\n clear(): void;\n\n /**\n * The current number of items in the cache. Always a non-negative integer.\n */\n get size(): number;\n\n /**\n * The maximum number of items in the cache. Always a non-negative integer that is >= size().\n */\n get capacity(): number;\n}\n\n/**\n * Cache that maps from string -> ValueType with a LRU (least recently used) eviction policy.\n *\n * `get` and `set` are O(1) operations.\n *\n * @link https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU\n */\nexport class LruCache<KeyType extends string, ValueType> implements Cache<KeyType, ValueType> {\n private readonly _cache = new Map<string, ValueType>();\n private readonly _capacity: number;\n\n /**\n * Create a new LRU cache with the given capacity.\n *\n * @param capacity The maximum number of items in the cache. If set to 0, the cache is effectively disabled.\n * @throws Error if capacity is not a non-negative integer.\n */\n public constructor(capacity: number) {\n if (!Number.isInteger(capacity)) {\n throw new Error(\n `LruCache requires capacity to be an integer but a capacity of ${capacity} was requested.`,\n );\n }\n\n if (capacity < 0) {\n throw new Error(\n `LruCache requires a non-negative capacity but a capacity of ${capacity} was requested.`,\n );\n }\n\n this._capacity = capacity;\n }\n\n public set(key: string, value: ValueType) {\n this._cache.set(key, value);\n\n if (this._cache.size > this._capacity) {\n // oldestKey is guaranteed to be defined\n const oldestKey = this._cache.keys().next().value as string;\n this._cache.delete(oldestKey);\n }\n }\n\n public get(key: string) {\n const value = this._cache.get(key);\n if (value) {\n // The key is already in the cache, move it to the end (most recent)\n this._cache.delete(key);\n this._cache.set(key, value);\n }\n return value;\n }\n\n public clear() {\n this._cache.clear();\n }\n\n public get size() {\n return this._cache.size;\n }\n\n public get capacity() {\n return this._capacity;\n }\n}\n","/**\n * Filter out duplicates.\n */\nexport const uniq = <T>(arr: T[]): T[] => [...new Set(arr)];\n","import type { ChainIdString, DatetimeISO8601, UrlString } from \"./serialized-types\";\nimport type { ChainId, Datetime } from \"./types\";\n\n/**\n * Serializes a {@link ChainId} value into its string representation.\n */\nexport function serializeChainId(chainId: ChainId): ChainIdString {\n return chainId.toString();\n}\n\n/**\n * Serializes a {@link Datetime} value into its string representation.\n */\nexport function serializeDatetime(datetime: Datetime): DatetimeISO8601 {\n return datetime.toISOString();\n}\n\n/**\n * Serializes a {@link URL} value into its string representation.\n */\nexport function serializeUrl(url: URL): UrlString {\n return url.toString();\n}\n","import { prettifyError } from \"zod/v4\";\nimport type { ChainIdString, UrlString } from \"./serialized-types\";\nimport type { BlockNumber, BlockRef, Blockrange, ChainId, Datetime, Duration } from \"./types\";\nimport {\n makeBlockNumberSchema,\n makeBlockRefSchema,\n makeBlockrangeSchema,\n makeChainIdStringSchema,\n makeDatetimeSchema,\n makeDurationSchema,\n makeUnixTimestampSchema,\n makeUrlSchema,\n} from \"./zod-schemas\";\n\nexport function deserializeChainId(maybeChainId: ChainIdString, valueLabel?: string): ChainId {\n const schema = makeChainIdStringSchema(valueLabel);\n const parsed = schema.safeParse(maybeChainId);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ChainId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeDatetime(maybeDatetime: string, valueLabel?: string): Datetime {\n const schema = makeDatetimeSchema(valueLabel);\n const parsed = schema.safeParse(maybeDatetime);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Datetime:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeUnixTimestamp(maybeTimestamp: number, valueLabel?: string) {\n const schema = makeUnixTimestampSchema(valueLabel);\n const parsed = schema.safeParse(maybeTimestamp);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Unix Timestamp:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeUrl(maybeUrl: UrlString, valueLabel?: string): URL {\n const schema = makeUrlSchema(valueLabel);\n const parsed = schema.safeParse(maybeUrl);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize URL:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockNumber(maybeBlockNumber: number, valueLabel?: string): BlockNumber {\n const schema = makeBlockNumberSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockNumber);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize BlockNumber:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockrange(maybeBlockrange: Partial<Blockrange>, valueLabel?: string) {\n const schema = makeBlockrangeSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockrange);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Blockrange:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockRef(\n maybeBlockRef: Partial<BlockRef>,\n valueLabel?: string,\n): BlockRef {\n const schema = makeBlockRefSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockRef);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize BlockRef:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeDuration(maybeDuration: string, valueLabel?: string): Duration {\n const schema = makeDurationSchema(valueLabel);\n const parsed = schema.safeParse(maybeDuration);\n\n if (parsed.error) {\n throw new RangeError(`Cannot deserialize Duration:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n","/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport z from \"zod/v4\";\nimport { ENSNamespaceIds } from \"../ens\";\nimport type { BlockRef, Datetime, Duration, UnixTimestamp } from \"./types\";\n\n/**\n * Zod `.check()` function input.\n */\nexport type ZodCheckFnInput<T> = z.core.ParsePayload<T>;\n\n/**\n * Parses a string value as a boolean.\n */\nexport const makeBooleanStringSchema = (valueLabel: string = \"Value\") =>\n z\n .string()\n .pipe(\n z.enum([\"true\", \"false\"], {\n error: `${valueLabel} must be 'true' or 'false'.`,\n }),\n )\n .transform((val) => val === \"true\");\n\n/**\n * Parses a numeric value as an integer.\n */\nexport const makeIntegerSchema = (valueLabel: string = \"Value\") =>\n z.int({\n error: `${valueLabel} must be an integer.`,\n });\n\n/**\n * Parses a numeric value as a positive integer.\n */\nexport const makePositiveIntegerSchema = (valueLabel: string = \"Value\") =>\n makeIntegerSchema(valueLabel).positive({\n error: `${valueLabel} must be a positive integer (>0).`,\n });\n\n/**\n * Parses a numeric value as a non-negative integer.\n */\nexport const makeNonNegativeIntegerSchema = (valueLabel: string = \"Value\") =>\n makeIntegerSchema(valueLabel).nonnegative({\n error: `${valueLabel} must be a non-negative integer (>=0).`,\n });\n\n/**\n * Parses a numeric value as {@link Duration}\n */\nexport const makeDurationSchema = (valueLabel: string = \"Value\") =>\n z.coerce\n .number({\n error: `${valueLabel} must be a number.`,\n })\n .pipe(makeNonNegativeIntegerSchema(valueLabel));\n\n/**\n * Parses Chain ID\n *\n * {@link ChainId}\n */\nexport const makeChainIdSchema = (valueLabel: string = \"Chain ID\") =>\n makePositiveIntegerSchema(valueLabel);\n\n/**\n * Parses a string representation of {@link ChainId}.\n */\nexport const makeChainIdStringSchema = (valueLabel: string = \"Chain ID String\") =>\n z\n .string({ error: `${valueLabel} must be a string representing a chain ID.` })\n .pipe(z.coerce.number({ error: `${valueLabel} must represent a positive integer (>0).` }))\n .pipe(makeChainIdSchema(`The numeric value represented by ${valueLabel}`));\n\n/**\n * Parses an ISO 8601 string representations of {@link Datetime}\n */\nexport const makeDatetimeSchema = (valueLabel: string = \"Datetime string\") =>\n z.iso\n .datetime({ error: `${valueLabel} must be a string in ISO 8601 format.` })\n .transform((v) => new Date(v));\n\n/**\n * Parses value as {@link UnixTimestamp}.\n */\nexport const makeUnixTimestampSchema = (valueLabel: string = \"Timestamp\") =>\n makeIntegerSchema(valueLabel);\n\n/**\n * Parses a string representations of {@link URL}\n */\nexport const makeUrlSchema = (valueLabel: string = \"Value\") =>\n z\n .url({\n error: `${valueLabel} must be a valid URL string (e.g., http://localhost:8080 or https://example.com).`,\n })\n .transform((v) => new URL(v));\n\n/**\n * Parses a string representation of a comma separated list.\n */\nexport const makeCommaSeparatedList = (valueLabel: string = \"Value\") =>\n z\n .string({ error: `${valueLabel} must be a comma separated list.` })\n .transform((val) => val.split(\",\").filter(Boolean))\n .refine((val) => val.length > 0, {\n error: `${valueLabel} must be a comma separated list with at least one value.`,\n });\n\n/**\n * Parses a numeric value as a block number.\n */\nexport const makeBlockNumberSchema = (valueLabel: string = \"Block number\") =>\n makeNonNegativeIntegerSchema(valueLabel);\n\n/**\n * Parses an object value as the {@link Blockrange} object.\n */\nexport const makeBlockrangeSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject(\n {\n startBlock: makeBlockNumberSchema(`${valueLabel}.startBlock`).optional(),\n endBlock: makeBlockNumberSchema(`${valueLabel}.endBlock`).optional(),\n },\n {\n error: `${valueLabel} must be a valid Blockrange object.`,\n },\n )\n .refine(\n (v) => {\n if (v.startBlock && v.endBlock) {\n return v.startBlock <= v.endBlock;\n }\n\n return true;\n },\n { error: `${valueLabel}: startBlock must be before or equal to endBlock` },\n );\n\n/**\n * Parses an object value as the {@link BlockRef} object.\n */\nexport const makeBlockRefSchema = (valueLabel: string = \"Value\") =>\n z.strictObject(\n {\n timestamp: makeUnixTimestampSchema(`${valueLabel}.timestamp`),\n number: makeBlockNumberSchema(`${valueLabel}.number`),\n },\n {\n error: `${valueLabel} must be a valid BlockRef object.`,\n },\n );\n\n/**\n * Parses a string value as ENSNamespaceId.\n */\nexport const makeENSNamespaceIdSchema = (valueLabel: string = \"ENSNamespaceId\") =>\n z.enum(ENSNamespaceIds, {\n error() {\n return `Invalid ${valueLabel}. Supported ENS namespace IDs are: ${Object.keys(ENSNamespaceIds).join(\", \")}`;\n },\n });\n\n/**\n * Parses a numeric value as a port number.\n */\nexport const makePortSchema = (valueLabel: string = \"Port\") =>\n makePositiveIntegerSchema(valueLabel).max(65535, {\n error: `${valueLabel} must be an integer between 1 and 65535.`,\n });\n","import { isAddressEqual } from \"viem\";\nimport { AccountId } from \"./types\";\n\n/**\n * Determines where the provided AccountId values represent the same address on the same chain.\n */\nexport const accountIdEqual = (a: AccountId, b: AccountId): boolean => {\n return a.chainId === b.chainId && isAddressEqual(a.address, b.address);\n};\n","import { labelhash } from \"viem\";\n\nimport {\n type EncodedLabelHash,\n type Label,\n type Name,\n encodeLabelHash,\n isNormalizedLabel,\n isNormalizedName,\n} from \"../ens\";\n\n/**\n * Transforms a Literal Label into an Interpreted Label.\n *\n * @see https://ensnode.io/docs/reference/terminology#literal-label\n * @see https://ensnode.io/docs/reference/terminology#interpreted-label\n *\n * @param label - The Literal Label string to interpret\n * @returns The provided label if it is normalized, else the EncodedLabelHash of the label\n */\nexport function interpretLiteralLabel(label: Label): Label | EncodedLabelHash {\n // if the label is normalized, good to go\n if (isNormalizedLabel(label)) return label;\n\n // otherwise (includes empty string label), interpret as EncodedLabelHash\n return encodeLabelHash(labelhash(label));\n}\n\n/**\n * Transforms a Literal Name into an Interpreted Name.\n *\n * @see https://ensnode.io/docs/reference/terminology#literal-name\n * @see https://ensnode.io/docs/reference/terminology#interpreted-name\n *\n * If the name provided to this function contains empty-string labels (i.e 'this..name'),\n * then the empty string labels will be Interpreted. Empty-string is not a normalizable name, so the\n * label will be replaced with its Encoded LabelHash representation (i.e. )\n *\n * @param name - The Literal Name string to interpret\n * @returns The provided name if it is normalized, else converts each label in name that is not a\n * normalized label into an Interpreted Label\n */\nexport function interpretLiteralName(name: Name): Name {\n // if the name is already normalized (includes empty string), good to go\n if (isNormalizedName(name)) return name;\n\n // otherwise ensure the name is composed of Interpreted Labels\n return name.split(\".\").map(interpretLiteralLabel).join(\".\");\n}\n","import { ENSNamespaceId } from \"@ensnode/datasources\";\n\nimport type { EnsRainbowClientLabelSet } from \"../../ensrainbow\";\nimport { ChainId } from \"../../shared\";\n\n/**\n * A PluginName is a unique id for a 'plugin': we use the notion of\n * 'plugins' to describe bundles of indexing logic.\n */\nexport enum PluginName {\n Subgraph = \"subgraph\",\n Basenames = \"basenames\",\n Lineanames = \"lineanames\",\n ThreeDNS = \"threedns\",\n ReverseResolvers = \"reverse-resolvers\",\n Referrals = \"referrals\",\n TokenScope = \"tokenscope\",\n}\n\n/**\n * Information about ENSIndexer's dependencies.\n */\nexport interface DependencyInfo {\n /** Node.js runtime version */\n nodejs: string;\n\n /** Ponder framework version */\n ponder: string;\n\n /** ENSRainbow service version */\n ensRainbow: string;\n\n /** ENSRainbow schema version */\n ensRainbowSchema: number;\n}\n\n/**\n * Complete public configuration object for ENSIndexer.\n *\n * We use parameter types to maintain fields layout and documentation across\n * the domain model and its serialized counterpart.\n */\nexport interface ENSIndexerPublicConfig {\n /**\n * The ENS namespace that ENSNode operates in the context of.\n *\n * See {@link ENSNamespaceIds} for available namespace identifiers.\n */\n namespace: ENSNamespaceId;\n\n /**\n * An ENSAdmin URL\n *\n * The ENSNode root api route `/` redirects to {@link ensAdminUrl},\n * configuring ENSAdmin with an entry for this instance of ENSNode,\n * identified by {@link ensNodePublicUrl}.\n *\n * @see https://ensnode.io/ensadmin/overview/what-is-ensadmin\n */\n ensAdminUrl: URL;\n\n /**\n * The publicly accessible endpoint of the ENSNode API\n * (ex: http://localhost:42069).\n *\n * ENSAdmin will use this url to connect to the ENSNode api for querying\n * state about the ENSNode instance.\n */\n ensNodePublicUrl: URL;\n\n /**\n * The \"fully pinned\" label set reference that ENSIndexer will request ENSRainbow use for deterministic label healing across time. This label set reference is \"fully pinned\" as it requires both the labelSetId and labelSetVersion fields to be defined.\n */\n labelSet: Required<EnsRainbowClientLabelSet>;\n\n /**\n * A Postgres database schema name. This instance of ENSIndexer will write\n * indexed data to the tables in this schema.\n *\n * Invariants:\n * - Must be a non-empty string that is a valid Postgres database schema\n * identifier.\n */\n databaseSchemaName: string;\n\n /**\n * A set of {@link PluginName}s indicating which plugins to activate.\n *\n * Invariants:\n * - A set of valid {@link PluginName}s with at least one value\n */\n plugins: PluginName[];\n\n /**\n * Enable or disable healing of addr.reverse subnames.\n * If this is set to true, ENSIndexer will attempt to heal subnames of\n * addr.reverse.\n */\n healReverseAddresses: boolean;\n\n /**\n * Enable or disable the indexing of Resolver record values.\n * If this is set to false, ENSIndexer will apply subgraph-backwards\n * compatible logic that only tracks the keys of Resolver records.\n * If this is set to true, ENSIndexer will track both the keys and the values\n * of Resolver records.\n *\n * WARNING: Special care must be taken when interacting with indexed resolver\n * record values. It is unsafe to naively assume that indexed resolver record\n * values are equivalent to the resolver record values that would be returned\n * through dynamic lookups via the ENS protocol. For example, if a resolver\n * implements CCIP-Read, the resolver records may not be discoverable through\n * onchain indexing. This feature is under R&D. At this time we do not\n * recommend anyone directly use indexed resolver record values in their\n * applications. Features are planned in the ENSNode roadmap that will\n * provide safe use of indexed resolver record values (in appropriate\n * contexts).\n *\n * Note that enabling {@link indexAdditionalResolverRecords} results in indexed data becoming a\n * _superset_ of the Subgraph. For exact data-level backwards compatibility with the ENS Subgraph,\n * {@link indexAdditionalResolverRecords} should be `false`.\n */\n indexAdditionalResolverRecords: boolean;\n\n /**\n * Controls ENSIndexer's handling of Literal Labels and Literal Names\n * This configuration only applies to the Subgraph datamodel and Subgraph Compatible GraphQL API responses.\n *\n * When set to true, all Literal Labels and Literal Names encountered by ENSIndexer will be Interpreted.\n * - https://ensnode.io/docs/reference/terminology#interpreted-label\n * - https://ensnode.io/docs/reference/terminology#interpreted-name\n *\n * That is,\n * 1) all Labels stored and returned by ENSIndexer will either be normalized or represented as an Encoded\n * LabelHash, and\n * 2) all Names stored and returned by ENSIndexer will either be normalized or consist of Labels that\n * may be represented as an Encoded LabelHash of the Literal Label value found onchain.\n *\n * When set to false, ENSIndexer will store and return Literal Labels and Literal Names without further\n * interpretation.\n * - https://ensnode.io/docs/reference/terminology#literal-label\n * - https://ensnode.io/docs/reference/terminology#literal-name\n *\n * NOTE: {@link replaceUnnormalized} must be `false` for subgraph compatible indexing behavior.\n */\n replaceUnnormalized: boolean;\n\n /**\n * Indexed Chain IDs\n *\n * Includes the {@link ChainId} for each chain being indexed.\n */\n indexedChainIds: Set<ChainId>;\n\n /**\n * A flag derived from the built config indicating whether ENSIndexer is operating in a\n * subgraph-compatible way. This flag is true if:\n * a) only the subgraph plugin is activated,\n * b) healReverseAddresess is false, and\n * c) indexRecordValues is false\n *\n * If {@link isSubgraphCompatible} is true, ENSIndexer will:\n * 1) use subgraph-compatible IDs for entities and events\n * 2) limit indexing behavior to subgraph indexing semantics\n */\n isSubgraphCompatible: boolean;\n\n /**\n * Information about the ENSIndexer instance dependencies.\n */\n dependencyInfo: DependencyInfo;\n}\n","import { type ENSIndexerPublicConfig, PluginName } from \"./types\";\n\n/**\n * Determines if the provided `config` produces an index equivalent to the ENS Subgraph.\n *\n * @see https://ensnode.io/docs/reference/subgraph-compatibility/\n */\nexport function isSubgraphCompatible(\n config: Pick<\n ENSIndexerPublicConfig,\n | \"plugins\"\n | \"healReverseAddresses\"\n | \"indexAdditionalResolverRecords\"\n | \"replaceUnnormalized\"\n | \"labelSet\"\n >,\n): boolean {\n // 1. only the subgraph plugin is active\n const onlySubgraphPluginActivated =\n config.plugins.length === 1 && config.plugins[0] === PluginName.Subgraph;\n\n // 2. healReverseAddresses = false\n // 3. indexAdditionalResolverRecords = false\n // 4. replaceUnnormalized = false\n const indexingBehaviorIsSubgraphCompatible =\n !config.healReverseAddresses &&\n !config.indexAdditionalResolverRecords &&\n !config.replaceUnnormalized;\n\n // 5. label set id must be \"subgraph\" and version must be 0\n const labelSetIsSubgraphCompatible =\n config.labelSet.labelSetId === \"subgraph\" && config.labelSet.labelSetVersion === 0;\n\n return (\n onlySubgraphPluginActivated &&\n indexingBehaviorIsSubgraphCompatible &&\n labelSetIsSubgraphCompatible\n );\n}\n","import { ChainId } from \"../../shared\";\nimport { serializeUrl } from \"../../shared/serialize\";\nimport { SerializedENSIndexerPublicConfig, SerializedIndexedChainIds } from \"./serialized-types\";\nimport { ENSIndexerPublicConfig } from \"./types\";\n\n/**\n * Serializes a {@link ChainConfig} object.\n */\nexport function serializeIndexedChainIds(indexedChainIds: Set<ChainId>): SerializedIndexedChainIds {\n return Array.from(indexedChainIds);\n}\n/**\n * Serialize a {@link ENSIndexerPublicConfig} object.\n */\nexport function serializeENSIndexerPublicConfig(\n config: ENSIndexerPublicConfig,\n): SerializedENSIndexerPublicConfig {\n const {\n ensAdminUrl,\n ensNodePublicUrl,\n labelSet,\n indexedChainIds,\n databaseSchemaName,\n healReverseAddresses,\n indexAdditionalResolverRecords,\n replaceUnnormalized,\n isSubgraphCompatible,\n namespace,\n plugins,\n dependencyInfo,\n } = config;\n\n return {\n ensAdminUrl: serializeUrl(ensAdminUrl),\n ensNodePublicUrl: serializeUrl(ensNodePublicUrl),\n labelSet,\n indexedChainIds: serializeIndexedChainIds(indexedChainIds),\n databaseSchemaName,\n healReverseAddresses,\n indexAdditionalResolverRecords,\n replaceUnnormalized,\n isSubgraphCompatible,\n namespace,\n plugins,\n dependencyInfo,\n } satisfies SerializedENSIndexerPublicConfig;\n}\n","import {\n type EnsRainbowClientLabelSet,\n type EnsRainbowServerLabelSet,\n type LabelSetId,\n type LabelSetVersion,\n} from \"../../ensrainbow\";\nimport { makeLabelSetIdSchema, makeLabelSetVersionSchema } from \"./zod-schemas\";\n\n/**\n * Builds a valid LabelSetId from a string.\n * @param maybeLabelSetId - The string to validate and convert to a LabelSetId.\n * @returns A valid LabelSetId.\n * @throws If the input string is not a valid LabelSetId.\n */\nexport function buildLabelSetId(maybeLabelSetId: string): LabelSetId {\n return makeLabelSetIdSchema(\"LabelSetId\").parse(maybeLabelSetId);\n}\n\n/**\n * Builds a valid LabelSetVersion from a number or string.\n * @param maybeLabelSetVersion - The number or string to validate and convert to a LabelSetVersion.\n * @returns A valid LabelSetVersion.\n * @throws If the input is not a valid LabelSetVersion.\n */\nexport function buildLabelSetVersion(maybeLabelSetVersion: number | string): LabelSetVersion {\n return makeLabelSetVersionSchema(\"LabelSetVersion\").parse(maybeLabelSetVersion);\n}\n\n/**\n * Builds an EnsRainbowClientLabelSet.\n * @param labelSetId - The label set ID.\n * @param labelSetVersion - The label set version.\n * @returns A valid EnsRainbowClientLabelSet object.\n * @throws If `labelSetVersion` is defined without `labelSetId`.\n */\nexport function buildEnsRainbowClientLabelSet(\n labelSetId?: LabelSetId,\n labelSetVersion?: LabelSetVersion,\n): EnsRainbowClientLabelSet {\n if (labelSetVersion !== undefined && labelSetId === undefined) {\n throw new Error(\"When a labelSetVersion is defined, labelSetId must also be defined.\");\n }\n\n return { labelSetId, labelSetVersion };\n}\n\n/**\n * Validates that the server's label set is compatible with the client's requested label set.\n * @param serverSet - The label set provided by the server.\n * @param clientSet - The label set requested by the client.\n * @throws If the server set is not compatible with the client set.\n */\nexport function validateSupportedLabelSetAndVersion(\n serverSet: EnsRainbowServerLabelSet,\n clientSet: EnsRainbowClientLabelSet,\n): void {\n if (clientSet.labelSetId === undefined) {\n // Client did not specify a label set, so any server set is acceptable.\n return;\n }\n\n if (serverSet.labelSetId !== clientSet.labelSetId) {\n throw new Error(\n `Server label set ID \"${serverSet.labelSetId}\" does not match client's requested label set ID \"${clientSet.labelSetId}\".`,\n );\n }\n\n if (\n clientSet.labelSetVersion !== undefined &&\n serverSet.highestLabelSetVersion < clientSet.labelSetVersion\n ) {\n throw new Error(\n `Server highest label set version ${serverSet.highestLabelSetVersion} is less than client's requested version ${clientSet.labelSetVersion} for label set ID \"${clientSet.labelSetId}\".`,\n );\n }\n}\n","import { ByteArray, hexToBytes } from \"viem\";\nimport type { LabelHash } from \"../../ens\";\n\n/**\n * Converts a Labelhash to bytes, with validation\n * @param labelHash The Labelhash to convert\n * @returns A ByteArray containing the bytes\n * @throws Error if `labelHash` is not a valid 32-byte hex string\n */\nexport function labelHashToBytes(labelHash: LabelHash): ByteArray {\n try {\n if (labelHash.length !== 66) {\n throw new Error(`Invalid labelHash length ${labelHash.length} characters (expected 66)`);\n }\n if (labelHash !== labelHash.toLowerCase()) {\n throw new Error(\"Labelhash must be in lowercase\");\n }\n if (!labelHash.startsWith(\"0x\")) {\n throw new Error(\"Labelhash must be 0x-prefixed\");\n }\n const bytes = hexToBytes(labelHash);\n if (bytes.length !== 32) {\n // should be redundant but keeping it for the principle of defensive programming\n throw new Error(`Invalid labelHash length ${bytes.length} bytes (expected 32)`);\n }\n return bytes;\n } catch (e) {\n if (e instanceof Error) {\n throw e;\n }\n throw new Error(\"Invalid hex format\");\n }\n}\n","/**\n * Parses a string into a non-negative integer.\n * @param input The string to parse\n * @returns The parsed non-negative integer\n * @throws Error if the input is not a valid non-negative integer\n */\nexport function parseNonNegativeInteger(maybeNumber: string): number {\n const trimmed = maybeNumber.trim();\n\n // Check for empty strings\n if (!trimmed) {\n throw new Error(\"Input cannot be empty\");\n }\n\n // Check for -0\n if (trimmed === \"-0\") {\n throw new Error(\"Negative zero is not a valid non-negative integer\");\n }\n\n const num = Number(maybeNumber);\n\n // Check if it's not a number\n if (Number.isNaN(num)) {\n throw new Error(`\"${maybeNumber}\" is not a valid number`);\n }\n\n // Check if it's not finite\n if (!Number.isFinite(num)) {\n throw new Error(`\"${maybeNumber}\" is not a finite number`);\n }\n\n // Check if it's not an integer\n if (!Number.isInteger(num)) {\n throw new Error(`\"${maybeNumber}\" is not an integer`);\n }\n\n // Check if it's negative\n if (num < 0) {\n throw new Error(`\"${maybeNumber}\" is not a non-negative integer`);\n }\n\n return num;\n}\n","import { prettifyError } from \"zod/v4\";\nimport { SerializedENSIndexerOverallIndexingStatus } from \"./serialized-types\";\nimport { ENSIndexerOverallIndexingStatus } from \"./types\";\nimport { makeENSIndexerIndexingStatusSchema } from \"./zod-schemas\";\n\n/**\n * Serialize a {@link ENSIndexerOverallIndexingStatus} object.\n */\nexport function deserializeENSIndexerIndexingStatus(\n maybeStatus: SerializedENSIndexerOverallIndexingStatus,\n valueLabel?: string,\n): ENSIndexerOverallIndexingStatus {\n const schema = makeENSIndexerIndexingStatusSchema(valueLabel);\n const parsed = schema.safeParse(maybeStatus);\n\n if (parsed.error) {\n throw new Error(\n `Cannot deserialize ENSIndexerIndexingStatus:\\n${prettifyError(parsed.error)}\\n`,\n );\n }\n\n return parsed.data;\n}\n","/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport z from \"zod/v4\";\nimport { ChainId, deserializeChainId } from \"../../shared\";\nimport * as blockRef from \"../../shared/block-ref\";\nimport {\n makeBlockRefSchema,\n makeChainIdStringSchema,\n makeDurationSchema,\n makeUnixTimestampSchema,\n} from \"../../shared/zod-schemas\";\nimport {\n checkChainIndexingStatusesForBackfillOverallStatus,\n checkChainIndexingStatusesForCompletedOverallStatus,\n checkChainIndexingStatusesForFollowingOverallStatus,\n checkChainIndexingStatusesForUnstartedOverallStatus,\n getOverallApproxRealtimeDistance,\n getOverallIndexingStatus,\n getStandbyChains,\n} from \"./helpers\";\nimport {\n ChainIndexingBackfillStatus,\n ChainIndexingCompletedStatus,\n ChainIndexingConfig,\n ChainIndexingFollowingStatus,\n ChainIndexingStatus,\n ChainIndexingStatusForBackfillOverallStatus,\n ChainIndexingStatusIds,\n ChainIndexingStrategyIds,\n ChainIndexingUnstartedStatus,\n ENSIndexerOverallIndexingBackfillStatus,\n ENSIndexerOverallIndexingCompletedStatus,\n ENSIndexerOverallIndexingErrorStatus,\n ENSIndexerOverallIndexingFollowingStatus,\n ENSIndexerOverallIndexingUnstartedStatus,\n OverallIndexingStatusIds,\n} from \"./types\";\n\n/**\n * Makes Zod schema for {@link ChainIndexingConfig} type.\n */\nconst makeChainIndexingConfigSchema = (valueLabel: string = \"Value\") =>\n z.discriminatedUnion(\"strategy\", [\n z.strictObject({\n strategy: z.literal(ChainIndexingStrategyIds.Indefinite),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: z.null(),\n }),\n z.strictObject({\n strategy: z.literal(ChainIndexingStrategyIds.Definite),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n ]);\n\n/**\n * Makes Zod schema for {@link ChainIndexingUnstartedStatus} type.\n */\nexport const makeChainIndexingUnstartedStatusSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject({\n status: z.literal(ChainIndexingStatusIds.Unstarted),\n config: makeChainIndexingConfigSchema(valueLabel),\n })\n .refine(\n ({ config }) =>\n config.endBlock === null || blockRef.isBeforeOrEqualTo(config.startBlock, config.endBlock),\n {\n error: `config.startBlock must be before or same as config.endBlock.`,\n },\n );\n\n/**\n * Makes Zod schema for {@link ChainIndexingBackfillStatus} type.\n */\nexport const makeChainIndexingBackfillStatusSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject({\n status: z.literal(ChainIndexingStatusIds.Backfill),\n config: makeChainIndexingConfigSchema(valueLabel),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n latestSyncedBlock: makeBlockRefSchema(valueLabel),\n backfillEndBlock: makeBlockRefSchema(valueLabel),\n })\n .refine(\n ({ config, latestIndexedBlock }) =>\n blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock),\n {\n error: `config.startBlock must be before or same as latestIndexedBlock.`,\n },\n )\n .refine(\n ({ latestIndexedBlock, latestSyncedBlock }) =>\n blockRef.isBeforeOrEqualTo(latestIndexedBlock, latestSyncedBlock),\n {\n error: `latestIndexedBlock must be before or same as latestSyncedBlock.`,\n },\n )\n .refine(\n ({ latestSyncedBlock, backfillEndBlock }) =>\n blockRef.isBeforeOrEqualTo(latestSyncedBlock, backfillEndBlock),\n {\n error: `latestSyncedBlock must be before or same as backfillEndBlock.`,\n },\n )\n .refine(\n ({ config, backfillEndBlock }) =>\n config.endBlock === null || blockRef.isEqualTo(backfillEndBlock, config.endBlock),\n {\n error: `backfillEndBlock must be the same as config.endBlock.`,\n },\n );\n\n/**\n * Makes Zod schema for {@link ChainIndexingFollowingStatus} type.\n */\nexport const makeChainIndexingFollowingStatusSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject({\n status: z.literal(ChainIndexingStatusIds.Following),\n config: z.strictObject({\n strategy: z.literal(ChainIndexingStrategyIds.Indefinite),\n startBlock: makeBlockRefSchema(valueLabel),\n }),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n latestKnownBlock: makeBlockRefSchema(valueLabel),\n approxRealtimeDistance: makeDurationSchema(valueLabel),\n })\n .refine(\n ({ config, latestIndexedBlock }) =>\n blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock),\n {\n error: `config.startBlock must be before or same as latestIndexedBlock.`,\n },\n )\n .refine(\n ({ latestIndexedBlock, latestKnownBlock }) =>\n blockRef.isBeforeOrEqualTo(latestIndexedBlock, latestKnownBlock),\n {\n error: `latestIndexedBlock must be before or same as latestKnownBlock.`,\n },\n );\n\n/**\n * Makes Zod schema for {@link ChainIndexingCompletedStatus} type.\n */\nexport const makeChainIndexingCompletedStatusSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject({\n status: z.literal(ChainIndexingStatusIds.Completed),\n config: z.strictObject({\n strategy: z.literal(ChainIndexingStrategyIds.Definite),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n })\n .refine(\n ({ config, latestIndexedBlock }) =>\n blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock),\n {\n error: `config.startBlock must be before or same as latestIndexedBlock.`,\n },\n )\n .refine(\n ({ config, latestIndexedBlock }) =>\n blockRef.isBeforeOrEqualTo(latestIndexedBlock, config.endBlock),\n {\n error: `latestIndexedBlock must be before or same as config.endBlock.`,\n },\n );\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatus}\n */\nexport const makeChainIndexingStatusSchema = (valueLabel: string = \"Value\") =>\n z.discriminatedUnion(\"status\", [\n makeChainIndexingUnstartedStatusSchema(valueLabel),\n makeChainIndexingBackfillStatusSchema(valueLabel),\n makeChainIndexingFollowingStatusSchema(valueLabel),\n makeChainIndexingCompletedStatusSchema(valueLabel),\n ]);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatus} per chain.\n */\nexport const makeChainIndexingStatusesSchema = (valueLabel: string = \"Value\") =>\n z\n .record(makeChainIdStringSchema(), makeChainIndexingStatusSchema(valueLabel), {\n error: \"Chains configuration must be an object mapping valid chain IDs to their configs.\",\n })\n .transform((serializedChainsIndexingStatus) => {\n const chainsIndexingStatus = new Map<ChainId, ChainIndexingStatus>();\n\n for (const [chainIdString, chainStatus] of Object.entries(serializedChainsIndexingStatus)) {\n chainsIndexingStatus.set(deserializeChainId(chainIdString), chainStatus);\n }\n\n return chainsIndexingStatus;\n });\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingUnstartedStatus}\n */\nconst makeUnstartedOverallStatusSchema = (valueLabel?: string) =>\n z\n .strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.Unstarted),\n chains: makeChainIndexingStatusesSchema(valueLabel)\n .refine(\n (chains) =>\n checkChainIndexingStatusesForUnstartedOverallStatus(Array.from(chains.values())),\n {\n error: `${valueLabel} at least one chain must be in \"unstarted\" status and\neach chain has to have a status of either \"unstarted\", or \"completed\"`,\n },\n )\n .transform((chains) => chains as Map<ChainId, ChainIndexingUnstartedStatus>),\n })\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return getOverallIndexingStatus(chains) === indexingStatus.overallStatus;\n },\n { error: `${valueLabel} is an invalid overallStatus.` },\n );\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingBackfillStatus}\n */\nconst makeBackfillOverallStatusSchema = (valueLabel?: string) =>\n z\n .strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.Backfill),\n chains: makeChainIndexingStatusesSchema(valueLabel)\n .refine(\n (chains) =>\n checkChainIndexingStatusesForBackfillOverallStatus(Array.from(chains.values())),\n {\n error: `${valueLabel} at least one chain must be in \"backfill\" status and\neach chain has to have a status of either \"unstarted\", \"backfill\" or \"completed\"`,\n },\n )\n .transform((chains) => chains as Map<ChainId, ChainIndexingStatusForBackfillOverallStatus>),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return getOverallIndexingStatus(chains) === indexingStatus.overallStatus;\n },\n { error: `${valueLabel} is an invalid overallStatus.` },\n )\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n const standbyChainStartBlocks = getStandbyChains(chains).map(\n (chain) => chain.config.startBlock.timestamp,\n );\n\n const standbyChainEarliestStartBlocks = Math.min(...standbyChainStartBlocks);\n\n return indexingStatus.omnichainIndexingCursor <= standbyChainEarliestStartBlocks;\n },\n {\n error:\n \"omnichainIndexingCursor must be lower than or equal to the earliest config.startBlock across all standby chains\",\n },\n );\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingCompletedStatus}\n */\nconst makeCompletedOverallStatusSchema = (valueLabel?: string) =>\n z\n .strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.Completed),\n chains: makeChainIndexingStatusesSchema(valueLabel)\n .refine(\n (chains) =>\n checkChainIndexingStatusesForCompletedOverallStatus(Array.from(chains.values())),\n {\n error: `${valueLabel} all chains must have \"completed\" status`,\n },\n )\n .transform((chains) => chains as Map<ChainId, ChainIndexingCompletedStatus>),\n })\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return getOverallIndexingStatus(chains) === indexingStatus.overallStatus;\n },\n { error: `${valueLabel} is an invalid overallStatus.` },\n );\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingFollowingStatus}\n */\nconst makeFollowingOverallStatusSchema = (valueLabel?: string) =>\n z\n .strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.Following),\n chains: makeChainIndexingStatusesSchema(valueLabel),\n overallApproxRealtimeDistance: makeDurationSchema(valueLabel),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return getOverallIndexingStatus(chains) === indexingStatus.overallStatus;\n },\n { error: `${valueLabel} is an invalid overallStatus.` },\n )\n .refine(\n (indexingStatus) =>\n checkChainIndexingStatusesForFollowingOverallStatus(\n Array.from(indexingStatus.chains.values()),\n ),\n {\n error: `${valueLabel} at least one chain must be in \"following\" status`,\n },\n )\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n return (\n getOverallApproxRealtimeDistance(chains) === indexingStatus.overallApproxRealtimeDistance\n );\n },\n { error: `${valueLabel} is an invalid overallApproxRealtimeDistance.` },\n )\n .refine(\n (indexingStatus) => {\n const chains = Array.from(indexingStatus.chains.values());\n\n const standbyChainStartBlocks = getStandbyChains(chains).map(\n (chain) => chain.config.startBlock.timestamp,\n );\n\n const standbyChainEarliestStartBlocks = Math.min(...standbyChainStartBlocks);\n\n return indexingStatus.omnichainIndexingCursor <= standbyChainEarliestStartBlocks;\n },\n {\n error:\n \"omnichainIndexingCursor must be lower than or equal to the earliest config.startBlock across all standby chains\",\n },\n );\n\n/**\n * Makes Zod schema for {@link ENSIndexerOverallIndexingErrorStatus}\n */\nconst makeErrorSchemaOverallStatusSchema = (valueLabel?: string) =>\n z.strictObject({\n overallStatus: z.literal(OverallIndexingStatusIds.IndexerError),\n });\n\n/**\n * ENSIndexer Overall Indexing Status Schema\n *\n * Makes a Zod schema definition for validating indexing status\n * across all chains indexed by ENSIndexer instance.\n */\nexport const makeENSIndexerIndexingStatusSchema = (\n valueLabel: string = \"ENSIndexerIndexingStatus\",\n) =>\n z.discriminatedUnion(\"overallStatus\", [\n makeUnstartedOverallStatusSchema(valueLabel),\n makeBackfillOverallStatusSchema(valueLabel),\n makeCompletedOverallStatusSchema(valueLabel),\n makeFollowingOverallStatusSchema(valueLabel),\n makeErrorSchemaOverallStatusSchema(valueLabel),\n ]);\n","import type { BlockRef } from \"./types\";\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is before blockB.\n */\nexport function isBefore(blockA: BlockRef, blockB: BlockRef) {\n return blockA.number < blockB.number && blockA.timestamp < blockB.timestamp;\n}\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is equal to blockB.\n */\nexport function isEqualTo(blockA: BlockRef, blockB: BlockRef) {\n return blockA.number === blockB.number && blockA.timestamp === blockB.timestamp;\n}\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is before or equal to blockB.\n */\nexport function isBeforeOrEqualTo(blockA: BlockRef, blockB: BlockRef) {\n return isBefore(blockA, blockB) || isEqualTo(blockA, blockB);\n}\n","import type { BlockRef, ChainId, Duration, UnixTimestamp } from \"../../shared\";\n\nexport const ChainIndexingStatusIds = {\n Unstarted: \"unstarted\",\n Backfill: \"backfill\",\n Following: \"following\",\n Completed: \"completed\",\n} as const;\n\n/**\n * ChainIndexingStatusId is the derived string union of possible Chain Indexing Status identifiers.\n */\nexport type ChainIndexingStatusId =\n (typeof ChainIndexingStatusIds)[keyof typeof ChainIndexingStatusIds];\n\nexport const OverallIndexingStatusIds = {\n Unstarted: \"unstarted\",\n Backfill: \"backfill\",\n Following: \"following\",\n Completed: \"completed\",\n IndexerError: \"indexer-error\",\n} as const;\n\n/**\n * OverallIndexingStatusId is the derived string union of possible Overall Indexing Status identifiers.\n */\nexport type OverallIndexingStatusId =\n (typeof OverallIndexingStatusIds)[keyof typeof OverallIndexingStatusIds];\n\nexport const ChainIndexingStrategyIds = {\n Indefinite: \"indefinite\",\n Definite: \"definite\",\n} as const;\n\n/**\n * ChainIndexingStrategyIds is the derived string union of possible Chain Indexing Strategy identifiers.\n */\nexport type ChainIndexingStrategyId =\n (typeof ChainIndexingStrategyIds)[keyof typeof ChainIndexingStrategyIds];\n\n/**\n * Chain Indexing Indefinite Config\n *\n * Configures a chain to be indexed for an indefinite range.\n */\nexport interface ChainIndexingIndefiniteConfig {\n /**\n * Chain indexing strategy.\n */\n strategy: typeof ChainIndexingStrategyIds.Indefinite;\n\n /**\n * The block where indexing of the chain starts.\n *\n * An indexed chain always has its `startBlock` defined.\n */\n startBlock: BlockRef;\n\n /**\n * Indefinite chain indexing configs always have a null `endBlock`.\n */\n endBlock?: null;\n}\n\n/**\n * Chain Indexing Definite Config\n *\n * Configures a chain to be indexed for a definite range.\n *\n * Invariants:\n * - `startBlock` is always before or the same as `endBlock`\n */\nexport interface ChainIndexingDefiniteConfig {\n /**\n * Chain indexing strategy.\n */\n strategy: typeof ChainIndexingStrategyIds.Definite;\n\n /**\n * The block where indexing of the chain starts.\n *\n * `startBlock` must always be defined.\n */\n startBlock: BlockRef;\n\n /**\n * The block where indexing of the chain ends.\n *\n * Definite chain indexing configs always have a defined `endBlock`.\n */\n endBlock: BlockRef;\n}\n\n/**\n * Chain Indexing Config\n *\n * Configuration of an indexed chain.\n */\nexport type ChainIndexingConfig = ChainIndexingIndefiniteConfig | ChainIndexingDefiniteConfig;\n\n/**\n * Chain Indexing Status: Unstarted\n *\n * Notes:\n * - The \"unstarted\" status applies when using omnichain ordering and\n * the omnichainIndexingCursor from the overall indexing status <= config.startBlock.timestamp.\n */\nexport interface ChainIndexingUnstartedStatus {\n status: typeof ChainIndexingStatusIds.Unstarted;\n config: ChainIndexingConfig;\n}\n\n/**\n * Chain Indexing Status: Backfill\n *\n * During a backfill, special performance optimizations are applied to\n * index all blocks between config.startBlock and backfillEndBlock\n * as fast as possible.\n *\n * Notes:\n * - The backfillEndBlock is either config.endBlock (if present) or\n * the latest block on the chain when the ENSIndexer process started up.\n * Note how this means the backfillEndBlock is always a \"fixed target\".\n * - When latestIndexedBlock reaches backfillEndBlock, the backfill is complete.\n * The moment backfill is complete the status does not immediately transition.\n * Instead, internal processing is completed for a period of time while\n * the status remains \"backfill\". After this internal processing is completed\n * the status will change to \"following\" or \"completed\" depending on\n * the configured indexing strategy. If the strategy is indefinite,\n * changes to \"following\", else if the strategy is definite, changes to\n * \"completed\".\n *\n * Invariants:\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always before or the same as `latestSyncedBlock`\n * - `latestSyncedBlock` is always before or the same as `backfillEndBlock`\n * - `backfillEndBlock` is the same as `config.endBlock` if and only if\n * the config is definite.\n */\nexport interface ChainIndexingBackfillStatus {\n status: typeof ChainIndexingStatusIds.Backfill;\n config: ChainIndexingConfig;\n\n /**\n * The block that was most recently indexed.\n */\n latestIndexedBlock: BlockRef;\n\n /**\n * The \"highest\" block that has been synced into RPC cache. Backfill indexing\n * is accelerated by cached RPC calls through this block height.\n */\n latestSyncedBlock: BlockRef;\n\n /**\n * The block that is the target for finishing the backfill.\n */\n backfillEndBlock: BlockRef;\n}\n\n/**\n * Chain Indexing Status: Following\n *\n * Following occurs after the backfill of a chain is completed and represents\n * the process of indefinitely following (and indexing!) new blocks as they are\n * added to the indexed chain across time.\n *\n * Invariants:\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always before or the same as `latestKnownBlock`\n */\nexport interface ChainIndexingFollowingStatus {\n status: typeof ChainIndexingStatusIds.Following;\n\n config: ChainIndexingIndefiniteConfig;\n\n /**\n * The block that was most recently indexed.\n */\n latestIndexedBlock: BlockRef;\n\n /**\n * The \"highest\" block that has been fetched by RPC calls and stored in\n * the RPC cache as part of the indexing process.\n */\n latestKnownBlock: BlockRef;\n\n /**\n * The number of seconds between `latestIndexedBlock.timestamp` and\n * the current time in ENSIndexer. This represents the upper-bound worst case\n * distance approximation between the latest block on the chain (independent\n * of it becoming known to us) and the latest block that has completed\n * indexing. The true distance to the latest block on the chain will be less\n * if the latest block on the chain was not issued at the current second.\n */\n approxRealtimeDistance: Duration;\n}\n\n/**\n * Chain Indexing Status: Completed\n *\n * Indexing of a chain is completed after the backfill when the chain is\n * not configured to be indefinitely indexed.\n *\n * Invariants:\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always the same as `config.endBlock`.\n */\nexport interface ChainIndexingCompletedStatus {\n status: typeof ChainIndexingStatusIds.Completed;\n config: ChainIndexingDefiniteConfig;\n\n /**\n * The block that was most recently indexed.\n */\n latestIndexedBlock: BlockRef;\n}\n\n/**\n * Chain Indexing Status\n *\n * Use the `status` field to determine the correct type interpretation at runtime.\n */\nexport type ChainIndexingStatus =\n | ChainIndexingUnstartedStatus\n | ChainIndexingBackfillStatus\n | ChainIndexingFollowingStatus\n | ChainIndexingCompletedStatus;\n\n/**\n * Chain Indexing Status: Active\n *\n * Represents a chain where indexing is currently active.\n * The `latestIndexedBlock` field will be available.\n */\nexport type ChainIndexingActiveStatus = ChainIndexingBackfillStatus | ChainIndexingFollowingStatus;\n\n/**\n * Chain Indexing Status: Standby\n *\n * Represents a chain where indexing is currently on standby (not happening).\n * The `latestIndexedBlock` field will not be available.\n */\nexport type ChainIndexingStandbyStatus =\n | ChainIndexingUnstartedStatus\n | ChainIndexingCompletedStatus;\n\n/**\n * ENSIndexer Overall Indexing Status: Unstarted\n *\n * Describes the current state of indexing operations across all indexed chains\n * when the overall indexing status is {@link OverallIndexingStatusIds.Unstarted}.\n */\nexport interface ENSIndexerOverallIndexingUnstartedStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.Unstarted;\n\n /**\n * Indexing Status for each chain.\n *\n * Each chain is guaranteed to have the \"unstarted\" status.\n * It's impossible for any chain to have status other than \"unstarted\".\n */\n chains: Map<ChainId, ChainIndexingUnstartedStatus>;\n}\n\n/**\n * Chain Indexing Status allowed when overall status is 'backfill'.\n */\nexport type ChainIndexingStatusForBackfillOverallStatus =\n | ChainIndexingUnstartedStatus\n | ChainIndexingBackfillStatus\n | ChainIndexingCompletedStatus;\n\n/**\n * ENSIndexer Overall Indexing Status: Backfill\n *\n * Describes the current state of indexing operations across all indexed chains\n * when the overall indexing status is {@link OverallIndexingStatusIds.Backfill}.\n */\nexport interface ENSIndexerOverallIndexingBackfillStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.Backfill;\n\n /**\n * Omnichain Indexing Cursor\n *\n * Identifies the timestamp of the progress of omnichain indexing across\n * all chains in {@link ChainIndexingBackfillStatus} status.\n *\n * Invariants:\n * - the cursor value is guaranteed to be lower than or equal to\n * the timestamp of the earliest `config.startBlock` across all chains\n * in {@link ChainIndexingStandbyStatus} status.\n */\n omnichainIndexingCursor: UnixTimestamp;\n\n /**\n * Indexing Status for each chain.\n *\n * At least one chain is guaranteed to be in the \"backfill\" status.\n * Each chain is guaranteed to have a status of either \"unstarted\",\n * \"backfill\" or \"completed\". It's impossible for any chain to be\n * in the \"following\" status.\n */\n chains: Map<ChainId, ChainIndexingStatusForBackfillOverallStatus>;\n}\n\n/**\n * ENSIndexer Overall Indexing Status: Completed\n *\n * Describes the final state of indexing operations across all indexed chains\n * when all indexed chains are configured for a definite indexing strategy and\n * all indexing of that definite range is completed.\n */\nexport interface ENSIndexerOverallIndexingCompletedStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.Completed;\n\n /**\n * Indexing Status for each chain.\n *\n * Each chain is guaranteed to have the \"completed\" status.\n * It's impossible for any chain to have status other than \"completed\".\n */\n chains: Map<ChainId, ChainIndexingCompletedStatus>;\n}\n\n/**\n * ENSIndexer Overall Indexing Status: Following\n *\n * Describes the state when the overall indexing status is\n * {@link OverallIndexingStatusIds.Following}.\n */\nexport interface ENSIndexerOverallIndexingFollowingStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.Following;\n\n /**\n * Omnichain Indexing Cursor\n *\n * Identifies the timestamp of the progress of omnichain indexing across\n * all chains in {@link ChainIndexingActiveStatus} status.\n *\n * Invariants:\n * - the cursor value is guaranteed to be lower than or equal to\n * the timestamp of the earliest `config.startBlock` across all chains\n * in {@link ChainIndexingStandbyStatus} status.\n */\n omnichainIndexingCursor: UnixTimestamp;\n\n /**\n * Indexing Status for each chain.\n *\n * At least one chain is guaranteed to be in the \"following\" status.\n * Each chain is guaranteed to have a status of either \"unstarted\",\n * \"backfill\", \"following\" or \"completed\".\n */\n chains: Map<ChainId, ChainIndexingStatus>;\n\n /**\n * The maximum\n * {@link ChainIndexingFollowingStatus.approxRealtimeDistance} value\n * across all chains with status: 'following'.\n */\n overallApproxRealtimeDistance: Duration;\n}\n\n/**\n * ENSIndexer Overall Indexing Status: Error\n *\n * Describes the state when ENSIndexer failed to return the indexing status for\n * all indexed chains.\n *\n * This state suggests an error with the \"primary\" ENSIndexer.\n */\nexport interface ENSIndexerOverallIndexingErrorStatus {\n /**\n * Overall Indexing Status\n */\n overallStatus: typeof OverallIndexingStatusIds.IndexerError;\n}\n\n/**\n * ENSIndexer Overall Indexing Status\n *\n * Describes the overall state of indexing operations.\n */\nexport type ENSIndexerOverallIndexingStatus =\n | ENSIndexerOverallIndexingUnstartedStatus\n | ENSIndexerOverallIndexingBackfillStatus\n | ENSIndexerOverallIndexingCompletedStatus\n | ENSIndexerOverallIndexingFollowingStatus\n | ENSIndexerOverallIndexingErrorStatus;\n","import { BlockRef, ChainId, Duration, UnixTimestamp } from \"../../shared\";\nimport {\n ChainIndexingActiveStatus,\n ChainIndexingCompletedStatus,\n ChainIndexingConfig,\n ChainIndexingDefiniteConfig,\n ChainIndexingIndefiniteConfig,\n ChainIndexingStandbyStatus,\n ChainIndexingStatus,\n ChainIndexingStatusForBackfillOverallStatus,\n ChainIndexingStatusIds,\n ChainIndexingStrategyIds,\n ChainIndexingUnstartedStatus,\n OverallIndexingStatusId,\n OverallIndexingStatusIds,\n} from \"./types\";\n\n/**\n * Get {@link OverallIndexingStatusId} based on indexed chains' statuses.\n *\n * This function decides what is the current overall indexing status,\n * based on provided chain indexing statuses. The fact that chain indexing\n * statuses were provided to this function guarantees there was no indexer\n * error, and that the overall indexing status is never\n * an {@link OverallIndexingStatusIds.IndexerError}\n */\nexport function getOverallIndexingStatus(\n chains: ChainIndexingStatus[],\n): Exclude<OverallIndexingStatusId, typeof OverallIndexingStatusIds.IndexerError> {\n const chainStatuses = chains.map((chain) => chain.status);\n\n let overallStatus: OverallIndexingStatusId;\n\n if (chainStatuses.some((chainStatus) => chainStatus === ChainIndexingStatusIds.Following)) {\n overallStatus = OverallIndexingStatusIds.Following;\n } else if (chainStatuses.some((chainStatus) => chainStatus === ChainIndexingStatusIds.Backfill)) {\n overallStatus = OverallIndexingStatusIds.Backfill;\n } else if (\n chainStatuses.some((chainStatus) => chainStatus === ChainIndexingStatusIds.Unstarted)\n ) {\n overallStatus = OverallIndexingStatusIds.Unstarted;\n } else {\n overallStatus = OverallIndexingStatusIds.Completed;\n }\n\n return overallStatus;\n}\n\n/**\n * Get overall approximate realtime distance across all indexed chains.\n *\n * @throws an error if none of the indexed chains was in the 'following' status.\n */\nexport function getOverallApproxRealtimeDistance(chains: ChainIndexingStatus[]): Duration {\n const chainApproxRealtimeDistances = chains\n .filter((chain) => chain.status === ChainIndexingStatusIds.Following)\n .map((chain) => chain.approxRealtimeDistance);\n\n if (chainApproxRealtimeDistances.length === 0) {\n throw new Error(\n `The overall approximate realtime distance value is undefined if no indexed chain is in the '${OverallIndexingStatusIds.Following}' status`,\n );\n }\n\n const approxRealtimeDistance = Math.max(...chainApproxRealtimeDistances);\n\n return approxRealtimeDistance;\n}\n\n/**\n * Get lowest of the highest end block across all chains which status is\n * {@link ChainIndexingStatus}.\n */\nexport function getTimestampForLowestOmnichainStartBlock(\n chains: ChainIndexingStatus[],\n): UnixTimestamp {\n const earliestKnownBlockTimestamps: UnixTimestamp[] = chains.map(\n (chain) => chain.config.startBlock.timestamp,\n );\n\n return Math.min(...earliestKnownBlockTimestamps);\n}\n\n/**\n * Get timestamp of the highest known block across all chains which status is\n * {@link ChainIndexingStatusForBackfillOverallStatus}.\n */\nexport function getTimestampForHighestOmnichainKnownBlock(\n chains: ChainIndexingStatus[],\n): UnixTimestamp {\n const latestKnownBlockTimestamps: UnixTimestamp[] = [];\n\n for (const chain of chains) {\n switch (chain.status) {\n case ChainIndexingStatusIds.Unstarted:\n if (chain.config.endBlock) {\n latestKnownBlockTimestamps.push(chain.config.endBlock.timestamp);\n }\n break;\n\n case ChainIndexingStatusIds.Backfill:\n latestKnownBlockTimestamps.push(chain.backfillEndBlock.timestamp);\n\n break;\n\n case ChainIndexingStatusIds.Completed:\n latestKnownBlockTimestamps.push(chain.latestIndexedBlock.timestamp);\n break;\n\n case ChainIndexingStatusIds.Following:\n latestKnownBlockTimestamps.push(chain.latestKnownBlock.timestamp);\n break;\n }\n }\n\n return Math.max(...latestKnownBlockTimestamps);\n}\n\n/**\n * Get Omnichain Indexing Cursor across all chains which status is\n * {@link ChainIndexingActiveStatus}.\n */\nexport function getOmnichainIndexingCursor(chains: ChainIndexingActiveStatus[]): UnixTimestamp {\n return Math.min(...chains.map((chain) => chain.latestIndexedBlock.timestamp));\n}\n\n/**\n * Get all chains which status is {@link ChainIndexingActiveStatus}.\n */\nexport function getActiveChains(chains: ChainIndexingStatus[]): ChainIndexingActiveStatus[] {\n return chains.filter(\n (chain) =>\n chain.status === ChainIndexingStatusIds.Backfill ||\n chain.status === ChainIndexingStatusIds.Following,\n );\n}\n\n/**\n * Get all chains which status is {@link ChainIndexingStandbyStatus}.\n */\nexport function getStandbyChains(chains: ChainIndexingStatus[]): ChainIndexingStandbyStatus[] {\n return chains.filter(\n (chain) =>\n chain.status === ChainIndexingStatusIds.Unstarted ||\n chain.status === ChainIndexingStatusIds.Completed,\n );\n}\n\n/**\n * Create {@link ChainIndexingConfig} for given block refs.\n *\n * @param startBlock required block ref\n * @param endBlock optional block ref\n */\nexport function createIndexingConfig(\n startBlock: BlockRef,\n endBlock: BlockRef | null,\n): ChainIndexingConfig {\n if (endBlock) {\n return {\n strategy: ChainIndexingStrategyIds.Definite,\n startBlock,\n endBlock,\n } satisfies ChainIndexingDefiniteConfig;\n }\n\n return {\n strategy: ChainIndexingStrategyIds.Indefinite,\n startBlock,\n endBlock: null,\n } satisfies ChainIndexingIndefiniteConfig;\n}\n\n/**\n * Check if Chain Indexing Statuses fit the 'unstarted' overall status\n * requirements:\n * - All chains are guaranteed to have a status of \"unstarted\".\n *\n * Note: This function narrows the {@link ChainIndexingStatus} type to\n * {@link ChainIndexingUnstartedStatus}.\n */\nexport function checkChainIndexingStatusesForUnstartedOverallStatus(\n chains: ChainIndexingStatus[],\n): chains is ChainIndexingUnstartedStatus[] {\n return chains.every((chain) => chain.status === ChainIndexingStatusIds.Unstarted);\n}\n\n/**\n * Check if Chain Indexing Statuses fit the 'backfill' overall status\n * requirements:\n * - At least one chain is guaranteed to be in the \"backfill\" status.\n * - Each chain is guaranteed to have a status of either \"unstarted\",\n * \"backfill\" or \"completed\".\n *\n * Note: This function narrows the {@linkChainIndexingStatus} type to\n * {@link ChainIndexingStatusForBackfillOverallStatus}.\n */\nexport function checkChainIndexingStatusesForBackfillOverallStatus(\n chains: ChainIndexingStatus[],\n): chains is ChainIndexingStatusForBackfillOverallStatus[] {\n const atLeastOneChainInTargetStatus = chains.some(\n (chain) => chain.status === ChainIndexingStatusIds.Backfill,\n );\n const otherChainsHaveValidStatuses = chains.every(\n (chain) =>\n chain.status === ChainIndexingStatusIds.Unstarted ||\n chain.status === ChainIndexingStatusIds.Backfill ||\n chain.status === ChainIndexingStatusIds.Completed,\n );\n\n return atLeastOneChainInTargetStatus && otherChainsHaveValidStatuses;\n}\n\n/**\n * Checks if Chain Indexing Statuses fit the 'completed' overall status\n * requirements:\n * - All chains are guaranteed to have a status of \"completed\".\n *\n * Note: This function narrows the {@linkChainIndexingStatus} type to\n * {@link ChainIndexingCompletedStatus}.\n */\nexport function checkChainIndexingStatusesForCompletedOverallStatus(\n chains: ChainIndexingStatus[],\n): chains is ChainIndexingCompletedStatus[] {\n const allChainsHaveValidStatuses = chains.every(\n (chain) => chain.status === ChainIndexingStatusIds.Completed,\n );\n\n return allChainsHaveValidStatuses;\n}\n\n/**\n * Checks Chain Indexing Statuses fit the 'following' overall status\n * requirements:\n * - At least one chain is guaranteed to be in the \"following\" status.\n * - Any other chain can have any status.\n */\nexport function checkChainIndexingStatusesForFollowingOverallStatus(\n chains: ChainIndexingStatus[],\n): chains is ChainIndexingStatus[] {\n const allChainsHaveValidStatuses = chains.some(\n (chain) => chain.status === ChainIndexingStatusIds.Following,\n );\n\n return allChainsHaveValidStatuses;\n}\n\n/**\n * Sort a list of [{@link ChainId}, {@link ChainIndexingStatus}] tuples\n * by the omnichain start block timestamp in ascending order.\n */\nexport function sortAscChainStatusesByStartBlock<ChainStatusType extends ChainIndexingStatus>(\n chains: [ChainId, ChainStatusType][],\n): [ChainId, ChainStatusType][] {\n // Sort the chain statuses by the omnichain first block to index timestamp\n chains.sort(\n ([, chainA], [, chainB]) =>\n chainA.config.startBlock.timestamp - chainB.config.startBlock.timestamp,\n );\n\n return chains;\n}\n","import { ChainId, ChainIdString, serializeChainId } from \"../../shared\";\nimport {\n SerializedENSIndexerOverallIndexingBackfillStatus,\n SerializedENSIndexerOverallIndexingCompletedStatus,\n SerializedENSIndexerOverallIndexingErrorStatus,\n SerializedENSIndexerOverallIndexingFollowingStatus,\n SerializedENSIndexerOverallIndexingStatus,\n SerializedENSIndexerOverallIndexingUnstartedStatus,\n} from \"./serialized-types\";\nimport {\n ChainIndexingStatus,\n ENSIndexerOverallIndexingStatus,\n OverallIndexingStatusIds,\n} from \"./types\";\n\n/**\n * Serialize chain indexing statuses.\n */\nexport function serializeChainIndexingStatuses<ChainIndexingStatusType extends ChainIndexingStatus>(\n chainIndexingStatuses: Map<ChainId, ChainIndexingStatusType>,\n): Record<ChainIdString, ChainIndexingStatusType> {\n const serializedChainsIndexingStatuses: Record<ChainIdString, ChainIndexingStatusType> = {};\n\n for (const [chainId, chainIndexingStatus] of chainIndexingStatuses.entries()) {\n serializedChainsIndexingStatuses[serializeChainId(chainId)] = chainIndexingStatus;\n }\n\n return serializedChainsIndexingStatuses;\n}\n\n/**\n * Serialize a {@link ENSIndexerIndexingStatus} object.\n */\nexport function serializeENSIndexerIndexingStatus(\n indexingStatus: ENSIndexerOverallIndexingStatus,\n): SerializedENSIndexerOverallIndexingStatus {\n switch (indexingStatus.overallStatus) {\n case OverallIndexingStatusIds.IndexerError:\n return {\n overallStatus: OverallIndexingStatusIds.IndexerError,\n } satisfies SerializedENSIndexerOverallIndexingErrorStatus;\n\n case OverallIndexingStatusIds.Unstarted:\n return {\n overallStatus: OverallIndexingStatusIds.Unstarted,\n chains: serializeChainIndexingStatuses(indexingStatus.chains),\n } satisfies SerializedENSIndexerOverallIndexingUnstartedStatus;\n\n case OverallIndexingStatusIds.Backfill:\n return {\n overallStatus: OverallIndexingStatusIds.Backfill,\n chains: serializeChainIndexingStatuses(indexingStatus.chains),\n omnichainIndexingCursor: indexingStatus.omnichainIndexingCursor,\n } satisfies SerializedENSIndexerOverallIndexingBackfillStatus;\n\n case OverallIndexingStatusIds.Completed: {\n return {\n overallStatus: OverallIndexingStatusIds.Completed,\n chains: serializeChainIndexingStatuses(indexingStatus.chains),\n } satisfies SerializedENSIndexerOverallIndexingCompletedStatus;\n }\n\n case OverallIndexingStatusIds.Following:\n return {\n overallStatus: OverallIndexingStatusIds.Following,\n chains: serializeChainIndexingStatuses(indexingStatus.chains),\n overallApproxRealtimeDistance: indexingStatus.overallApproxRealtimeDistance,\n omnichainIndexingCursor: indexingStatus.omnichainIndexingCursor,\n } satisfies SerializedENSIndexerOverallIndexingFollowingStatus;\n }\n}\n","/**\n * Identifiers for each traceable ENS protocol.\n */\nexport enum TraceableENSProtocol {\n ForwardResolution = \"forward-resolution\",\n ReverseResolution = \"reverse-resolution\",\n}\n\n/**\n * Encodes the set of well-known steps in the ENS Forward Resolution protocol.\n */\nexport enum ForwardResolutionProtocolStep {\n Operation = \"forward-resolution\",\n FindResolver = \"find-resolver\",\n ActiveResolverExists = \"active-resolver-exists\",\n AccelerateENSIP19ReverseResolver = \"accelerate-ensip-19-reverse-resolver\",\n AccelerateKnownOffchainLookupResolver = \"accelerate-known-offchain-lookup-resolver\",\n AccelerateKnownOnchainStaticResolver = \"accelerate-known-onchain-static-resolver\",\n RequireResolver = \"require-resolver\",\n ExecuteResolveCalls = \"execute-resolve-calls\",\n}\n\n/**\n * Encodes the set of well-known steps in the ENS Reverse Resolution protocol.\n */\nexport enum ReverseResolutionProtocolStep {\n Operation = \"reverse-resolution\",\n ResolveReverseName = \"resolve-reverse-name\",\n NameRecordExists = \"name-record-exists-check\",\n ForwardResolveAddressRecord = \"forward-resolve-address-record\",\n VerifyResolvedAddressMatchesAddress = \"verify-resolved-address-matches-address\",\n}\n\nexport const PROTOCOL_ATTRIBUTE_PREFIX = \"ens\";\nexport const ATTR_PROTOCOL_NAME = `${PROTOCOL_ATTRIBUTE_PREFIX}.protocol`;\nexport const ATTR_PROTOCOL_STEP = `${PROTOCOL_ATTRIBUTE_PREFIX}.protocol.step`;\nexport const ATTR_PROTOCOL_STEP_RESULT = `${PROTOCOL_ATTRIBUTE_PREFIX}.protocol.step.result`;\n\ninterface SpanAttributes {\n [key: string]: unknown;\n}\n\ninterface SpanEvent {\n name: string;\n attributes: SpanAttributes;\n time: number;\n}\n\nexport interface ProtocolSpan {\n scope: string;\n id: string;\n traceId: string;\n parentSpanContext:\n | {\n traceId: string;\n spanId: string;\n }\n | undefined;\n name: string;\n timestamp: number;\n duration: number;\n attributes: SpanAttributes;\n status: { code: number; message?: string };\n events: SpanEvent[];\n}\n\nexport type ProtocolSpanTreeNode = ProtocolSpan & { children: ProtocolSpanTreeNode[] };\nexport type ProtocolTrace = ProtocolSpanTreeNode[];\n","import { prettifyError } from \"zod/v4\";\nimport { ErrorResponse } from \"./types\";\nimport { ErrorResponseSchema } from \"./zod-schemas\";\n\nexport function deserializeErrorResponse(maybeErrorResponse: unknown): ErrorResponse {\n const parsed = ErrorResponseSchema.safeParse(maybeErrorResponse);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ErrorResponse:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n","import z from \"zod/v4\";\n\nexport const ErrorResponseSchema = z.object({\n message: z.string(),\n details: z.optional(z.unknown()),\n});\n","import type { ENSIndexerOverallIndexingStatus, ENSIndexerPublicConfig } from \"../ensindexer\";\nimport type {\n ForwardResolutionArgs,\n MultichainPrimaryNameResolutionArgs,\n MultichainPrimaryNameResolutionResult,\n ResolverRecordsResponse,\n ResolverRecordsSelection,\n ReverseResolutionArgs,\n ReverseResolutionResult,\n} from \"../resolution\";\nimport type { Duration } from \"../shared\";\nimport type { ProtocolTrace } from \"../tracing\";\n\n/**\n * API Error Response Type\n */\nexport interface ErrorResponse {\n message: string;\n details?: unknown; // subject to change\n}\n\nexport interface TraceableRequest {\n trace?: boolean;\n}\n\nexport interface TraceableResponse {\n trace?: ProtocolTrace;\n}\n\nexport interface AcceleratableRequest {\n accelerate?: boolean;\n}\n\nexport interface AcceleratableResponse {\n accelerationAttempted: boolean;\n}\n\n/**\n * Resolve Records Request Type\n */\nexport interface ResolveRecordsRequest<SELECTION extends ResolverRecordsSelection>\n extends ForwardResolutionArgs<SELECTION>,\n AcceleratableRequest,\n TraceableRequest {}\n\n/**\n * Resolve Records Response Type\n */\nexport interface ResolveRecordsResponse<SELECTION extends ResolverRecordsSelection>\n extends AcceleratableResponse,\n TraceableResponse {\n records: ResolverRecordsResponse<SELECTION>;\n}\n\n/**\n * Resolve Primary Name Request Type\n */\nexport interface ResolvePrimaryNameRequest\n extends ReverseResolutionArgs,\n AcceleratableRequest,\n TraceableRequest {}\n\n/**\n * Resolve Primary Name Response Type\n */\nexport interface ResolvePrimaryNameResponse extends AcceleratableResponse, TraceableResponse {\n name: ReverseResolutionResult;\n}\n\nexport interface ResolvePrimaryNamesRequest\n extends MultichainPrimaryNameResolutionArgs,\n AcceleratableRequest,\n TraceableRequest {}\n\nexport interface ResolvePrimaryNamesResponse extends AcceleratableResponse, TraceableResponse {\n names: MultichainPrimaryNameResolutionResult;\n}\n\n/**\n * ENSIndexer Public Config Response\n */\nexport type ConfigResponse = ENSIndexerPublicConfig;\n\n/**\n * ENSIndexer Overall Indexing Status Request\n */\nexport interface IndexingStatusRequest {\n /**\n * Max Realtime Distance (optional)\n *\n * A duration value in seconds, representing the max allowed distance\n * between the latest indexed block of each chain and the “tip” of\n * all indexed chains. Setting this parameter influences the HTTP response\n * code as follows:\n * - Success (200 OK): The latest indexed block of each chain\n * is within the requested distance from realtime.\n * - Service Unavailable (503): The latest indexed block of each chain\n * is NOT within the requested distance from realtime.\n */\n maxRealtimeDistance?: Duration;\n}\n\n/**\n * ENSIndexer Overall Indexing Status Response\n */\nexport type IndexingStatusResponse = ENSIndexerOverallIndexingStatus;\n\n/**\n * ENSIndexer Overall Indexing Status Response Codes\n *\n * Define a custom response code for known responses.\n */\nexport const IndexingStatusResponseCodes = {\n IndexerError: 512,\n RequestedDistanceNotAchievedError: 513,\n} as const;\n","import { ErrorResponse } from \"./api\";\n\nexport class ClientError extends Error {\n details?: unknown;\n\n constructor(message: string, details?: unknown) {\n super(message);\n this.name = \"ClientError\";\n this.details = details;\n }\n\n static fromErrorResponse({ message, details }: ErrorResponse) {\n return new ClientError(message, details);\n }\n}\n","import { deserializeErrorResponse } from \"./api\";\nimport {\n type ConfigResponse,\n type ErrorResponse,\n type IndexingStatusRequest,\n type IndexingStatusResponse,\n IndexingStatusResponseCodes,\n type ResolvePrimaryNameRequest,\n type ResolvePrimaryNameResponse,\n type ResolvePrimaryNamesRequest,\n type ResolvePrimaryNamesResponse,\n type ResolveRecordsRequest,\n type ResolveRecordsResponse,\n} from \"./api/types\";\nimport { ClientError } from \"./client-error\";\nimport {\n type SerializedENSIndexerOverallIndexingStatus,\n type SerializedENSIndexerPublicConfig,\n deserializeENSIndexerIndexingStatus,\n deserializeENSIndexerPublicConfig,\n} from \"./ensindexer\";\nimport { ResolverRecordsSelection } from \"./resolution\";\n\n/**\n * Default ENSNode API endpoint URL\n */\nexport const DEFAULT_ENSNODE_API_URL = \"https://api.alpha.ensnode.io\" as const;\n\n/**\n * Configuration options for ENSNode API client\n */\nexport interface ClientOptions {\n /** The ENSNode API URL */\n url: URL;\n}\n\n/**\n * ENSNode API Client\n *\n * Provides access to the following ENSNode APIs:\n * - Resolution API\n * - 🚧 Configuration API\n * - 🚧 Indexing Status API\n *\n * @example\n * ```typescript\n * // Create client with default options\n * const client = new ENSNodeClient();\n *\n * // Use resolution methods\n * const { records } = await client.resolveRecords(\"jesse.base.eth\", {\n * addresses: [60],\n * texts: [\"avatar\"]\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Custom configuration\n * const client = new ENSNodeClient({\n * url: new URL(\"https://my-ensnode-instance.com\"),\n * });\n * ```\n */\nexport class ENSNodeClient {\n private readonly options: ClientOptions;\n\n static defaultOptions(): ClientOptions {\n return {\n url: new URL(DEFAULT_ENSNODE_API_URL),\n };\n }\n\n constructor(options: Partial<ClientOptions> = {}) {\n this.options = {\n ...ENSNodeClient.defaultOptions(),\n ...options,\n };\n }\n\n getOptions(): Readonly<ClientOptions> {\n return Object.freeze({\n url: new URL(this.options.url.href),\n });\n }\n\n /**\n * Resolves records for an ENS name (Forward Resolution).\n *\n * The returned `name` field, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name).\n * If the name record returned by the resolver is not normalized, `null` is returned as if no name record was set.\n *\n * @param name The ENS Name whose records to resolve\n * @param selection selection of Resolver records\n * @param options additional options\n * @param options.accelerate whether to attempt Protocol Acceleration (default false)\n * @param options.trace whether to include a trace in the response (default false)\n * @returns ResolveRecordsResponse<SELECTION>\n * @throws If the request fails or the ENSNode API returns an error response\n *\n * @example\n * ```typescript\n * const { records } = await client.resolveRecords(\"jesse.base.eth\", {\n * addresses: [60],\n * texts: [\"avatar\", \"com.twitter\"]\n * });\n *\n * console.log(records);\n * // {\n * // addresses: {\n * // 60: \"0xabcd...\"\n * // },\n * // texts: {\n * // avatar: \"https://example.com/image.jpg\",\n * // \"com.twitter\": null, // if not set, for example\n * // }\n * // }\n * ```\n */\n async resolveRecords<SELECTION extends ResolverRecordsSelection>(\n name: ResolveRecordsRequest<SELECTION>[\"name\"],\n selection: ResolveRecordsRequest<SELECTION>[\"selection\"],\n options?: Omit<ResolveRecordsRequest<SELECTION>, \"name\" | \"selection\">,\n ): Promise<ResolveRecordsResponse<SELECTION>> {\n const url = new URL(`/api/resolve/records/${encodeURIComponent(name)}`, this.options.url);\n\n // Add query parameters based on selection\n if (selection.name) {\n url.searchParams.set(\"name\", \"true\");\n }\n\n if (selection.addresses && selection.addresses.length > 0) {\n url.searchParams.set(\"addresses\", selection.addresses.join(\",\"));\n }\n\n if (selection.texts && selection.texts.length > 0) {\n url.searchParams.set(\"texts\", selection.texts.join(\",\"));\n }\n\n if (options?.trace) url.searchParams.set(\"trace\", \"true\");\n if (options?.accelerate) url.searchParams.set(\"accelerate\", \"true\");\n\n const response = await fetch(url);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw ClientError.fromErrorResponse(error);\n }\n\n const data = await response.json();\n return data as ResolveRecordsResponse<SELECTION>;\n }\n\n /**\n * Resolves the primary name of a specified address (Reverse Resolution) on a specific chain.\n *\n * If the `address` specifies a valid [ENSIP-19 Default Name](https://docs.ens.domains/ensip/19/#default-primary-name),\n * the Default Name will be returned. You _may_ query the Default EVM Chain Id (`0`) in order to\n * determine the `address`'s Default Name directly.\n *\n * The returned Primary Name, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name).\n * If the primary name set for the address is not normalized, `null` is returned as if no primary name was set.\n *\n * @param address The Address whose Primary Name to resolve\n * @param chainId The chain id within which to query the address' ENSIP-19 Multichain Primary Name\n * @param options additional options\n * @param options.accelerate whether to attempt Protocol Acceleration (default false)\n * @param options.trace whether to include a trace in the response (default false)\n * @returns ResolvePrimaryNameResponse\n * @throws If the request fails or the ENSNode API returns an error response\n *\n * @example\n * ```typescript\n * // Resolve the address' Primary Name on Ethereum Mainnet\n * const { name } = await client.resolvePrimaryName(\"0x179A862703a4adfb29896552DF9e307980D19285\", 1);\n * // name === 'gregskril.eth'\n *\n * // Resolve the address' Primary Name on Base\n * const { name } = await client.resolvePrimaryName(\"0x179A862703a4adfb29896552DF9e307980D19285\", 8453);\n * // name === 'greg.base.eth'\n *\n * // Resolve the address' Default Primary Name\n * const { name } = await client.resolvePrimaryName(\"0x179A862703a4adfb29896552DF9e307980D19285\", 0);\n * // name === 'gregskril.eth'\n * ```\n */\n async resolvePrimaryName(\n address: ResolvePrimaryNameRequest[\"address\"],\n chainId: ResolvePrimaryNameRequest[\"chainId\"],\n options?: Omit<ResolvePrimaryNameRequest, \"address\" | \"chainId\">,\n ): Promise<ResolvePrimaryNameResponse> {\n const url = new URL(`/api/resolve/primary-name/${address}/${chainId}`, this.options.url);\n\n if (options?.trace) url.searchParams.set(\"trace\", \"true\");\n if (options?.accelerate) url.searchParams.set(\"accelerate\", \"true\");\n\n const response = await fetch(url);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw ClientError.fromErrorResponse(error);\n }\n\n const data = await response.json();\n return data as ResolvePrimaryNameResponse;\n }\n\n /**\n * Resolves the primary names of a specified address across multiple chains.\n *\n * If the `address` specifies a valid [ENSIP-19 Default Name](https://docs.ens.domains/ensip/19/#default-primary-name),\n * the Default Name will be returned for all chainIds for which there is not a chain-specific\n * Primary Name. To avoid misuse, you _may not_ query the Default EVM Chain Id (`0`) directly, and\n * should rely on the aforementioned per-chain defaulting behavior.\n *\n * Each returned Primary Name, if set, is guaranteed to be a [Normalized Name](https://ensnode.io/docs/reference/terminology#normalized-name).\n * If the primary name set for the address on any chain is not normalized, `null` is returned for that chain as if no primary name was set.\n *\n * @param address The Address whose Primary Names to resolve\n * @param options additional options\n * @param options.chainIds The set of chain ids within which to query the address' ENSIP-19\n * Multichain Primary Name (default: all ENSIP-19 supported chains)\n * @param options.accelerate whether to attempt Protocol Acceleration (default: true)\n * @param options.trace whether to include a trace in the response (default: false)\n * @returns ResolvePrimaryNamesResponse\n * @throws If the request fails or the ENSNode API returns an error response\n *\n * @example\n * ```typescript\n * // Resolve the address' Primary Names on all ENSIP-19 supported chain ids\n * const { names } = await client.resolvePrimaryNames(\"0x179A862703a4adfb29896552DF9e307980D19285\");\n *\n * console.log(names);\n * // {\n * // \"1\": \"gregskril.eth\",\n * // \"10\": \"gregskril.eth\",\n * // \"8453\": \"greg.base.eth\", // base-specific Primary Name!\n * // \"42161\": \"gregskril.eth\",\n * // \"59144\": \"gregskril.eth\",\n * // \"534352\": \"gregskril.eth\"\n * // }\n *\n * // Resolve the address' Primary Names on specific chain Ids\n * const { names } = await client.resolvePrimaryNames(\"0xabcd...\", [1, 8453]);\n *\n * console.log(names);\n * // {\n * // \"1\": \"gregskril.eth\",\n * // \"8453\": \"greg.base.eth\", // base-specific Primary Name!\n * // }\n * ```\n */\n async resolvePrimaryNames(\n address: ResolvePrimaryNamesRequest[\"address\"],\n options?: Omit<ResolvePrimaryNamesRequest, \"address\">,\n ): Promise<ResolvePrimaryNamesResponse> {\n const url = new URL(`/api/resolve/primary-names/${address}`, this.options.url);\n\n if (options?.chainIds) url.searchParams.set(\"chainIds\", options.chainIds.join(\",\"));\n if (options?.trace) url.searchParams.set(\"trace\", \"true\");\n if (options?.accelerate) url.searchParams.set(\"accelerate\", \"true\");\n\n const response = await fetch(url);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw ClientError.fromErrorResponse(error);\n }\n\n const data = await response.json();\n return data as ResolvePrimaryNamesResponse;\n }\n\n /**\n * Fetch ENSNode Config\n *\n * Fetch the ENSNode's configuration.\n *\n * @returns {ConfigResponse}\n *\n * @throws if the ENSNode request fails\n * @throws if the ENSNode API returns an error response\n * @throws if the ENSNode response breaks required invariants\n */\n async config(): Promise<ConfigResponse> {\n const url = new URL(`/api/config`, this.options.url);\n\n const response = await fetch(url);\n\n let responseData: unknown;\n\n // ENSNode API should always allow parsing a response as JSON object.\n // If for some reason it's not the case, throw an error.\n try {\n responseData = await response.json();\n } catch {\n throw new Error(\"Malformed response data: invalid JSON\");\n }\n\n if (!response.ok) {\n const errorResponse = deserializeErrorResponse(responseData);\n throw new Error(`Fetching ENSNode Config Failed: ${errorResponse.message}`);\n }\n\n return deserializeENSIndexerPublicConfig(responseData as SerializedENSIndexerPublicConfig);\n }\n\n /**\n * Fetch ENSNode Indexing Status\n *\n * Fetch the ENSNode's multichain indexing status.\n *\n * @param options additional options\n * @param options.maxRealtimeDistance the max allowed distance between the\n * latest indexed block of each chain and the \"tip\" of all indexed chains.\n * Setting this parameter influences the HTTP response code as follows:\n * - Success (200 OK): The latest indexed block of each chain is within the\n * requested distance from realtime.\n * - Service Unavailable (503): The latest indexed block of each chain is NOT\n * within the requested distance from realtime.\n *\n * @returns {IndexingStatusResponse}\n *\n * @throws if the ENSNode request fails\n * @throws if the ENSNode API returns an error response\n * @throws if the ENSNode response breaks required invariants\n */\n async indexingStatus(options?: IndexingStatusRequest): Promise<IndexingStatusResponse> {\n const url = new URL(`/api/indexing-status`, this.options.url);\n\n if (typeof options?.maxRealtimeDistance !== \"undefined\") {\n url.searchParams.set(\"maxRealtimeDistance\", `${options.maxRealtimeDistance}`);\n }\n\n const response = await fetch(url);\n\n let responseData: unknown;\n\n // ENSNode API should always allow parsing a response as JSON object.\n // If for some reason it's not the case, throw an error.\n try {\n responseData = await response.json();\n } catch {\n throw new Error(\"Malformed response data: invalid JSON\");\n }\n\n // handle application errors accordingly\n if (!response.ok) {\n switch (response.status) {\n case IndexingStatusResponseCodes.IndexerError: {\n console.error(\"Indexing Status API: indexer error\");\n return deserializeENSIndexerIndexingStatus(\n responseData as SerializedENSIndexerOverallIndexingStatus,\n );\n }\n\n case IndexingStatusResponseCodes.RequestedDistanceNotAchievedError: {\n console.error(\n \"Indexing Status API: Requested realtime indexing distance not achieved error\",\n );\n return deserializeENSIndexerIndexingStatus(\n responseData as SerializedENSIndexerOverallIndexingStatus,\n );\n }\n\n default: {\n const errorResponse = deserializeErrorResponse(responseData);\n throw new Error(`Fetching ENSNode Indexing Status Failed: ${errorResponse.message}`);\n }\n }\n }\n\n return deserializeENSIndexerIndexingStatus(\n responseData as SerializedENSIndexerOverallIndexingStatus,\n );\n }\n}\n","import type { CoinType } from \"../ens\";\n\n/**\n * Encodes a selection of Resolver records in the context of a specific Name.\n */\nexport interface ResolverRecordsSelection {\n /**\n * Whether to fetch the name's `name` record. This value is primarily used in the context of\n * Reverse Resolution.\n *\n * @see https://docs.ens.domains/ensip/19/#reverse-resolution\n */\n name?: boolean;\n\n /**\n * Which coinTypes to fetch address records for.\n */\n addresses?: CoinType[];\n\n /**\n * Which keys to fetch text records for.\n */\n texts?: string[];\n\n // TODO: include others as/if necessary\n}\n\nexport const isSelectionEmpty = (selection: ResolverRecordsSelection) =>\n !selection.name && !selection.addresses?.length && !selection.texts?.length;\n","import {\n DatasourceNames,\n ENSNamespaceId,\n ENSNamespaceIds,\n maybeGetDatasource,\n} from \"@ensnode/datasources\";\nimport { ETH_COIN_TYPE, evmChainIdToCoinType } from \"../ens\";\nimport { uniq } from \"../shared\";\nimport type { ResolverRecordsSelection } from \"./resolver-records-selection\";\n\nconst getENSIP19SupportedCoinTypes = (namespace: ENSNamespaceId) =>\n uniq(\n [\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverBase),\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverLinea),\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverOptimism),\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverArbitrum),\n maybeGetDatasource(namespace, DatasourceNames.ReverseResolverScroll),\n ]\n .filter((ds) => ds !== undefined)\n .map((ds) => ds.chain.id),\n ).map(evmChainIdToCoinType);\n\nconst TEXTS = [\n \"url\",\n \"avatar\",\n \"header\",\n \"description\",\n \"email\",\n \"com.twitter\",\n \"com.farcaster\",\n \"com.github\",\n] as const satisfies string[];\n\nexport const DefaultRecordsSelection = {\n [ENSNamespaceIds.Mainnet]: {\n addresses: [ETH_COIN_TYPE, ...getENSIP19SupportedCoinTypes(ENSNamespaceIds.Mainnet)],\n texts: TEXTS,\n },\n [ENSNamespaceIds.Sepolia]: {\n addresses: [ETH_COIN_TYPE, ...getENSIP19SupportedCoinTypes(ENSNamespaceIds.Sepolia)],\n texts: TEXTS,\n },\n [ENSNamespaceIds.Holesky]: {\n addresses: [ETH_COIN_TYPE, ...getENSIP19SupportedCoinTypes(ENSNamespaceIds.Holesky)],\n texts: TEXTS,\n },\n [ENSNamespaceIds.EnsTestEnv]: {\n addresses: [ETH_COIN_TYPE, ...getENSIP19SupportedCoinTypes(ENSNamespaceIds.EnsTestEnv)],\n texts: TEXTS,\n },\n} as const satisfies Record<ENSNamespaceId, ResolverRecordsSelection>;\n"],"mappings":"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","names":["prettifyError","z","labelhash","labelhash","PluginName","z","prettifyError","isSubgraphCompatible","prettifyError","z","z","prettifyError","TraceableENSProtocol","ForwardResolutionProtocolStep","ReverseResolutionProtocolStep","prettifyError","z","prettifyError","ENSNamespaceIds","ENSNamespaceIds"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensnode/ensnode-sdk",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "type": "module",
5
5
  "description": "A utility library for interacting with ENSNode and ENS data",
6
6
  "license": "MIT",
@@ -36,12 +36,12 @@
36
36
  "typescript": "^5.7.3",
37
37
  "viem": "^2.22.13",
38
38
  "vitest": "^3.1.1",
39
- "@ensnode/shared-configs": "0.34.0"
39
+ "@ensnode/shared-configs": "0.35.0"
40
40
  },
41
41
  "dependencies": {
42
42
  "@ensdomains/address-encoder": "^1.1.2",
43
43
  "zod": "^3.25.7",
44
- "@ensnode/datasources": "0.34.0"
44
+ "@ensnode/datasources": "0.35.0"
45
45
  },
46
46
  "scripts": {
47
47
  "prepublish": "tsup",