diff --git a/docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts b/docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts
index bcfd7d91a..858db3b4e 100644
--- a/docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts
+++ b/docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts
@@ -119,22 +119,46 @@ export const integrateSidebarTopic = {
label: "Overview",
link: "/docs/integrate/unigraph",
},
+ {
+ label: "Core Concepts",
+ link: "/docs/integrate/unigraph/concepts",
+ },
{
label: "Examples",
collapsed: true,
items: [
{
- label: "Overview",
+ label: "Connect",
link: "/docs/integrate/unigraph/examples",
},
{
label: "Domain by Name",
link: "/docs/integrate/unigraph/examples/domain-by-name",
},
+ {
+ label: "Domain Fuzzy Search",
+ link: "/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name",
+ },
+ {
+ label: "Domain Events",
+ link: "/docs/integrate/unigraph/examples/domain-events",
+ },
+ {
+ label: "Subdomains",
+ link: "/docs/integrate/unigraph/examples/subdomains-by-parent-name",
+ },
{
label: "Account Domains",
link: "/docs/integrate/unigraph/examples/account-domains",
},
+ {
+ label: "Latest Registrations",
+ link: "/docs/integrate/unigraph/examples/latest-registrations",
+ },
+ {
+ label: "Expiring Registrations",
+ link: "/docs/integrate/unigraph/examples/expiring-registrations",
+ },
{
label: "Indexing Status",
link: "/docs/integrate/unigraph/examples/indexing-status",
@@ -180,7 +204,7 @@ export const integrateSidebarTopic = {
link: "/docs/integrate/integration-options/ensdb-readers",
},
{
- label: "ENSNode Plugins (data models)",
+ label: "ENSNode Plugins (Data Models)",
link: "/docs/integrate/integration-options/ensnode-plugins",
},
{
diff --git a/docs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astro b/docs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astro
index d1119a101..fa1781b67 100644
--- a/docs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astro
+++ b/docs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astro
@@ -7,5 +7,5 @@ import { Aside } from "@astrojs/starlight/components";
href="/docs/services/ensdb/concepts/glossary#ensdb-writer-schema"
>ensIndexerSchema
schema definition in the Connect section if you haven't already.
+ > in the Connect example if you haven't already.
diff --git a/docs/ensnode.io/src/components/molecules/EnsUnigraphIntro.astro b/docs/ensnode.io/src/components/molecules/EnsUnigraphIntro.astro
new file mode 100644
index 000000000..609f140bc
--- /dev/null
+++ b/docs/ensnode.io/src/components/molecules/EnsUnigraphIntro.astro
@@ -0,0 +1,9 @@
+---
+import { Aside } from "@astrojs/starlight/components";
+---
+
+
diff --git a/docs/ensnode.io/src/components/molecules/unigraph-static-example/UnigraphStaticExample.astro b/docs/ensnode.io/src/components/molecules/unigraph-static-example/UnigraphStaticExample.astro
index a4663d928..093a7e1f6 100644
--- a/docs/ensnode.io/src/components/molecules/unigraph-static-example/UnigraphStaticExample.astro
+++ b/docs/ensnode.io/src/components/molecules/unigraph-static-example/UnigraphStaticExample.astro
@@ -38,7 +38,7 @@ const defaultResultNote =
- {sql.resultNote ?? defaultResultNote}
+
@@ -54,8 +54,6 @@ const defaultResultNote =
-
- {ensDbSdk.resultNote ?? defaultResultNote}
-
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/index.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/index.mdx
index d34a04a3c..5308e2963 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/index.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/index.mdx
@@ -202,9 +202,9 @@ Same query: `address -> primary name -> forward profile` — via raw GraphQL wit
Beyond [`enssdk`](/docs/integrate/integration-options/enssdk), [`enskit`](/docs/integrate/integration-options/enskit), and the [Omnigraph GraphQL API](/docs/integrate/integration-options/omnigraph-graphql-api), ENSNode exposes a deeper set of integration surfaces for advanced use cases:
- **[ENSDb (SQL)](/docs/integrate/integration-options/ensdb)** — query the indexed ENSv1 and ENSv2 datasets directly via SQL for custom analytics or your own service layer, from any language with a Postgres driver.
-- **[ENSDb Writers (Indexers)](/docs/integrate/integration-options/ensdb-writers)** — build your own ENSDb Writer to index ENS data into your own ENSDb instance.
-- **[ENSDb Readers](/docs/integrate/integration-options/ensdb-readers)** — build your own ENSDb Reader to query your own ENSDb instance through any interface of your choice.
-- **[ENSNode Plugins](/docs/integrate/integration-options/ensnode-plugins)** — define how onchain data should be indexed into ENSDb.
+- **[ENSDb Writers (Indexers)](/docs/integrate/integration-options/ensdb-writers)** — enable all other layers of the ENSNode stack to build on your custom indexing engine.
+- **[ENSDb Readers (Custom APIs)](/docs/integrate/integration-options/ensdb-readers)** — build your own custom APIs and services on top of ENSDb using any programming language or framework.
+- **[ENSNode Plugins (Indexed Data Models)](/docs/integrate/integration-options/ensnode-plugins)** — define how onchain data should be indexed into ENSDb.
- **[enscli (CLI)](/docs/integrate/integration-options/enscli)** — resolve names, look up records, and run ad-hoc Omnigraph queries from the terminal — built for humans and AI agents alike.
- **[ensskills (AI agents)](/docs/integrate/integration-options/ensskills)** — a curated set of skills that gives AI coding agents a well-defined contract for working with ENS.
- **[ensdb-cli (ENSDb Snapshots)](/docs/integrate/integration-options/ensdb-cli)** — bootstrap a fresh ENSDb in minutes from portable, versioned snapshots instead of waiting days on a full historical backfill.
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/concepts.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/concepts.mdx
new file mode 100644
index 000000000..1b3aeac60
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/concepts.mdx
@@ -0,0 +1,47 @@
+---
+title: ENS Unigraph Core Concepts
+description: The core concepts behind the ENS Unigraph indexed data model.
+---
+
+## Indexed Data Model
+
+The ENS Unigraph indexed data model is available only when the [`unigraph` plugin](/docs/integrate/integration-options/ensnode-plugins#existing-plugins) is activated in your ENSNode instance.
+
+:::caution[`unigraph` plugin required]
+Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration) about activating [ENSNode Plugins](/docs/integrate/integration-options/ensnode-plugins).
+:::
+
+## Canonical Nametree
+
+The **Canonical Nametree** is the set of all Domains that have an inferrable **Canonical Name** — materialized from the namegraph. For every Domain in it, the canonical fields are populated — `canonical_name`, `canonical_path`, `canonical_node`, and `canonical_depth` — across both ENSv1 and ENSv2. That means you can look a name up by `canonical_name = 'vitalik.eth'`, order by `canonical_depth`, or walk a name's path **without branching by `type` on protocol version** and without traversing the namegraph yourself.
+
+Multichain coverage is part of the same model: Basenames (`.base.eth`), Lineanames (`.linea.eth`), and 3DNS names (`.box`) are materialized into the same Unigraph as mainnet `.eth`, so a single query spans every indexable name.
+
+:::danger[Not a substitute for ENS Resolution]
+The Unigraph mirrors onchain state; ENS's resolution-time behavior is applied _on top_ of it by
+[ENSApi](/docs/services/ensapi). A direct SQL read of resolver records is therefore **not**
+ENSIP-10 / CCIP-Read compliant and **cannot** be used as a source of truth for name resolution.
+For correct resolution, use the [ENS Omnigraph API](/docs/integrate/omnigraph) (which adds ENS
+Protocol Acceleration on top of the Unigraph). Use Unigraph SQL for analytics, discovery, and
+custom indexing.
+:::
+
+## Query optimizations
+
+### Domains
+
+A `canonical_name` can be very long, as it's the full, correct name. Due to limitations in Postgres btree indexes, the `domains` table has the `canonical_name` column and also the `__canonical_name_prefix` column (the first 64 code points of `canonical_name`, backed by a GIN trigram index).
+
+:::tip[Searching vs. displaying]
+Always **select and display `canonical_name`**. When you need to **search** by prefix (`ILIKE 'vit%'`, case-insensitive to match the Omnigraph `starts_with` filter), match against the materialized `__canonical_name_prefix` column (the first 64 code points of `canonical_name`, backed by a GIN trigram index) so the `ILIKE` filter is index-backed:
+
+```sql
+SELECT id, type, canonical_name, canonical_node, owner_id
+FROM ensindexer_0.domains
+WHERE __canonical_name_prefix ILIKE 'vit%'
+ORDER BY __canonical_name_prefix
+LIMIT 10;
+```
+
+The `SELECT` still returns `canonical_name`; only the `ILIKE` / `ORDER BY` use the prefix. The GIN trigram index backs the `ILIKE` filter; the `ORDER BY` then sorts the matched set (cheap under a small `LIMIT`) — scope the query by `registry_id` to use the `(registry_id, __canonical_name_prefix, id)` btree for fully index-backed ordering. For exact matches, use `canonical_name` directly (`canonical_name = 'vitalik.eth'`).
+:::
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdx
index c157b6595..5df936b4b 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdx
@@ -8,47 +8,13 @@ sidebar:
import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleAccountDomains } from "@data/unigraph-examples/account-domains";
-export const resultJson = [
- {
- type: "ENSv1Domain",
- count: 2
- },
- {
- type: "ENSv2Domain",
- count: 14
- }
-];
-
-export const sqlExampleSnippet = `SELECT type, count(*) FROM ensindexer_0.domains
-WHERE owner_id = '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
-GROUP BY type;
-`;
-
-export const tsExampleSnippet = `import { count, eq } from "drizzle-orm";
-
-const counts = await ensDb
-\t.select({ type: ensIndexerSchema.domain.type, count: count() })
-\t.from(ensIndexerSchema.domain)
-\t.where(eq(ensIndexerSchema.domain.ownerId, "0x70997970c51812dc3a010c7d01b50e0d17dc79c8"))
-\t.groupBy(ensIndexerSchema.domain.type);
-`
-
-:::caution[`unigraph` plugin required]
-Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
-:::
-
-Count the Domains owned by an address, grouped by Domain `type` (`ENSv1Domain` vs `ENSv2Domain`) — a single query spanning both protocol versions. See [Connect](/docs/integrate/unigraph/examples) for setup.
+Fetch the Domains owned by an address (across both ENSv1 and ENSv2), including each Domain's `type` (`ENSv1Domain` vs `ENSv2Domain`). See [Connect](/docs/integrate/unigraph/examples) for setup.
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdx
index bc80cedd1..c78c73529 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdx
@@ -8,79 +8,14 @@ sidebar:
import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
-
-export const unigraphSqlResultJson = [
- {
- id: "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
- type: "ENSv1Domain",
- canonical_name: "vitalik.eth",
- canonical_node: "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
- owner_id: "0x220866b1a2219f40e72f5c628b65d54268ca3a9d",
- },
-];
-
-export const ensDbSdkResultJson = [
- {
- id: "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
- type: "ENSv1Domain",
- canonicalName: "vitalik.eth",
- canonicalNode: "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
- ownerId: "0x220866b1a2219f40e72f5c628b65d54268ca3a9d",
- },
-];
-
-export const sqlExampleSnippet = `SELECT
- id,
- type,
- canonical_name,
- canonical_node,
- owner_id
-FROM ensindexer_0.domains
-WHERE canonical_name = 'vitalik.eth';`
-
-export const tsExampleSnippet = `import { eq } from "drizzle-orm";
-
-const [vitalik] = await ensDb
-\t.select({
-\t\tid: ensIndexerSchema.domain.id,
-\t\ttype: ensIndexerSchema.domain.type,
-\t\tcanonicalName: ensIndexerSchema.domain.canonicalName,
-\t\tcanonicalNode: ensIndexerSchema.domain.canonicalNode,
-\t\townerId: ensIndexerSchema.domain.ownerId,
-\t})
-\t.from(ensIndexerSchema.domain)
-\t.where(eq(ensIndexerSchema.domain.canonicalName, "vitalik.eth"));
-
-console.log(vitalik);`
-
-:::caution[`unigraph` plugin required]
-Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
-:::
+import { exampleDomainByName } from "@data/unigraph-examples/domain-by-name";
Fetch a Domain by its canonical name. Because `canonical_name` is materialized across both ENSv1 and ENSv2, the same lookup works regardless of protocol version. See [Connect](/docs/integrate/unigraph/examples) for setup.
-:::tip[Searching vs. displaying]
-A `canonical_name` can be very long, but it's the full, correct name — always **select and display `canonical_name`**. When you need to **search** by prefix (`ILIKE 'vit%'`, case-insensitive to match the Omnigraph `starts_with` filter), match against the materialized `__canonical_name_prefix` column (the first 64 code points of `canonical_name`, backed by a GIN trigram index) so the `ILIKE` filter is index-backed:
-
-```sql
-SELECT id, type, canonical_name, canonical_node, owner_id
-FROM ensindexer_0.domains
-WHERE __canonical_name_prefix ILIKE 'vit%'
-ORDER BY __canonical_name_prefix
-LIMIT 10;
-```
-
-The `SELECT` still returns `canonical_name`; only the `ILIKE` / `ORDER BY` use the prefix. The GIN trigram index backs the `ILIKE` filter; the `ORDER BY` then sorts the matched set (cheap under a small `LIMIT`) — scope the query by `registry_id` to use the `(registry_id, __canonical_name_prefix, id)` btree for fully index-backed ordering. For exact matches, use `canonical_name` directly (`canonical_name = 'vitalik.eth'`).
-:::
-
-:::note[Canonical fields]
-Canonical fields are populated on every Domain reachable from the canonical root, across both ENSv1 and ENSv2 — query them uniformly without branching by `type`. In SQL, these columns are `canonical_name`, `canonical_path`, `canonical_node`, and `canonical_depth`; in `ensdb-sdk`, the corresponding fields are `canonicalName`, `canonicalPath`, `canonicalNode`, and `canonicalDepth`.
-:::
-
-
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdx
new file mode 100644
index 000000000..5ed2a204f
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdx
@@ -0,0 +1,27 @@
+---
+title: Domain Events
+description: Fetch recent events for a Domain from the ENS Unigraph by its canonical name.
+sidebar:
+ label: Domain Events
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleDomainEvents } from "@data/unigraph-examples/domain-events";
+
+Fetch recent events for a Domain by its canonical name. This example joins the `events`, `domain_events`, and `domains` tables to retrieve domain events associated with the `vitalik.eth` name. See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+:::caution[Raw event data]
+The `events` table contains low-level onchain event data, which may require additional processing to interpret. For example, the `data` field is a hex string of ABI-encoded event data that may need to be decoded based on the event type (see `selector` field) to extract meaningful details about the event.
+
+In the future, the ENS Unigraph may include data referencing higher-level event types (e.g., `DomainRegistered`, `DomainTransferred`, etc.) to simplify querying for common events without needing to parse raw event data. For now, use `selector`, `topics`, and `data` fields in the `events` table to filter and interpret events based on your app's needs.
+:::
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name.mdx
new file mode 100644
index 000000000..5cfd9e968
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name.mdx
@@ -0,0 +1,21 @@
+---
+title: Fuzzy Search for ENS Names
+description: Perform a fuzzy search for ENS names.
+sidebar:
+ label: Fuzzy Search
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleDomainsFuzzySearchByName } from "@data/unigraph-examples/domains-fuzzy-search-by-name";
+
+Fetch Domains with names similar to a query string, ranked by similarity. This example uses PostgreSQL's `pg_trgm` extension, which provides the `%` operator for fuzzy matching and the `similarity()` function for ranking results. See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdx
new file mode 100644
index 000000000..f724c58a0
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdx
@@ -0,0 +1,21 @@
+---
+title: Expiring ENS Registrations
+description: Fetch ENS registrations that are about to expire.
+sidebar:
+ label: Expiring Registrations
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleExpiringRegistrations } from "@data/unigraph-examples/expiring-registrations";
+
+Fetch Domains with registrations expiring within a certain timeframe. This example uses a simple `WHERE` clause to filter for Domains with `expiry` between the current time and a specified future time (e.g., 3 days from now). See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/index.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/index.mdx
index c424eedcd..c1d702ddc 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/index.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/index.mdx
@@ -5,9 +5,10 @@ sidebar:
label: Overview
---
-import { LinkCard, Aside } from "@astrojs/starlight/components";
+import { CardGrid, LinkCard, Aside } from "@astrojs/starlight/components";
import Pill from "@components/atoms/Pill.astro";
import SqlResultTable from "@components/molecules/SqlResultTable.astro";
+import UnigraphIntro from "@components/molecules/EnsUnigraphIntro.astro";
import UnigraphExampleWrapper from "@components/molecules/unigraph-static-example/UnigraphExampleWrapper.astro";
import UnigraphExampleSQLTab from "@components/molecules/unigraph-static-example/UnigraphExampleSQLTab.astro";
import UnigraphExampleEnsDbSdkTab from "@components/molecules/unigraph-static-example/UnigraphExampleEnsDbSdkTab.astro";
@@ -46,15 +47,11 @@ export const bashSdkInstallSnippet = `npm install @ensnode/ensdb-sdk`;
These examples show the same queries two ways: in **raw SQL** (any PostgreSQL client, any language) and with the typed **[`@ensnode/ensdb-sdk`](https://www.npmjs.com/package/@ensnode/ensdb-sdk)** for TypeScript projects.
-SQL access requires connecting to your own [self-hosted](/docs/self-host) ENSDb instance.
-
-:::caution[`unigraph` plugin required]
-Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
-:::
+
## Connect
-The Unigraph lives in [ENSDb](/docs/services/ensdb), a PostgreSQL database. Each [ENSDb Writer](/docs/services/ensdb/concepts/glossary#ensdb-writer) instance writes to its own **ENSDb Writer Schema** (e.g. `ensindexer_0`). Each instance of [ENSDb Metadata Writer](/docs/services/ensdb/concepts/glossary#ensdb-metadata-writer) writes to a shared operational [metadata table](/docs/services/ensdb/concepts/glossary#ensnode-metadata-table) in the [`ensnode` schema](/docs/services/ensdb/concepts/glossary#ensnode-schema).
+The ENS Unigraph lives in [ENSDb](/docs/services/ensdb), a PostgreSQL database. Each [ENSDb Writer](/docs/services/ensdb/concepts/glossary#ensdb-writer) instance writes to its own **ENSDb Writer Schema** (e.g. `ensindexer_0`). Each instance of [ENSDb Metadata Writer](/docs/services/ensdb/concepts/glossary#ensdb-metadata-writer) writes to a shared operational [metadata table](/docs/services/ensdb/concepts/glossary#ensnode-metadata-table) in the [`ensnode` schema](/docs/services/ensdb/concepts/glossary#ensnode-schema).
@@ -103,6 +100,13 @@ The Unigraph lives in [ENSDb](/docs/services/ensdb), a PostgreSQL database. Each
## Examples
-
-
-
+Here are some example queries to get you started. Each example is available in raw SQL and with the `ensdb-sdk` for TypeScript projects.
+
+See each example's page for details on the query and how to run it against your ENSDb instance.
+
+
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdx
index 000984ac8..69b538e94 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdx
@@ -1,6 +1,6 @@
---
title: Indexing Status
-description: Read the indexing status snapshot for an ENSIndexer instance from ENSDb.
+description: Read the indexing status snapshot for an ENSDb Writer instance from ENSDb.
sidebar:
label: Indexing Status
---
@@ -8,141 +8,13 @@ sidebar:
import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
import EnsNodeSchemaIntro from "@components/molecules/EnsNodeSchemaIntro.astro";
import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleIndexingStatus } from "@data/unigraph-examples/indexing-status";
-export const ensDbSdkResultJson = {
- indexingStatus: {
- strategy: "omnichain",
- snapshotTime: 1779795066,
- omnichainSnapshot: {
- chains: {
- 1: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 3327417,
- timestamp: 1489165544,
- },
- },
- chainStatus: "chain-backfill",
- backfillEndBlock: {
- number: 25171597,
- timestamp: 1779703391,
- },
- latestIndexedBlock: {
- number: 21224717,
- timestamp: 1732054691,
- },
- },
- 10: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 110393959,
- timestamp: 1696386695,
- },
- },
- chainStatus: "chain-backfill",
- backfillEndBlock: {
- number: 152052671,
- timestamp: 1779704119,
- },
- latestIndexedBlock: {
- number: 128226309,
- timestamp: 1732051395,
- },
- },
- 8453: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 17522624,
- timestamp: 1721834595,
- },
- },
- chainStatus: "chain-backfill",
- backfillEndBlock: {
- number: 46457386,
- timestamp: 1779704119,
- },
- latestIndexedBlock: {
- number: 22632818,
- timestamp: 1732054983,
- },
- },
- 42161: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 349263357,
- timestamp: 1750406457,
- },
- },
- chainStatus: "chain-queued",
- },
- 59144: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 6682888,
- timestamp: 1720768992,
- },
- },
- chainStatus: "chain-backfill",
- backfillEndBlock: {
- number: 30774477,
- timestamp: 1779703911,
- },
- latestIndexedBlock: {
- number: 12280006,
- timestamp: 1732054967,
- },
- },
- 534352: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 16604272,
- timestamp: 1750406415,
- },
- },
- chainStatus: "chain-queued",
- },
- },
- omnichainStatus: "omnichain-backfill",
- omnichainIndexingCursor: 1732054983,
- },
- slowestChainIndexingCursor: 1732054983,
- }
-}
-
-export const unigraphSqlResultJson = {
- indexing_status_snapshot: ensDbSdkResultJson.indexingStatus,
-};
-
-export const sqlExampleSnippet = `-- Indexing status snapshot for the \`ensindexer_0\` ENSIndexer Schema
-SELECT value -> 'indexingStatus' as indexing_status_snapshot
-FROM ensnode.metadata
-WHERE ens_indexer_schema_name = 'ensindexer_0'
-AND key = 'indexing_metadata_context';
-`;
-
-export const tsExampleSnippet = `import { IndexingMetadataContextStatusCodes } from "@ensnode/ensdb-sdk";
-
-const indexingMetadataContext = await ensDbReader.getIndexingMetadataContext();
-if (indexingMetadataContext.statusCode === IndexingMetadataContextStatusCodes.Initialized) {
-\tconst { indexingStatus } = indexingMetadataContext;
-\tconsole.log({ indexingStatus });
-}`;
-
-:::caution[`unigraph` plugin required]
-Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
-:::
-
-Read the indexing status snapshot for an ENSIndexer instance from the shared `ensnode.metadata` table. See [Connect](/docs/integrate/unigraph/examples) for setup.
+Read the indexing status snapshot for an ENSDb Writer instance from the shared `ensnode.metadata` table. See [Connect](/docs/integrate/unigraph/examples) for setup.
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/latest-registrations.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/latest-registrations.mdx
new file mode 100644
index 000000000..5add162fd
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/latest-registrations.mdx
@@ -0,0 +1,21 @@
+---
+title: Latest ENS Registrations
+description: Fetch the latest ENS registrations.
+sidebar:
+ label: Latest Registrations
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleLatestRegistrations } from "@data/unigraph-examples/latest-registrations";
+
+Fetch the latest registrations and their associated Domains. See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/subdomains-by-parent-name.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/subdomains-by-parent-name.mdx
new file mode 100644
index 000000000..ced9f3aaf
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/subdomains-by-parent-name.mdx
@@ -0,0 +1,21 @@
+---
+title: Subdomains
+description: Subdomains under an ENS name.
+sidebar:
+ label: Subdomains
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleSubdomainsByParentName } from "@data/unigraph-examples/subdomains-by-parent-name";
+
+Get a list of subdomains for the `eth` domain, including their Domain `type` (`ENSv1Domain` vs `ENSv2Domain`) — a single query spanning both protocol versions. See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/index.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/index.mdx
index 3fe93d120..d19c84a43 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/index.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/index.mdx
@@ -30,37 +30,26 @@ The Unigraph models both protocol versions with the **same polymorphic entities*
- **Label** — the `labelHash` → label mapping that heals hashed labels into human-readable names.
- **Permissions** — the ENSv2 roles model for who can do what in a specific contract.
-## The Canonical Nametree
-
-:::note[The Canonical Nametree]
-The **Canonical Nametree** is the set of all Domains that have an inferrable **Canonical Name** — materialized from the namegraph. For every Domain in it, the canonical fields are populated — `canonical_name`, `canonical_path`, `canonical_node`, and `canonical_depth` — across both ENSv1 and ENSv2. That means you can look a name up by `canonical_name = 'vitalik.eth'`, order by `canonical_depth`, or walk a name's path **without branching on protocol version** and without traversing the namegraph yourself.
-:::
-
-Multichain coverage is part of the same model: Basenames (`.base.eth`), Lineanames (`.linea.eth`), and 3DNS names (`.box`) are materialized into the same Unigraph as mainnet `.eth`, so a single query spans every indexable name.
-
-
-
## Get started
+
+
-
+
\`similarity(\${ensIndexerSchema.domain.canonicalName}, \${q})\`.as(
+ "name_similarity",
+ ),
+ id: ensIndexerSchema.domain.id,
+ })
+ .from(ensIndexerSchema.domain)
+ .where(
+ and(
+ sql\`\${ensIndexerSchema.domain.__canonicalNamePrefix} % \${q}\`,
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ )
+ .orderBy(
+ desc(sql\`name_similarity\`),
+ asc(sql\`LENGTH(\${ensIndexerSchema.domain.canonicalName})\`),
+ )
+ .limit(limit);
+
+console.log(domains);`,
+ result: [
+ {
+ type: "ENSv1Domain",
+ canonicalName: "vitalik.id",
+ canonicalNode: "0xaf3232eb15e694ef5b9107cd2659c9ea75e7c74b59db776ce6be7df6d1131287",
+ ownerId: "0x62f4706c61a7b3bf6db74faff7e5e48ac1e004a5",
+ nameSimilarity: 0.72727275,
+ id: "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xaf3232eb15e694ef5b9107cd2659c9ea75e7c74b59db776ce6be7df6d1131287",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "vitalik.eth",
+ canonicalNode: "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
+ ownerId: "0x220866b1a2219f40e72f5c628b65d54268ca3a9d",
+ nameSimilarity: 0.6666667,
+ id: "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "🚀vitalik.eth",
+ canonicalNode: "0x2eaf5dba5efa24eb33e59cfeb1ada63bce28966d82896f8358a5b7e0cd33c0fb",
+ ownerId: "0x7dcb9d6e9ecfb03a275dc4864c812dd09a1768a2",
+ nameSimilarity: 0.6666667,
+ id: "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x2eaf5dba5efa24eb33e59cfeb1ada63bce28966d82896f8358a5b7e0cd33c0fb",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "❤vitalik.eth",
+ canonicalNode: "0xedad39bf146ed24b42e93f8579ae318df3bc925a38d66aef6af87ae91cb1b064",
+ ownerId: "0x8cd59e8486a0d57bd95ce467f561f0d13293a0be",
+ nameSimilarity: 0.6666667,
+ id: "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xedad39bf146ed24b42e93f8579ae318df3bc925a38d66aef6af87ae91cb1b064",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "vitalik😂.eth",
+ canonicalNode: "0x4771060c6bcc732384b8a5969ef56d1b085d47f93bb67af828a1bfcacf00c79a",
+ ownerId: "0x4c54c8c65789ed2d77b948f9aa9482daa6b4a582",
+ nameSimilarity: 0.6666667,
+ id: "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x4771060c6bcc732384b8a5969ef56d1b085d47f93bb67af828a1bfcacf00c79a",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/expiring-registrations.ts b/docs/ensnode.io/src/data/unigraph-examples/expiring-registrations.ts
new file mode 100644
index 000000000..f846b504c
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/expiring-registrations.ts
@@ -0,0 +1,173 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("Alpha");
+
+/**
+ * Example query for fetching ENS registrations that are expiring soon.
+ */
+export const exampleExpiringRegistrations = {
+ sql: {
+ codeSnippet: `SELECT
+ d.canonical_name,
+ r.start,
+ r.expiry,
+ r.grace_period,
+ d.owner_id,
+ d.id as domain_id
+FROM "ensindexer_0".registrations r
+JOIN "ensindexer_0".latest_registration_index lri
+ ON r.domain_id = lri.domain_id
+ AND r.registration_index = lri.registration_index
+JOIN "ensindexer_0".domains d ON r.domain_id = d.id
+WHERE r.expiry >= EXTRACT(EPOCH FROM NOW())
+ AND r.expiry <= EXTRACT(EPOCH FROM NOW() + INTERVAL '3 days')
+ AND d.canonical = true
+ORDER BY r.expiry ASC
+LIMIT 5;
+`,
+ result: [
+ {
+ canonical_name: "artea.eth",
+ start: "1686405839",
+ expiry: "1781013839",
+ grace_period: "7776000",
+ owner_id: "0xcd421e50f622ce64b34be68195ca955b8bfd87c9",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x66c0bb79871615383d8dfda2db33e11bf7bce500296cdf744c02ed002dd34fbe",
+ },
+ {
+ canonical_name: "happydad.eth",
+ start: "1623291951",
+ expiry: "1781013855",
+ grace_period: "7776000",
+ owner_id: "0x4e2da5a0f339bbb8044911289db6fc856b96ceb8",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xf193ccd69a8f1aa4f9a8db9436eaf72a76485f3326a8035282c2798b50f15f7a",
+ },
+ {
+ canonical_name: "00h08.eth",
+ start: "1749477923",
+ expiry: "1781013923",
+ grace_period: "7776000",
+ owner_id: "0xd6f7483334dabfc269b6593404937ac47d8c14b7",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xfa69df157ceade1a0096790f985146fa8c4d739d53c0b5d19e9e3b91b1e69b20",
+ },
+ {
+ canonical_name: "saasnft.eth",
+ start: "1654786180",
+ expiry: "1781013988",
+ grace_period: "7776000",
+ owner_id: "0x2fb477bf0db48926ca59d9d34c72424524cb9d51",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x317489d1004fe21a7c3377f67d47fa476890e73acbf96377e12fa1b0597460b0",
+ },
+ {
+ canonical_name: "agris.eth",
+ start: "1654786368",
+ expiry: "1781014176",
+ grace_period: "7776000",
+ owner_id: "0xd26481ac94175b074f58900baf0dd0e597e8cf96",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x0a8c71787f5029e883e4ce6aa20b35d7c29599b9658d92f8c44d48fdf09aeda3",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, asc, eq, gte, lte, sql } from "drizzle-orm";
+
+const limit = 5;
+
+const expiringRegistrations = await ensDb
+ .select({
+ canonicalName: ensIndexerSchema.domain.canonicalName,
+ expiry: ensIndexerSchema.registration.expiry,
+ start: ensIndexerSchema.registration.start,
+ gracePeriod: ensIndexerSchema.registration.gracePeriod,
+ ownerId: ensIndexerSchema.domain.ownerId,
+ domainId: ensIndexerSchema.domain.id,
+ })
+ .from(ensIndexerSchema.registration)
+ .innerJoin(
+ ensIndexerSchema.latestRegistrationIndex,
+ and(
+ eq(
+ ensIndexerSchema.registration.domainId,
+ ensIndexerSchema.latestRegistrationIndex.domainId,
+ ),
+ eq(
+ ensIndexerSchema.registration.registrationIndex,
+ ensIndexerSchema.latestRegistrationIndex.registrationIndex,
+ ),
+ ),
+ )
+ .innerJoin(
+ ensIndexerSchema.domain,
+ eq(ensIndexerSchema.registration.domainId, ensIndexerSchema.domain.id),
+ )
+ .where(
+ and(
+ gte(ensIndexerSchema.registration.expiry, sql\`EXTRACT(EPOCH FROM NOW())\`),
+ lte(
+ ensIndexerSchema.registration.expiry,
+ sql\`EXTRACT(EPOCH FROM NOW() + INTERVAL '3 days')\`,
+ ),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ )
+ .orderBy(asc(ensIndexerSchema.registration.expiry))
+ .limit(limit);
+
+console.log(expiringRegistrations);`,
+ result: [
+ {
+ canonicalName: "artea.eth",
+ expiry: "1781013839",
+ start: "1686405839",
+ gracePeriod: "7776000",
+ ownerId: "0xcd421e50f622ce64b34be68195ca955b8bfd87c9",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x66c0bb79871615383d8dfda2db33e11bf7bce500296cdf744c02ed002dd34fbe",
+ },
+ {
+ canonicalName: "happydad.eth",
+ expiry: "1781013855",
+ start: "1623291951",
+ gracePeriod: "7776000",
+ ownerId: "0x4e2da5a0f339bbb8044911289db6fc856b96ceb8",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xf193ccd69a8f1aa4f9a8db9436eaf72a76485f3326a8035282c2798b50f15f7a",
+ },
+ {
+ canonicalName: "00h08.eth",
+ expiry: "1781013923",
+ start: "1749477923",
+ gracePeriod: "7776000",
+ ownerId: "0xd6f7483334dabfc269b6593404937ac47d8c14b7",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xfa69df157ceade1a0096790f985146fa8c4d739d53c0b5d19e9e3b91b1e69b20",
+ },
+ {
+ canonicalName: "saasnft.eth",
+ expiry: "1781013988",
+ start: "1654786180",
+ gracePeriod: "7776000",
+ ownerId: "0x2fb477bf0db48926ca59d9d34c72424524cb9d51",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x317489d1004fe21a7c3377f67d47fa476890e73acbf96377e12fa1b0597460b0",
+ },
+ {
+ canonicalName: "agris.eth",
+ expiry: "1781014176",
+ start: "1654786368",
+ gracePeriod: "7776000",
+ ownerId: "0xd26481ac94175b074f58900baf0dd0e597e8cf96",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x0a8c71787f5029e883e4ce6aa20b35d7c29599b9658d92f8c44d48fdf09aeda3",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/indexing-status.ts b/docs/ensnode.io/src/data/unigraph-examples/indexing-status.ts
new file mode 100644
index 000000000..a8aee98fe
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/indexing-status.ts
@@ -0,0 +1,137 @@
+import { outputSource } from "@data/unigraph-examples/utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("Alpha");
+
+const indexingMetadataContextPartial = {
+ indexingStatus: {
+ strategy: "omnichain",
+ snapshotTime: 1779795066,
+ omnichainSnapshot: {
+ chains: {
+ 1: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 3327417,
+ timestamp: 1489165544,
+ },
+ },
+ chainStatus: "chain-backfill",
+ backfillEndBlock: {
+ number: 25171597,
+ timestamp: 1779703391,
+ },
+ latestIndexedBlock: {
+ number: 21224717,
+ timestamp: 1732054691,
+ },
+ },
+ 10: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 110393959,
+ timestamp: 1696386695,
+ },
+ },
+ chainStatus: "chain-backfill",
+ backfillEndBlock: {
+ number: 152052671,
+ timestamp: 1779704119,
+ },
+ latestIndexedBlock: {
+ number: 128226309,
+ timestamp: 1732051395,
+ },
+ },
+ 8453: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 17522624,
+ timestamp: 1721834595,
+ },
+ },
+ chainStatus: "chain-backfill",
+ backfillEndBlock: {
+ number: 46457386,
+ timestamp: 1779704119,
+ },
+ latestIndexedBlock: {
+ number: 22632818,
+ timestamp: 1732054983,
+ },
+ },
+ 42161: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 349263357,
+ timestamp: 1750406457,
+ },
+ },
+ chainStatus: "chain-queued",
+ },
+ 59144: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 6682888,
+ timestamp: 1720768992,
+ },
+ },
+ chainStatus: "chain-backfill",
+ backfillEndBlock: {
+ number: 30774477,
+ timestamp: 1779703911,
+ },
+ latestIndexedBlock: {
+ number: 12280006,
+ timestamp: 1732054967,
+ },
+ },
+ 534352: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 16604272,
+ timestamp: 1750406415,
+ },
+ },
+ chainStatus: "chain-queued",
+ },
+ },
+ omnichainStatus: "omnichain-backfill",
+ omnichainIndexingCursor: 1732054983,
+ },
+ slowestChainIndexingCursor: 1732054983,
+ },
+} as const;
+
+/**
+ * Example query for fetching the indexing status snapshot of an ENSDb Writer
+ */
+export const exampleIndexingStatus = {
+ sql: {
+ codeSnippet: `SELECT value -> 'indexingStatus' as indexing_status_snapshot
+FROM "ensnode".metadata
+WHERE ens_indexer_schema_name = 'ensindexer_0'
+AND key = 'indexing_metadata_context';
+`,
+ result: { indexing_status_snapshot: indexingMetadataContextPartial.indexingStatus },
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { IndexingMetadataContextStatusCodes } from "@ensnode/ensdb-sdk";
+
+const indexingMetadataContext = await ensDbReader.getIndexingMetadataContext();
+
+if (indexingMetadataContext.statusCode === IndexingMetadataContextStatusCodes.Initialized) {
+ const { indexingStatus } = indexingMetadataContext;
+ console.log({ indexingStatus });
+}`,
+ result: { indexingStatus: indexingMetadataContextPartial.indexingStatus },
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts b/docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts
new file mode 100644
index 000000000..e85c07d87
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts
@@ -0,0 +1,182 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("Alpha Sepolia");
+
+/**
+ * Example query for fetching the latest registrations across all Domains.
+ */
+export const exampleLatestRegistrations = {
+ sql: {
+ codeSnippet: `SELECT
+ d.canonical_name,
+ r.start,
+ r.expiry,
+ r.grace_period,
+ r.type as registration_type,
+ d.owner_id,
+ d.id as domain_id
+FROM "ensindexer_0".registrations r
+JOIN "ensindexer_0".latest_registration_index lri
+ ON r.domain_id = lri.domain_id
+ AND r.registration_index = lri.registration_index
+JOIN "ensindexer_0".domains d ON r.domain_id = d.id
+WHERE r.start <= EXTRACT(EPOCH FROM NOW())
+ AND d.canonical = true
+ AND r.type <> 'NameWrapper'
+ORDER BY r.start DESC
+LIMIT 5;
+`,
+ result: [
+ {
+ canonical_name: "karsten.base.eth",
+ start: "1762698085",
+ expiry: "1794234086",
+ grace_period: "7776000",
+ registration_type: "BaseRegistrar",
+ owner_id: "0x2426bd7d89230ce5cd4015c47811445b8a6c8f0b",
+ domain_id:
+ "8453-0xb94704422c2a1e396835a571837aa5ae53285a95-0xa0cf65983e0b8f2363aaac795c5844c44131ce0b94568e57fcb5e2e5115a87e3",
+ },
+ {
+ canonical_name: "urolinkfu.base.eth",
+ start: "1762698015",
+ expiry: "1794234016",
+ grace_period: "7776000",
+ registration_type: "BaseRegistrar",
+ owner_id: "0x66c52ecef41ee67119cfbcaf88d2097ec1eec5f0",
+ domain_id:
+ "8453-0xb94704422c2a1e396835a571837aa5ae53285a95-0x1be1354816d460696b36c96b2fa75e3f1fbed97e95720603553d513724d1e233",
+ },
+ {
+ canonical_name: "quantumrepeater.eth",
+ start: "1762697939",
+ expiry: "1794233939",
+ grace_period: "7776000",
+ registration_type: "BaseRegistrar",
+ owner_id: "0x53e1c07bf0282e84fd5b600b2b1f90e8bc14d4f1",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xd06fb94af8abfbe4cfe0a6f5fed589ce5bae7a28bd0347241d0903b3d9893233",
+ },
+ {
+ canonical_name: "spirich.base.eth",
+ start: "1762697929",
+ expiry: "1794233930",
+ grace_period: "7776000",
+ registration_type: "BaseRegistrar",
+ owner_id: "0xe46bc24cd3c5f2f73e8604b994d18675c64e0019",
+ domain_id:
+ "8453-0xb94704422c2a1e396835a571837aa5ae53285a95-0x94f8855a549a1ba319531b8acb1d0130b6ec095bf27e0de3b84e05207a2b154e",
+ },
+ {
+ canonical_name: "hexiuling3.base.eth",
+ start: "1762697917",
+ expiry: "1794255517",
+ grace_period: "7776000",
+ registration_type: "BaseRegistrar",
+ owner_id: "0x4b2945016ef05155863723cf07740b2d25d5db19",
+ domain_id:
+ "8453-0xb94704422c2a1e396835a571837aa5ae53285a95-0x0944dfcb1ef210d64d6ac38637c57012fa356831d58d31a6ecc9d18484668cd7",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, desc, eq, ne, lte, sql } from "drizzle-orm";
+
+const limit = 5;
+
+const recentRegistrations = await ensDb
+ .select({
+ canonicalName: ensIndexerSchema.domain.canonicalName,
+ start: ensIndexerSchema.registration.start,
+ expiry: ensIndexerSchema.registration.expiry,
+ gracePeriod: ensIndexerSchema.registration.gracePeriod,
+ registrationType: ensIndexerSchema.registration.type,
+ ownerId: ensIndexerSchema.domain.ownerId,
+ domainId: ensIndexerSchema.domain.id,
+ })
+ .from(ensIndexerSchema.registration)
+ .innerJoin(
+ ensIndexerSchema.latestRegistrationIndex,
+ and(
+ eq(
+ ensIndexerSchema.registration.domainId,
+ ensIndexerSchema.latestRegistrationIndex.domainId,
+ ),
+ eq(
+ ensIndexerSchema.registration.registrationIndex,
+ ensIndexerSchema.latestRegistrationIndex.registrationIndex,
+ ),
+ ),
+ )
+ .innerJoin(
+ ensIndexerSchema.domain,
+ eq(ensIndexerSchema.registration.domainId, ensIndexerSchema.domain.id),
+ )
+ .where(
+ and(
+ lte(ensIndexerSchema.registration.start, sql\`EXTRACT(EPOCH FROM NOW())\`),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ne(ensIndexerSchema.registration.type, "NameWrapper"),
+ ),
+ )
+ .orderBy(desc(ensIndexerSchema.registration.start))
+ .limit(limit);
+
+console.log(recentRegistrations);`,
+ result: [
+ {
+ canonicalName: "karsten.base.eth",
+ start: "1762698085",
+ expiry: "1794234086",
+ gracePeriod: "7776000",
+ registrationType: "BaseRegistrar",
+ ownerId: "0x2426bd7d89230ce5cd4015c47811445b8a6c8f0b",
+ domainId:
+ "8453-0xb94704422c2a1e396835a571837aa5ae53285a95-0xa0cf65983e0b8f2363aaac795c5844c44131ce0b94568e57fcb5e2e5115a87e3",
+ },
+ {
+ canonicalName: "urolinkfu.base.eth",
+ start: "1762698015",
+ expiry: "1794234016",
+ gracePeriod: "7776000",
+ registrationType: "BaseRegistrar",
+ ownerId: "0x66c52ecef41ee67119cfbcaf88d2097ec1eec5f0",
+ domainId:
+ "8453-0xb94704422c2a1e396835a571837aa5ae53285a95-0x1be1354816d460696b36c96b2fa75e3f1fbed97e95720603553d513724d1e233",
+ },
+ {
+ canonicalName: "quantumrepeater.eth",
+ start: "1762697939",
+ expiry: "1794233939",
+ gracePeriod: "7776000",
+ registrationType: "BaseRegistrar",
+ ownerId: "0x53e1c07bf0282e84fd5b600b2b1f90e8bc14d4f1",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xd06fb94af8abfbe4cfe0a6f5fed589ce5bae7a28bd0347241d0903b3d9893233",
+ },
+ {
+ canonicalName: "spirich.base.eth",
+ start: "1762697929",
+ expiry: "1794233930",
+ gracePeriod: "7776000",
+ registrationType: "BaseRegistrar",
+ ownerId: "0xe46bc24cd3c5f2f73e8604b994d18675c64e0019",
+ domainId:
+ "8453-0xb94704422c2a1e396835a571837aa5ae53285a95-0x94f8855a549a1ba319531b8acb1d0130b6ec095bf27e0de3b84e05207a2b154e",
+ },
+ {
+ canonicalName: "hexiuling3.base.eth",
+ start: "1762697917",
+ expiry: "1794255517",
+ gracePeriod: "7776000",
+ registrationType: "BaseRegistrar",
+ ownerId: "0x4b2945016ef05155863723cf07740b2d25d5db19",
+ domainId:
+ "8453-0xb94704422c2a1e396835a571837aa5ae53285a95-0x0944dfcb1ef210d64d6ac38637c57012fa356831d58d31a6ecc9d18484668cd7",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts b/docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts
new file mode 100644
index 000000000..ab1acaac2
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts
@@ -0,0 +1,240 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("Alpha");
+
+/**
+ * Example query for fetching subdomains by their canonical name of the parent domain.
+ */
+export const exampleSubdomainsByParentName = {
+ sql: {
+ codeSnippet: `WITH parent AS (
+ SELECT subregistry_id
+ FROM "ensindexer_0".domains
+ WHERE canonical_name = 'ens.eth'
+ AND canonical = true
+)
+SELECT
+ d.type,
+ d.canonical_name,
+ d.canonical_node,
+ d.owner_id,
+ d.id as domain_id
+FROM "ensindexer_0".domains d
+JOIN parent p ON d.registry_id = p.subregistry_id
+WHERE d.canonical = true
+ORDER BY d.__canonical_name_prefix ASC
+LIMIT 10;
+`,
+ result: [
+ {
+ type: "ENSv1Domain",
+ canonical_name: "app.ens.eth",
+ canonical_node: "0x50a74dcf107973068dfc00db69ecf98b49d52f5361cb4db5feb740fc9f4f74d1",
+ owner_id: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x50a74dcf107973068dfc00db69ecf98b49d52f5361cb4db5feb740fc9f4f74d1",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "attestations.ens.eth",
+ canonical_node: "0x9e5c7a2f2ab8b565c6d2c4851a73decb53d1f6a23c97a2b5b66f21d8ace1bbd5",
+ owner_id: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x9e5c7a2f2ab8b565c6d2c4851a73decb53d1f6a23c97a2b5b66f21d8ace1bbd5",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "coldwallet.ens.eth",
+ canonical_node: "0xc867d2bd24b8a88c7d5d416dfab28fec6858b5a86f3a1c94faeab450c34023f6",
+ owner_id: "0x690f0581ececcf8389c223170778cd9d029606f2",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xc867d2bd24b8a88c7d5d416dfab28fec6858b5a86f3a1c94faeab450c34023f6",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "controller.ens.eth",
+ canonical_node: "0xceecb75ad42a60ea38b777bf842c14af3303219e2722a192ddeac19faa7fbb1c",
+ owner_id: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xceecb75ad42a60ea38b777bf842c14af3303219e2722a192ddeac19faa7fbb1c",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "design.ens.eth",
+ canonical_node: "0xe55e79685b24c7b16542f3c613a8899986ace5e2e08b3c9444ce70d81d49bcd2",
+ owner_id: "0x690f0581ececcf8389c223170778cd9d029606f2",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xe55e79685b24c7b16542f3c613a8899986ace5e2e08b3c9444ce70d81d49bcd2",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "dnsname.ens.eth",
+ canonical_node: "0x250712f87e86832e8bed775a563920aed01b926d9d21950e363a042af40ad2b5",
+ owner_id: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x250712f87e86832e8bed775a563920aed01b926d9d21950e363a042af40ad2b5",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "dnsregistrar.ens.eth",
+ canonical_node: "0x3124e45545d17d9fda8e24a7a09f111a0802ea26ce6b1f14c75c832442deb65d",
+ owner_id: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x3124e45545d17d9fda8e24a7a09f111a0802ea26ce6b1f14c75c832442deb65d",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "dnssec.ens.eth",
+ canonical_node: "0x287e74fe5b4463a7e8b8d4c4cccae51a8ab397df053bc829c6a4e26963c7ce2b",
+ owner_id: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x287e74fe5b4463a7e8b8d4c4cccae51a8ab397df053bc829c6a4e26963c7ce2b",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "docs.ens.eth",
+ canonical_node: "0x08625bbdd59ae52e6a0e3f8f2bd6213e60ad35276510c83d117c7a2a68bc65c0",
+ owner_id: "0xee9eeaab0bb7d9b969d701f6f8212609edea252e",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x08625bbdd59ae52e6a0e3f8f2bd6213e60ad35276510c83d117c7a2a68bc65c0",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "ecosystem.ens.eth",
+ canonical_node: "0x44ea949951a1e21fe141e9979ef9af0cef3df0ac50004c19309df97fef6c9023",
+ owner_id: "0x690f0581ececcf8389c223170778cd9d029606f2",
+ domain_id:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x44ea949951a1e21fe141e9979ef9af0cef3df0ac50004c19309df97fef6c9023",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, eq, inArray, asc } from "drizzle-orm";
+
+const name = "ens.eth";
+const limit = 10;
+
+// Two-step:
+// 1) find parent domains
+// 2) query children by each parent domain's subregistryId.
+const parentDomains = await ensDb
+ .select({ subregistryId: ensIndexerSchema.domain.subregistryId })
+ .from(ensIndexerSchema.domain)
+ .where(
+ and(
+ eq(ensIndexerSchema.domain.canonicalName, name),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ );
+
+if (parentDomains.length > 0) {
+ const subdomains = await ensDb
+ .select({
+ type: ensIndexerSchema.domain.type,
+ canonicalName: ensIndexerSchema.domain.canonicalName,
+ canonicalNode: ensIndexerSchema.domain.canonicalNode,
+ ownerId: ensIndexerSchema.domain.ownerId,
+ domainId: ensIndexerSchema.domain.id,
+ })
+ .from(ensIndexerSchema.domain)
+ .where(
+ and(
+ inArray(
+ ensIndexerSchema.domain.registryId,
+ parentDomains.map((d) => d.subregistryId),
+ ),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ )
+ .orderBy(asc(ensIndexerSchema.domain.__canonicalNamePrefix))
+ .limit(limit);
+
+ console.log(subdomains);
+}`,
+ result: [
+ {
+ type: "ENSv1Domain",
+ canonicalName: "app.ens.eth",
+ canonicalNode: "0x50a74dcf107973068dfc00db69ecf98b49d52f5361cb4db5feb740fc9f4f74d1",
+ ownerId: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x50a74dcf107973068dfc00db69ecf98b49d52f5361cb4db5feb740fc9f4f74d1",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "attestations.ens.eth",
+ canonicalNode: "0x9e5c7a2f2ab8b565c6d2c4851a73decb53d1f6a23c97a2b5b66f21d8ace1bbd5",
+ ownerId: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x9e5c7a2f2ab8b565c6d2c4851a73decb53d1f6a23c97a2b5b66f21d8ace1bbd5",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "coldwallet.ens.eth",
+ canonicalNode: "0xc867d2bd24b8a88c7d5d416dfab28fec6858b5a86f3a1c94faeab450c34023f6",
+ ownerId: "0x690f0581ececcf8389c223170778cd9d029606f2",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xc867d2bd24b8a88c7d5d416dfab28fec6858b5a86f3a1c94faeab450c34023f6",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "controller.ens.eth",
+ canonicalNode: "0xceecb75ad42a60ea38b777bf842c14af3303219e2722a192ddeac19faa7fbb1c",
+ ownerId: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xceecb75ad42a60ea38b777bf842c14af3303219e2722a192ddeac19faa7fbb1c",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "design.ens.eth",
+ canonicalNode: "0xe55e79685b24c7b16542f3c613a8899986ace5e2e08b3c9444ce70d81d49bcd2",
+ ownerId: "0x690f0581ececcf8389c223170778cd9d029606f2",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xe55e79685b24c7b16542f3c613a8899986ace5e2e08b3c9444ce70d81d49bcd2",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "dnsname.ens.eth",
+ canonicalNode: "0x250712f87e86832e8bed775a563920aed01b926d9d21950e363a042af40ad2b5",
+ ownerId: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x250712f87e86832e8bed775a563920aed01b926d9d21950e363a042af40ad2b5",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "dnsregistrar.ens.eth",
+ canonicalNode: "0x3124e45545d17d9fda8e24a7a09f111a0802ea26ce6b1f14c75c832442deb65d",
+ ownerId: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x3124e45545d17d9fda8e24a7a09f111a0802ea26ce6b1f14c75c832442deb65d",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "dnssec.ens.eth",
+ canonicalNode: "0x287e74fe5b4463a7e8b8d4c4cccae51a8ab397df053bc829c6a4e26963c7ce2b",
+ ownerId: "0xb6e040c9ecaae172a89bd561c5f73e1c48d28cd9",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x287e74fe5b4463a7e8b8d4c4cccae51a8ab397df053bc829c6a4e26963c7ce2b",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "docs.ens.eth",
+ canonicalNode: "0x08625bbdd59ae52e6a0e3f8f2bd6213e60ad35276510c83d117c7a2a68bc65c0",
+ ownerId: "0xee9eeaab0bb7d9b969d701f6f8212609edea252e",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x08625bbdd59ae52e6a0e3f8f2bd6213e60ad35276510c83d117c7a2a68bc65c0",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "ecosystem.ens.eth",
+ canonicalNode: "0x44ea949951a1e21fe141e9979ef9af0cef3df0ac50004c19309df97fef6c9023",
+ ownerId: "0x690f0581ececcf8389c223170778cd9d029606f2",
+ domainId:
+ "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x44ea949951a1e21fe141e9979ef9af0cef3df0ac50004c19309df97fef6c9023",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/types.ts b/docs/ensnode.io/src/data/unigraph-examples/types.ts
new file mode 100644
index 000000000..56aebb586
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/types.ts
@@ -0,0 +1,10 @@
+export interface CodeExample {
+ codeSnippet: string;
+ result: unknown;
+ resultNote?: string;
+}
+
+export interface QueryExample {
+ sql: CodeExample;
+ sdk: CodeExample;
+}
diff --git a/docs/ensnode.io/src/data/unigraph-examples/utils.ts b/docs/ensnode.io/src/data/unigraph-examples/utils.ts
new file mode 100644
index 000000000..9fd47e5e5
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/utils.ts
@@ -0,0 +1,29 @@
+export const EnsNodeInstances = {
+ V2Sepolia: "V2 Sepolia",
+ Alpha: "Alpha",
+ AlphaSepolia: "Alpha Sepolia",
+ Mainnet: "Mainnet",
+ Sepolia: "Sepolia",
+} as const;
+
+export type EnsNodeInstance = (typeof EnsNodeInstances)[keyof typeof EnsNodeInstances];
+
+export const outputSource = (ensNodeInstance: EnsNodeInstance) =>
+ `Output matches a point in time snapshot of ENSDb result from our ${ensNodeInstance} Hosted ENSNode instance. Live output depends on the configuration of your ENSNode instance and also changes that may have happened in ENS since this point in time snapshot example response was captured.`;
+
+const ensNodeInstanceDocUrl = (instance: EnsNodeInstance) => {
+ const hostedInstancesPath = "/docs/hosted-instances#ensnode-";
+
+ switch (instance) {
+ case EnsNodeInstances.V2Sepolia:
+ return `${hostedInstancesPath}v2-sepolia`;
+ case EnsNodeInstances.Alpha:
+ return `${hostedInstancesPath}alpha`;
+ case EnsNodeInstances.AlphaSepolia:
+ return `${hostedInstancesPath}alpha-sepolia`;
+ case EnsNodeInstances.Mainnet:
+ return `${hostedInstancesPath}mainnet`;
+ case EnsNodeInstances.Sepolia:
+ return `${hostedInstancesPath}sepolia`;
+ }
+};
diff --git a/docs/ensnode.io/src/styles/starlight.css b/docs/ensnode.io/src/styles/starlight.css
index 71e62eb38..4e93b132e 100644
--- a/docs/ensnode.io/src/styles/starlight.css
+++ b/docs/ensnode.io/src/styles/starlight.css
@@ -928,3 +928,14 @@ starlight-tabs ul[role="tablist"] {
padding: 0.125rem 0.375rem;
font-size: var(--sl-text-code-sm);
}
+
+.static-example p a {
+ color: var(--sl-color-text-accent);
+ text-decoration: underline;
+ text-underline-offset: 4px;
+ transition: text-underline-offset 0.2s ease-in-out;
+
+ &:hover {
+ text-underline-offset: 2px;
+ }
+}