Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d391047
add sandbox and ensv2readiness
sevenzing May 13, 2026
787609b
temp remove quickstart from llmtext
sevenzing May 13, 2026
f01ce76
create static graphql examples
sevenzing May 13, 2026
0e9b76e
revert quickstart and ensv2 readiness changes
sevenzing May 14, 2026
894b9b6
Merge branch 'main' into ll/docs-query-sandbox
sevenzing May 14, 2026
ab9e0de
playgroud examples
sevenzing May 14, 2026
394dd38
rename cookbook to examples
sevenzing May 14, 2026
58cef6a
Merge branch 'main' into ll/docs-query-sandbox
sevenzing May 15, 2026
28b1a51
add description to examples
sevenzing May 15, 2026
4f9ec7c
add interactive enssdk example
sevenzing May 15, 2026
8335ddf
add enskit interactive example
sevenzing May 15, 2026
b867a9c
remove title from code example
sevenzing May 15, 2026
0b720c5
add sidebar docked
sevenzing May 15, 2026
6d29219
add schema reference
sevenzing May 15, 2026
239109f
use @ import instead of ..
sevenzing May 15, 2026
e4045e4
add cleanup
sevenzing May 15, 2026
15959fc
Merge branch 'main' into ll/docs-query-sandbox
sevenzing May 15, 2026
5dceafa
fix AI comments
sevenzing May 15, 2026
9e7be1a
fix production bug
sevenzing May 15, 2026
85825e1
replace rocket with zap
sevenzing May 17, 2026
9c47174
update interactive example descriptions
sevenzing May 17, 2026
8b5dca6
Merge branch 'main' into ll/docs-query-sandbox
sevenzing May 17, 2026
4f30016
fix wrong git merge
sevenzing May 18, 2026
42def48
Merge branch 'main' into ll/docs-query-sandbox
sevenzing May 18, 2026
2ed324c
Update examples export to be published to NPM
tk-o May 18, 2026
e6413bb
Fix import paths
tk-o May 18, 2026
100fda5
Add specific package entrypoint for gql examples
tk-o May 18, 2026
6239a61
Update GQL examples
tk-o May 18, 2026
410e6ff
revert examples to use previous data model version
tk-o May 18, 2026
d5ce33d
publish the internal module for ENSNode SDK package
tk-o May 18, 2026
f2f7ac2
Pin package version to make GQL examples work with the current produc…
tk-o May 18, 2026
8fb2f07
fix example start
sevenzing May 18, 2026
9c223af
final fixes
sevenzing May 18, 2026
ea80606
Merge branch 'main' into ll/docs-query-sandbox
sevenzing May 18, 2026
821e2f3
Merge remote-tracking branch 'origin/fix-sha-89c022b' into ll/docs-qu…
sevenzing May 18, 2026
97d434f
fix final
sevenzing May 18, 2026
98c57d2
revert deleting why ensnode
sevenzing May 18, 2026
348661b
super final fixes after self review. always self review before merge!…
sevenzing May 18, 2026
922e358
final fixes
sevenzing May 18, 2026
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
14 changes: 14 additions & 0 deletions docs/ensnode.io/config/integrations/llms-txt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import starlightLlmsTxt from "starlight-llms-txt";

/**
* `starlight-llms-txt` renders each docs entry for `/llms-full.txt` and `/llms-small.txt` through
* an Astro container that only registers the MDX SSR renderer, not React. MDX pages that import
* `.tsx` islands must be omitted from those exports or `astro build` fails with `NoMatchingRenderer`.
*
* Patterns use micromatch against each entry's `id` in the Starlight `docs` collection
* (paths are relative to `src/content/docs/`; a folder's `index.mdx` uses the folder path as `id`,
* e.g. `docs/integrate` for `docs/integrate/index.mdx`).
*/
export const starlightLlmsTxtPlugin = starlightLlmsTxt({
exclude: ["docs/integrate"],
});
4 changes: 2 additions & 2 deletions docs/ensnode.io/config/integrations/starlight/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import AstroStarlight from "@astrojs/starlight";
import type { AstroIntegration } from "astro";
import starlightLlmsTxt from "starlight-llms-txt";
import starlightSidebarTopics from "starlight-sidebar-topics";

import { starlightLlmsTxtPlugin } from "../llms-txt";
import { starlightSidebarTopicsConfig } from "./sidebar-topics";

export function starlight(): AstroIntegration {
Expand All @@ -29,7 +29,7 @@ export function starlight(): AstroIntegration {
"@fontsource/inter/800.css",
"@fontsource/inter/900.css",
],
plugins: [starlightLlmsTxt(), starlightSidebarTopics(starlightSidebarTopicsConfig)],
plugins: [starlightLlmsTxtPlugin, starlightSidebarTopics(starlightSidebarTopicsConfig)],
title: "ENSNode",
disable404Route: true,
logo: {
Expand Down
1 change: 1 addition & 0 deletions docs/ensnode.io/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@namehash/namehash-ui": "workspace:*",
Comment thread
sevenzing marked this conversation as resolved.
"@octokit/rest": "^20.1.2",
"@scalar/astro": "^0.2.4",
"@stackblitz/sdk": "^1.11.0",
"@tailwindcss/vite": "^4.1.15",
"astro": "catalog:",
"astro-font": "catalog:",
Expand Down
Binary file added docs/ensnode.io/public/ensomnigraph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
86 changes: 86 additions & 0 deletions docs/ensnode.io/src/components/molecules/CodePlayground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import sdk, { type EmbedOptions, type Project } from "@stackblitz/sdk";
import { useEffect, useRef } from "react";

interface CodePlaygroundProps {
title: string;
description?: string;
files: Record<string, string>;
dependencies: Record<string, string>;
entryFileName?: string;
height?: number;
terminalHeight?: number;
}

export default function CodePlayground({
title,
description,
files,
dependencies,
entryFileName = "index.ts",
height = 500,
terminalHeight = 35,
}: CodePlaygroundProps) {
const ref = useRef<HTMLDivElement>(null);

useEffect(() => {
if (!ref.current) return;

const packageJson = JSON.stringify(
{
name: title.toLowerCase().replace(/\s+/g, "-"),
version: "0.0.0",
private: true,
type: "module",
scripts: { start: `tsx ${entryFileName}` },
dependencies: { tsx: "latest", ...dependencies },
},
null,
2,
);

const tsconfig = JSON.stringify(
{
compilerOptions: {
target: "es2022",
module: "nodenext",
moduleResolution: "nodenext",
strict: true,
},
},
null,
2,
);

const projectFiles = {
"package.json": packageJson,
"tsconfig.json": tsconfig,
...files,
};
Comment thread
sevenzing marked this conversation as resolved.

const project = {
title,
description,
template: "node",
files: projectFiles,
} as Project;
const options = {
openFile: entryFileName,
terminalHeight,
height,
hideNavigation: true,
hideExplorer: true,
hideDevTools: true,
showSidebar: false,
view: "editor",
theme: "light",
} as EmbedOptions;

sdk.embedProject(ref.current, project, options);
}, []);
Comment thread
sevenzing marked this conversation as resolved.
Outdated
Comment thread
sevenzing marked this conversation as resolved.
Outdated

return (
<div className="not-content">
<div ref={ref} />
</div>
);
}
28 changes: 28 additions & 0 deletions docs/ensnode.io/src/components/molecules/EnssdkPlayground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import CodePlayground from "./CodePlayground";

interface CodePlaygroundProps {
title: string;
description?: string;
fileContent: string;
height?: number;
terminalHeight?: number;
}

export default function EnssdkPlayground({
title,
description,
fileContent,
height,
terminalHeight,
}: CodePlaygroundProps) {
return (
<CodePlayground
title={title}
description={description}
files={{ "index.ts": fileContent }}
dependencies={{ "@ensnode/ensnode-sdk": "latest" }}
height={height}
terminalHeight={terminalHeight}
Comment thread
sevenzing marked this conversation as resolved.
Outdated
/>
);
}
40 changes: 40 additions & 0 deletions docs/ensnode.io/src/components/playgrounds/EnssdkResolutionApi.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import EnssdkPlayground from "../molecules/EnssdkPlayground";
import { ENSNODE_URL, getNiceHeightForSnippet } from "./common";

const snippet = `
import { createEnsNodeClient } from 'enssdk/core';
import { omnigraph, graphql } from 'enssdk/omnigraph';
import { asInterpretedName } from "enssdk";

const client = createEnsNodeClient({
url: '${ENSNODE_URL}',
}).extend(omnigraph);

const MyQuery = graphql(\`
query MyQuery($name: InterpretedName!) {
domain(by: { name: $name }) {
name
owner { address }
resolver { contract { chainId address }}
registration { expiry }
}
}
\`);

const result = await client.omnigraph.query({
query: MyQuery,
variables: { name: asInterpretedName('nick.eth') },
});
console.log('Result:', result.data);
`.trim();
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

export default function EnssdkResolutionApiPlayground() {
return (
<EnssdkPlayground
title="ENSNode SDK — Resolution API"
description="Query ENS name data in seconds using [`@ensnode/ensnode-sdk`](/docs/integrate/integration-options/enssdk)."
fileContent={snippet}
height={getNiceHeightForSnippet(snippet)}
/>
);
}
14 changes: 14 additions & 0 deletions docs/ensnode.io/src/components/playgrounds/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// TODO: Update to the latest ENSNode URL
export const ENSNODE_URL = "https://api.v2-sepolia.green.ensnode.io";
Comment thread
sevenzing marked this conversation as resolved.
Outdated
Comment thread
sevenzing marked this conversation as resolved.
Outdated

export function getNiceHeightForSnippet(snippet: string) {
const linesCount = snippet.split("\n").length;
const lineHeight = 18;
const headerHeight = 38;
const footerHeight = 32;
const height = linesCount * lineHeight + headerHeight + footerHeight;

const terminalHeightPercentage = 0.35;

return Math.ceil(height / (1 - terminalHeightPercentage));
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,57 @@ title: ENSv2 Readiness
description: How building with ENSNode today prepares your application for ENSv2, even before ENSv2 launches.
---

:::caution[Coming Soon]
We're actively working on this page right now. Check back by May 18th for full content!
:::
import { LinkCard, Aside } from "@astrojs/starlight/components";

This page will describe ENSNode's ENSv2 readiness story — how building with ENSNode today prepares your application for ENSv2, even before ENSv2 launches. Ensure that the moment ENSv2 launches, everything in your app continues working seamlessly with zero interruptions!

<Aside type="tip" title="Be ready!">
Build with **ENS Omnigraph** today and your app will support **ENSv2** the moment it launches — with zero code changes.
</Aside>


## The problem with ENSv1 integrations today

Fully supporting ENSv1 requires two separate systems working in parallel:

1. **On-chain resolution** — RPC calls with CCIP-read support (e.g. via [viem](/docs/reference/subgraph-legacy/with-viem) or [ensjs](/docs/reference/subgraph-legacy/with-ensjs) to resolve names to addresses and records at the current state of the chain.
2. **Indexed data** — the [ENS Subgraph](/docs/reference/what-is-the-ens-subgraph) for historical data, registration info, reverse records, and browsing names owned by an address.

Neither system alone is complete.
The Subgraph gives you queryable indexed history but can lag behind the chain and has no CCIP-read support.
On-chain resolution gives you accurate live state but no history and no way to browse names.

Most ENS integrations today live with this split — and with **ENSv2**, the complexity only increases as names spread across multiple chains.

## How ENS Omnigraph solves this

The [ENS Omnigraph API](/docs/integrate/omnigraph) is ENSNode's unified GraphQL API that replaces both systems with a single endpoint:

- **Resolution data is indexed** — owner, resolver, records, expiry, and CCIP-read results are resolved and stored at index time, so you get accurate resolution data from a simple GraphQL query with no RPC calls in your app.
- **Full history and browsability** — all the indexed capabilities of the Subgraph, unified across chains.
- **Multichain by design** — a single query can span mainnet, Base, Linea, 3DNS, and any future ENSv2 registries.

This means you write one integration instead of two, and you get more accurate data as a result.

## ENSv2 readiness

ENSv2 moves ENS registries from Ethereum mainnet to L2s. When it launches, names may exist across multiple chains, and the current two-system approach becomes even harder to maintain — you would need separate resolution logic and separate Subgraph queries for each chain.

ENSNode is already built for this world:

- ENSNode indexes ENSv2 registries as they come online
- The ENS Omnigraph API surfaces ENSv2 names alongside ENSv1 names transparently
- The [enssdk](/docs/integrate/integration-options/enssdk) and [enskit](/docs/integrate/integration-options/enskit) client libraries abstract over chain differences entirely


<Aside type="tip" title="The result">
If you integrate with **ENS Omnigraph** today to support **ENSv1**, you automatically get **ENSv2** support when it launches — your code does not need to change.
</Aside>


## What you need to do

1. **Replace your Subgraph queries** with ENS Omnigraph queries. The [Migration Guide](/docs/integrate/migrate-from-subgraph) will help you with that.
2. **Remove your RPC resolution calls** from the hot path. Omnigraph already resolves and indexes this data — you can query it directly and save on RPC calls.
3. **Use [enssdk](/docs/integrate/integration-options/enssdk)** for a fully typed TypeScript client, or query the [raw GraphQL endpoint](/docs/integrate/integration-options/raw-graphql) directly if you prefer.

That's it. There is no ENSv2-specific migration step later.
74 changes: 65 additions & 9 deletions docs/ensnode.io/src/content/docs/docs/integrate/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,72 @@ sidebar:
order: 1
---

import EnssdkResolutionApiPlayground from "../../../../components/playgrounds/EnssdkResolutionApi";
Comment thread
sevenzing marked this conversation as resolved.
Outdated
import { LinkCard, CardGrid } from "@astrojs/starlight/components";

:::caution[Coming Soon]
We're actively working on this page right now. Check back by May 18th for full content!
:::
## What is ENSv2?

This page will be a 60-second quickstart for querying ENSv2 data through ENSNode — including:
ENSv2 is the next generation of the Ethereum Name Service — a protocol upgrade that moves ENS registries from Ethereum mainnet onto L2s. Names become cheaper to register, faster to update, and natively multichain.

- A **React example** with [enskit](/docs/integrate/integration-options/enskit) using the `useOmnigraphQuery` hook.
- A **interactive code snippet** with [enssdk](/docs/integrate/integration-options/enssdk) showing a typed ENS Omnigraph query (e.g. look up a domain). Optionally can launch the request against the ENS Omnigraph API and see the response in your browser.
- Links to [hosted instances](/docs/integrate/hosted-instances) so you can start querying immediately with zero setup.
- [ENSv2 Readiness](/docs/integrate/ensv2-readiness) — how building with ENSNode today prepares your app for ENSv2.
- [Integration Options](/docs/integrate/integration-options) — choose the right path: enskit, enssdk, raw GraphQL, or ENSDb.
ENSv2 is backwards compatible with ENSv1: existing `.eth` names continue to work, and ENSv2 introduces a new registry architecture that supports names across multiple chains simultaneously.

## What is ENS Omnigraph?

ENS Omnigraph is ENSNode's unified GraphQL API for querying ENS name data across every supported chain from a single endpoint.

![ENS Omnigraph diagram](/ensomnigraph.png)

Today, fully supporting ENSv1 requires two separate systems: on-chain resolution (via RPC calls + CCIP-read) and indexed data (via the ENS Subgraph). Neither alone gives a complete picture.

ENS Omnigraph solves this by combining both into one API:

- **Indexes ENSv1 and ENSv2** names across mainnet, Base, Linea, 3DNS, and more
- **Provides resolution data** — owner, resolver, records, expiry — in a single query
- **Backwards compatible** with ENSv1, so you can integrate today and get ENSv2 support automatically when it launches

This means you can build your ENS integration once against the Omnigraph API and be ready for ENSv2 before it even launches. See [ENSv2 Readiness](/docs/integrate/ensv2-readiness) for the full story.

## Query ENS name data

The fastest way to query ENS data is with [`enssdk`](/docs/integrate/integration-options/enssdk) — the official TypeScript SDK. It gives you a fully typed GraphQL client pointed at the ENS Omnigraph API.

The playground below is live — edit the query or the name and run it against a real ENSNode instance:

<EnssdkResolutionApiPlayground client:load />

The `client.omnigraph.query(...)` call sends a typed GraphQL query to the [ENS Omnigraph API](/docs/integrate/omnigraph). The `asInterpretedName` helper normalizes the name before querying.

## What's next?

<CardGrid>
<LinkCard
title="🔀 Integration Options"
description="Choose the right path: enssdk, enskit, raw GraphQL, or direct ENSDb access."
href="/docs/integrate/integration-options"
/>
<LinkCard
title="🕸️ ENS Omnigraph API"
description="Schema overview, mental model, and how Omnigraph differs from the legacy ENS Subgraph."
href="/docs/integrate/omnigraph"
/>
<LinkCard
title="📖 Cookbook"
description="Ready-to-use query recipes: names by address, resolver records, registration history, multichain queries, and more."
href="/docs/integrate/omnigraph/cookbook"
/>
<LinkCard
title="🛠️ enssdk"
description="Full SDK reference — createEnsNodeClient, typed queries with gql.tada, and normalization utilities."
href="/docs/integrate/integration-options/enssdk"
/>
<LinkCard
title="🚀 ENSv2 Readiness"
description="How integrating with ENSNode today makes your app ENSv2-ready out of the box."
href="/docs/integrate/ensv2-readiness"
/>
<LinkCard
title="🌐 Hosted Instances"
description="Public ENSNode endpoints you can query immediately with zero setup."
href="/docs/integrate/hosted-instances"
/>
</CardGrid>
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@
"patchedDependencies": {
"@opentelemetry/api": "patches/@opentelemetry__api.patch",
"@opentelemetry/otlp-exporter-base": "patches/@opentelemetry__otlp-exporter-base.patch",
"@changesets/assemble-release-plan@6.0.9": "patches/@changesets__assemble-release-plan@6.0.9.patch"
"@changesets/assemble-release-plan@6.0.9": "patches/@changesets__assemble-release-plan@6.0.9.patch",
"starlight-llms-txt@0.5.1": "patches/starlight-llms-txt@0.5.1.patch"
}
}
}
18 changes: 18 additions & 0 deletions patches/starlight-llms-txt@0.5.1.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
diff --git a/llms-full.txt.ts b/llms-full.txt.ts
index cdc3a34c0555c4a556224f63d937d976c669eef0..45d60f54994240e93277021cb649237c4874f4ce 100644
--- a/llms-full.txt.ts
+++ b/llms-full.txt.ts
@@ -1,4 +1,5 @@
import type { APIRoute } from 'astro';
+import { starlightLllmsTxtContext } from 'virtual:starlight-llms-txt/context';
import { generateLlmsTxt } from './generator';
import { getSiteTitle } from './utils';

@@ -9,6 +10,7 @@ export const GET: APIRoute = async (context) => {
const body = await generateLlmsTxt(context, {
minify: false,
description: `This is the full developer documentation for ${getSiteTitle()}`,
+ exclude: starlightLllmsTxtContext.exclude,
});
return new Response(body);
};
Loading
Loading