Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
}
},
{
"comment": "Walkthroughs mirror the example apps verbatim; don't reflow their embedded GraphQL.",
"files": ["docs/ensnode.io/src/components/walkthroughs/**/*.mdx", "examples/**/*.{ts,tsx}"],
"comment": "Don't reflow embedded code: hand-authored GraphQL examples throughout the docs, and the example apps that walkthroughs mirror verbatim.",
"files": ["docs/ensnode.io/**/*.{md,mdx}", "examples/**/*.{ts,tsx}"],
"options": {
"embeddedLanguageFormatting": "off"
}
Expand Down
2 changes: 1 addition & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"recommendations": ["biomejs.biome"]
"recommendations": ["biomejs.biome", "esbenp.prettier-vscode"]
}
9 changes: 9 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,14 @@
},
"[terraform]": {
"editor.defaultFormatter": "hashicorp.terraform"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[mdx]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[astro]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ export const integrateSidebarTopic = {
label: "Overview",
link: "/docs/integrate/omnigraph",
},
{
label: "Core Concepts",
link: "/docs/integrate/omnigraph/concepts",
},
{
label: "Examples",
collapsed: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { LinkCard, CardGrid, Aside } from "@astrojs/starlight/components";
import HostedInstanceSdkVersionWarning from "@components/molecules/HostedInstanceSdkVersionWarning.astro";
import OmnigraphStaticExampleSet from "@components/organisms/OmnigraphStaticExampleSet.astro";

## What is ENSv2?
Expand Down Expand Up @@ -30,8 +29,6 @@ Here's a summary of some popular integration strategies:

With `enssdk`, leverage ENSNode and the Omnigraph from any JavaScript runtime to power your frontend or backend apps. `enssdk` comes with built-in type-safety and editor autocomplete for Omnigraph queries.

<HostedInstanceSdkVersionWarning />

```ts title="example.ts"
Comment thread
shrugs marked this conversation as resolved.
// create and extend an EnsNodeClient with Omnigraph API support
const client = createEnsNodeClient({ url: process.env.ENSNODE_URL! }).extend(omnigraph);
Expand Down Expand Up @@ -72,76 +69,34 @@ const result = await client.omnigraph.query({ query: HelloWorldQuery });

With `enskit`, leverage ENSNode and the Omnigraph to power your React components using `useOmnigraphQuery`. `enskit` comes with built-in type-safety, Omnigraph-specific cache directives, easy infinite pagination, and much much more.

<HostedInstanceSdkVersionWarning />
Comment thread
shrugs marked this conversation as resolved.

```tsx title="example.tsx"
// this is fully typechecked and supports editor autocomplete!
const DomainFragment = graphql(`
fragment DomainFragment on Domain {
__typename
id
name
owner { id address }
}
`);

// this is fully typechecked and supports editor autocomplete!
const DomainByNameQuery = graphql(
`
// this query is fully typechecked and supports editor autocomplete!
Comment thread
vercel[bot] marked this conversation as resolved.
const DomainByNameQuery = graphql(`
query DomainByNameQuery($name: InterpretedName!) {
domain(by: { name: $name }) {
...DomainFragment
subdomains {
edges { node { ...DomainFragment } }
Comment thread
vercel[bot] marked this conversation as resolved.
name
owner {
address
}
}
}
`,
[DomainFragment],
);

function RenderDomainFragment({ data }: { data: FragmentOf<typeof DomainFragment> }) {
// type-safe access to fragment data!
const domain = readFragment(DomainFragment, data);

return (
<>
<span>Name: {domain.name ? beautifyInterpretedName(domain.name) : "Unnamed Domain"}</span>
<span>Protocol Version: {domain.__typename === "ENSv1Domain" ? "ENSv1" : "ENSv2"}</span>
<span>Owner: {domain.owner ? domain.owner.address : "Unowned"}</span>
</>
);
}
`);
Comment thread
shrugs marked this conversation as resolved.

export function RenderDomainAndSubdomains({ name }: { name: InterpretedName }) {
export function DomainCard({ name }: { name: InterpretedName }) {
// `result` is fully typed!
const [result] = useOmnigraphQuery({ query: DomainByNameQuery, variables: { name } });
const { data, fetching, error } = result;

// some loading/error handling
if (!data && fetching) return <p>Loading...</p>;
if (fetching) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
if (!data?.domain) return <p>No domain was found with name '{name}'.</p>;
if (!data?.domain) return <p>No domain found for '{name}'.</p>;

// now we have type-safe access to Domain!
const domain = readFragment(DomainFragment, data.domain);
const { subdomains } = data.domain;
const { domain } = data;

return (
<div>
<RenderDomainFragment data={data.domain} />

<h2>Subdomains:</h2>
<ul>
{subdomains?.edges.map((edge) => {
const { id } = readFragment(DomainFragment, edge.node);
return (
<li key={id}>
<RenderDomainFragment data={edge.node} />
</li>
);
})}
</ul>
<p>Name: {domain.name ?? "Unnamed Domain"}</p>
Comment thread
shrugs marked this conversation as resolved.
Outdated
<p>Owner: {domain.owner?.address ?? "Unowned"}</p>
Comment thread
shrugs marked this conversation as resolved.
Outdated
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { LinkCard, CardGrid, Aside } from "@astrojs/starlight/components";
import HostedInstanceSdkVersionWarning from "@components/molecules/HostedInstanceSdkVersionWarning.astro";
import OmnigraphStaticExampleSet from "@components/organisms/OmnigraphStaticExampleSet.astro";

## What is ENSv2?
Expand Down Expand Up @@ -30,8 +29,6 @@ Here's a summary of some popular integration strategies:

With `enssdk`, leverage ENSNode and the Omnigraph from any JavaScript runtime to power your frontend or backend apps. `enssdk` comes with built-in type-safety and editor autocomplete for Omnigraph queries.

<HostedInstanceSdkVersionWarning />

```ts title="example.ts"
Comment thread
shrugs marked this conversation as resolved.
// create and extend an EnsNodeClient with Omnigraph API support
const client = createEnsNodeClient({ url: process.env.ENSNODE_URL! }).extend(omnigraph);
Expand All @@ -40,7 +37,6 @@ const client = createEnsNodeClient({ url: process.env.ENSNODE_URL! }).extend(omn
const HelloWorldQuery = graphql(`
query HelloWorld {
domain(by: { name: "eth" }) {
id
canonical { name { beautified } }
owner { address }
}
Expand Down Expand Up @@ -72,76 +68,32 @@ const result = await client.omnigraph.query({ query: HelloWorldQuery });

With `enskit`, leverage ENSNode and the Omnigraph to power your React components using `useOmnigraphQuery`. `enskit` comes with built-in type-safety, Omnigraph-specific cache directives, easy infinite pagination, and much much more.

<HostedInstanceSdkVersionWarning />

```tsx title="example.tsx"
// this is fully typechecked and supports editor autocomplete!
const DomainFragment = graphql(`
fragment DomainFragment on Domain {
__typename
id
canonical { name { beautified } }
owner { id address }
}
`);

// this is fully typechecked and supports editor autocomplete!
const DomainByNameQuery = graphql(
`
// this query is fully typechecked and supports editor autocomplete!
const DomainByNameQuery = graphql(`
Comment thread
shrugs marked this conversation as resolved.
query DomainByNameQuery($name: InterpretedName!) {
domain(by: { name: $name }) {
...DomainFragment
subdomains {
edges { node { ...DomainFragment } }
}
canonical { name { beautified } }
owner { address }
}
}
`,
[DomainFragment],
);

function RenderDomainFragment({ data }: { data: FragmentOf<typeof DomainFragment> }) {
// type-safe access to fragment data!
const domain = readFragment(DomainFragment, data);

return (
<>
<span>Name: {domain.canonical ? domain.canonical.name.beautified : "Unnamed Domain"}</span>
<span>Protocol Version: {domain.__typename === "ENSv1Domain" ? "ENSv1" : "ENSv2"}</span>
<span>Owner: {domain.owner ? domain.owner.address : "Unowned"}</span>
</>
);
}
`);

export function RenderDomainAndSubdomains({ name }: { name: InterpretedName }) {
export function DomainCard({ name }: { name: InterpretedName }) {
// `result` is fully typed!
const [result] = useOmnigraphQuery({ query: DomainByNameQuery, variables: { name } });
const { data, fetching, error } = result;

// some loading/error handling
if (!data && fetching) return <p>Loading...</p>;
if (fetching) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
if (!data?.domain) return <p>No domain was found with name '{name}'.</p>;
if (!data?.domain) return <p>No domain found for '{name}'.</p>;

// now we have type-safe access to Domain!
const domain = readFragment(DomainFragment, data.domain);
const { subdomains } = data.domain;
const { domain } = data;

return (
<div>
<RenderDomainFragment data={data.domain} />

<h2>Subdomains:</h2>
<ul>
{subdomains?.edges.map((edge) => {
const { id } = readFragment(DomainFragment, edge.node);
return (
<li key={id}>
<RenderDomainFragment data={edge.node} />
</li>
);
})}
</ul>
<p>Name: {domain.canonical?.name.beautified ?? "Unnamed Domain"}</p>
Comment thread
shrugs marked this conversation as resolved.
<p>Owner: {domain.owner?.address ?? "Unowned"}</p>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ Full access to ENS data formerly required two separate data-fetching strategies

## How ENSNode solves this

**The Unigraph Data Model** — [ENSIndexer](/docs/services/ensindexer) offers the `unigraph` plugin, which builds a **unified** polymorphic indexed data model in [ENSDb](/docs/services/ensdb) of multiple ENSv1 Nametrees (the ENSv1 onchain state model found in the ENS root registry, Basenames on Base, Lineanames on Linea, 3DNS on Optimism, etc.), and the ENSv2 Namegraph (the ENSv2 onchain state model that ENSv1 domains may optionally be upgraded to, which allows for dynamic reconfiguration of the name hierarchy, including possible cycles, disjoint domains, and infinite aliases).
**The Unigraph Data Model** — [ENSIndexer](/docs/services/ensindexer)'s `unigraph` plugin builds a single, **unified** indexed data model in [ENSDb](/docs/services/ensdb) that combines all of ENSv1 — mainnet `.eth`, Basenames on Base, Lineanames on Linea, 3DNS on Optimism — together with ENSv2. One data model, every chain, both protocol versions.

**The Omnigraph API** — The [ENS Omnigraph API](/docs/integrate/omnigraph) is delivered by [ENSApi](/docs/services/ensapi) and builds upon and refines the Unigraph data model held in [ENSDb](/docs/services/ensdb). The Omnigraph API provides a highly tailored, fully typed GraphQL API that understands ENS protocol implementation details—including ENSIP-10, ENSIP-15, ENSIP-19, and much more—so that you can focus on building your app (and not all the internal implementation complexities of the ENS protocol).
**The Omnigraph API** — The [ENS Omnigraph API](/docs/integrate/omnigraph), delivered by [ENSApi](/docs/services/ensapi), is a fully typed GraphQL API on top of that Unigraph data model. It handles the ENS protocol's many implementation details for you, so you can focus on building your app instead of wiring up the protocol's internals.

**Accelerated ENS Resolution** — The ENS Omnigraph API, through ENSApi, internally implements the ENS Universal Resolver on top of the indexed ENS Unigraph data model in ENSDb. We refer to this idea as "[ENS Protocol Acceleration](/docs/services/ensapi#ens-protocol-acceleration)". For cases where ENS Resolution requires offchain data, ENSApi internally performs the CCIP-read operations on your behalf to ensure every resolution request accurately follows all ENS protocol standards. No need for any RPC calls in your app, and your ENS resolutions for indexed names could speed up by an order of magnitude or more!

## What You Need to Do

**Resolving Records** — If you're exclusively interested in resolving ENS names, you need to ensure that your `resolve` RPC calls go to the new `UniversalResolverV2` contract or risk stale and incorrect results being returned. Depending on your situation, this update may be handled simply by updating `viem` or `wagmi`, but for many apps building on indexed ENS data or with more advanced requirements, additional upgrade actions may be required.

For many, the simple solution for ENSv2 readiness will be to adopt the ENS Omnigraph API from ENSNode for all their ENS data needs (both ENSv1 and ENSv2). ENSNode also provides **[ENS Protocol Acceleration](/docs/services/ensapi#ens-protocol-acceleration)**, dramatically reducing resolution latency for most names people use.
For many, the simple solution for ENSv2 readiness will be to adopt the ENS Omnigraph API from ENSNode for all their ENS data needs (both ENSv1 and ENSv2). ENSNode also provides **[ENS Protocol Acceleration](/docs/services/ensapi#ens-protocol-acceleration)**, dramatically reducing resolution latency for most names.

**Querying ENS Data** — If you're querying ENS names via a legacy API such as the ENS Subgraph you need to update to an ENSv2-ready service like ENSNode; as soon as ENSv2 launches, data served by the Subgraph (and any ENSv1-only indexers) will be instantly unreliable for the true state of ENS.

Expand Down
Loading
Loading