diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..fa29cdf
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+**
\ No newline at end of file
diff --git a/astro.config.mjs b/astro.config.mjs
index 80de9cb..af55412 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -20,16 +20,38 @@ export default defineConfig({
icon: "github",
label: "GitHub",
href: "https://github.com/midnames/docs",
+ }, {
+ icon: "twitter",
+ label: "Twitter",
+ href: "https://x.com/midnames"
},
+ {
+ icon: "linkedin",
+ label: "LinkedIn",
+ href: "https://www.linkedin.com/company/midnames/"
+ }
+
],
sidebar: [
{
label: "Guides",
- autogenerate: { directory: "guides" },
+ items: [
+ {label: "Quickstart", slug: "guides/quickstart"},
+ {label: "Buy Domains", slug: "guides/buy_domain"},
+ {label: "Transfer .night domains", slug: "guides/transfer_domain"},
+ {label: "Update domain fields", slug: "guides/update_fields"},
+ {label: "MNS domain specification", slug: "guides/valid_domains"}
+ ]
},
{
label: "SDK Reference",
- autogenerate: { directory: "reference" },
+ items: [
+ {label: "Domain Operations", slug: "reference/operations"},
+ {label: "Domain Resolution", slug: "reference/resolve"},
+ {label: "TypeScript Types", slug: "reference/types"},
+ {label: "Utility Functions", slug: "reference/utils"},
+ {label: "Profile Widget", slug: "reference/widget"}
+ ]
},
],
plugins: [
diff --git a/src/content/docs/guides/index.mdx b/src/content/docs/guides/index.mdx
index c84c3c5..e0a85fa 100644
--- a/src/content/docs/guides/index.mdx
+++ b/src/content/docs/guides/index.mdx
@@ -1,10 +1,54 @@
---
title: Guides
-description: Here are some guides to help you get started with Midnames, the .night domain registry.
+description: Step-by-step guides for using Midnames and the .night domain registry
sidebar:
hidden: true
---
-Here are some guides to help you get started with Midnames, the .night domain registry.
+import { CardGrid, LinkCard } from "@astrojs/starlight/components";
-Look through the list on the left to find a guide that suits your needs.
+Step-by-step guides to help you get started with Midnames, the .night domain registry, and the Midnames SDK.
+
+## Getting Started
+
+
+
+
+
+
+## Managing Your Domain
+
+
+
+
+
+
+## Specifications
+
+
+
+
+
+## SDK Documentation
+
+Looking for API documentation? Check out the [SDK Reference](/reference/) section for complete API docs, React components, utility functions, and TypeScript types.
diff --git a/src/content/docs/guides/quickstart.mdx b/src/content/docs/guides/quickstart.mdx
new file mode 100644
index 0000000..b951d9a
--- /dev/null
+++ b/src/content/docs/guides/quickstart.mdx
@@ -0,0 +1,405 @@
+---
+title: Quick Start
+description: Get started with the Midnames SDK in 5 minutes
+sidebar:
+ label: Quick Start
+ badge:
+ text: Start here
+ variant: success
+---
+
+import { Aside, Steps, Code } from "@astrojs/starlight/components";
+
+Get started with the Midnames SDK in minutes. This guide covers installation, basic usage, and common patterns for both DApp and wallet developers.
+
+## What is Midnames SDK?
+
+Midnames SDK is a TypeScript library for integrating the Midnight Name Service (MNS) into your applications. It allows you to:
+
+- **Resolve** `.night` domains to blockchain addresses
+- **Display** rich profile information with pre-built React components
+- **Manage** domain fields, ownership, and settings (with wallet integration)
+
+
+
+## Installation
+
+
+
+1. **Install the SDK**
+
+ ```bash
+ npm install @midnames/sdk
+ ```
+
+ For React components, also install peer dependencies:
+
+ ```bash
+ npm install react react-dom lucide-react
+ ```
+
+2. **Import and start using**
+
+ ```typescript
+ import { resolveDomain } from "@midnames/sdk";
+
+ const result = await resolveDomain("alice.night");
+ console.log(result.data); // Address or contract
+ ```
+
+
+
+That's it! The SDK is now ready for development purposes.
+
+## Basic Examples
+
+### Example 1: Resolve a Domain
+
+Translate a `.night` domain to its target address:
+
+```typescript
+import { resolveDomain } from "@midnames/sdk";
+
+async function resolveUserDomain(domain: string) {
+ const result = await resolveDomain(domain);
+
+ if (result.success) {
+ console.log("Resolved to:", result.data);
+ // => "mn_shield-cpk_test1..." or "0200..."
+ } else {
+ console.error("Resolution failed:", result.error.message);
+ }
+}
+
+await resolveUserDomain("alice.night");
+```
+
+### Example 2: Get Domain Profile
+
+Fetch complete profile data including fields and metadata:
+
+```typescript
+import { getDomainProfile } from "@midnames/sdk";
+
+async function fetchProfile(domain: string) {
+ const result = await getDomainProfile(domain);
+
+ if (!result.success) {
+ console.error("Error:", result.error.message);
+ return;
+ }
+
+ const profile = result.data;
+
+ console.log("Domain:", profile.fullDomain);
+ console.log("Owner:", profile.info?.owner);
+ console.log("Target:", profile.resolvedTarget);
+
+ // Access custom fields
+ console.log("Name:", profile.fields.get("name"));
+ console.log("Bio:", profile.fields.get("bio"));
+ console.log("Twitter:", profile.fields.get("twitter"));
+}
+
+await fetchProfile("alice.night");
+```
+
+### Example 3: Display Profile Widget (React)
+
+Show a beautiful profile card with zero configuration:
+
+```tsx
+import "@midnames/sdk/styles.css";
+import { DomainProfileWidget } from "@midnames/sdk/react/DomainProfileWidget";
+
+function ProfilePage() {
+ return (
+
+
User Profile
+
+
+ );
+}
+```
+
+That's all you need! The widget automatically:
+
+- Fetches domain data
+- Displays avatar, bio, and social links
+- Shows ownership information
+- Handles errors gracefully
+
+## Common Use Cases
+
+### For DApp Developers
+
+#### Display user names instead of addresses
+
+```typescript
+import { resolveDomain } from "@midnames/sdk";
+
+// In your transaction UI
+async function displayRecipient(addressOrDomain: string) {
+ // If it looks like a domain, resolve it
+ if (addressOrDomain.endsWith(".night")) {
+ const result = await resolveDomain(addressOrDomain);
+ if (result.success) {
+ return {
+ displayName: addressOrDomain,
+ address: result.data,
+ };
+ }
+ }
+
+ return {
+ displayName: `${addressOrDomain.slice(0, 10)}...`,
+ address: addressOrDomain,
+ };
+}
+
+// Usage
+const recipient = await displayRecipient("alice.night");
+console.log(`Sending to ${recipient.displayName} (${recipient.address})`);
+```
+
+#### Reverse resolution (address → domain)
+
+While the SDK doesn't provide direct reverse resolution, you can implement it by storing mappings in your application or querying all domains.
+
+### For Wallet Developers
+
+#### Autocomplete domain search
+
+```typescript
+import { getDomainInfo, normalizeDomain } from "@midnames/sdk";
+
+async function isDomainAvailable(input: string): Promise {
+ const domain = normalizeDomain(input);
+ const result = await getDomainInfo(domain);
+
+ // Domain is available if info is null
+ return !result.success || result.data.info === null;
+}
+
+// Usage
+const available = await isDomainAvailable("alice");
+console.log(available ? "Available!" : "Taken");
+```
+
+#### Show domain profile in wallet
+
+```tsx
+import { DomainProfileWidget } from "@midnames/sdk/react/DomainProfileWidget";
+
+function WalletContactCard({ domain }: { domain: string }) {
+ return (
+ {
+ showToast(`Copied ${field}`);
+ }}
+ />
+ );
+}
+```
+
+## Error Handling
+
+All SDK functions implement a `Result` type for type-safe error handling, ensuring developers write clean, maintainable & predictable code:
+
+```typescript
+import { resolveDomain } from "@midnames/sdk";
+
+const result = await resolveDomain("alice.night");
+
+if (result.success) {
+ // Type: string (the resolved address)
+ console.log("Success:", result.data);
+} else {
+ // Type: MidnamesError
+ console.error("Error:", result.error);
+ console.error("Code:", result.error.code);
+ console.error("Message:", result.error.message);
+}
+```
+
+**Common error codes:**
+
+| Code | Meaning | Action |
+| -------------------- | --------------------- | ------------------------ |
+| `DOMAIN_NOT_FOUND` | Domain doesn't exist | Show "Available" UI |
+| `INVALID_DOMAIN` | Invalid format | Show validation error |
+| `NETWORK_ERROR` | Connection failed | Retry or show offline UI |
+| `CONTRACT_NOT_FOUND` | Contract not deployed | Handle as not found |
+
+## Advanced Configuration
+
+### Custom Provider
+
+By default, the SDK connects to Midnight TestNet. The SDK allows developers to easily customize his prefered provider:
+
+```typescript
+import { createDefaultProvider, resolveDomain } from "@midnames/sdk";
+import { NetworkId } from "@midnight-ntwrk/midnight-js-network-id";
+
+// Create custom provider
+const provider = createDefaultProvider({
+ indexerUrl: "https://your-indexer.example.com/api/v1/graphql",
+ indexerWsUrl: "wss://your-indexer.example.com/api/v1/graphql/ws",
+ networkId: NetworkId.TestNet,
+});
+
+// Use it
+const result = await resolveDomain("alice.night", { provider });
+```
+
+### Set Default Provider Globally
+
+```typescript
+import { setDefaultProvider, createDefaultProvider } from "@midnames/sdk";
+
+// Set once at app initialization
+const provider = createDefaultProvider();
+setDefaultProvider(provider);
+
+// Now all SDK functions use this provider by default
+```
+
+## Next Steps
+
+Now that you know the basics, explore these topics:
+
+
+
+**📖 Learn More**
+
+- [Domain Resolution](/reference/resolve/) - Complete guide to reading domain data
+- [Profile Widget](/reference/widget/) - Customize the React component
+- [Domain Operations](/reference/operations/) - Write operations (requires wallet)
+
+**🛠️ Guides**
+
+- [Buy a .night domain](/guides/buy_domain/) - Get your own domain
+- [Update domain fields](/guides/update_fields/) - Customize your profile
+- [Transfer domains](/guides/transfer_domain/) - Transfer ownership
+
+**📚 Reference**
+
+- [Utility Functions](/reference/utils/) - Helper functions for validation
+- [MNS Specification](/guides/valid_domains/) - Domain naming rules
+- [Types Reference](/reference/types/) - TypeScript type definitions
+
+
+
+## Example Projects
+
+### Minimal DApp Integration
+
+A simple CLI DApp to visualize a Midnight Network stored profile through Midnames SDK tools.
+
+```typescript
+// app.ts
+import { getDomainProfile } from "@midnames/sdk";
+
+async function main() {
+ const domain = process.argv[2] || "alice.night";
+ const result = await getDomainProfile(domain);
+
+ if (!result.success) {
+ console.error("Error:", result.error.message);
+ process.exit(1);
+ }
+
+ const { fullDomain, resolvedTarget, info, fields } = result.data;
+
+ console.log(` === ${fullDomain} === `);
+ console.log(` Owner: ${info?.owner || "N/A"}`);
+ console.log(` Target: ${resolvedTarget || "N/A"}`);
+ console.log(` Name: ${fields.get("name") || "N/A"}`);
+ console.log(` Bio: ${fields.get("bio") || "N/A"}`);
+ console.log(` Website: ${fields.get("website") || "N/A"}`);
+}
+
+main();
+```
+
+```bash
+# Run it
+npx ts-node app.ts foo.night
+```
+
+### React App with Widget
+
+```tsx
+// App.tsx
+import { useState } from "react";
+import "@midnames/sdk/styles.css";
+import { DomainProfileWidget } from "@midnames/sdk/react/DomainProfileWidget";
+
+export default function App() {
+ const [domain, setDomain] = useState("alice.night");
+
+ return (
+
+
Midnames Profile Viewer
+
+ setDomain(e.target.value)}
+ placeholder="Enter a .night domain"
+ style={{ width: "100%", padding: "0.5rem", marginBottom: "1rem" }}
+ />
+
+ {
+ console.error("Widget error:", error);
+ }}
+ />
+
+ );
+}
+```
+
+## Troubleshooting
+
+### "Domain not found" for valid domains
+
+- Check that you're using the correct network with your wallet provider (TestNet vs MainNet)
+- Verify the domain is actually registered at [ns.midnames.com](https://ns.midnames.com)
+- Ensure `.night` TLD is included (use `normalizeDomain()` helper)
+
+### React widget not styling correctly
+
+- Make sure you imported the CSS: `import '@midnames/sdk/styles.css'`
+- Check for CSS conflicts with your app's global styles
+- Try wrapping in a container with `className` to isolate styles
+
+### TypeScript errors
+
+- Ensure you have `@midnight-ntwrk` peer dependencies installed
+- Check your `tsconfig.json` has `"moduleResolution": "bundler"` or `"node"`
+- Import types explicitly if needed: `import type { DomainProfileData } from '@midnames/sdk'`
+
+### Network connection issues
+
+- Verify your internet connection
+- Check if the indexer is accessible (default: `https://indexer.testnet-02.midnight.network`)
+- Try with a custom provider to rule out default configuration issues
+
+## Community & Support
+
+- **Documentation**: [https://docs.midnames.com](/)
+- **GitHub**: [https://github.com/midnames/sdk](https://github.com/midnames/sdk)
+- **Issues**: [Report bugs](https://github.com/midnames/sdk/issues)
+
+Ready to dive deeper? Check out the [complete API reference](/reference/) or explore specific [guides](/guides/).
diff --git a/src/content/docs/guides/transfer_domain.mdx b/src/content/docs/guides/transfer_domain.mdx
index a4a5aaf..967d593 100644
--- a/src/content/docs/guides/transfer_domain.mdx
+++ b/src/content/docs/guides/transfer_domain.mdx
@@ -21,6 +21,7 @@ Ensure you have:
- Lace Wallet for Midnight installed
- The wallet address of the recipient
+- Enough funds in your wallet to sign your transaction
## Transfer Process
@@ -71,6 +72,11 @@ Ensure you have:

+
+
+
## Common Issues
**Transfer failed?**
diff --git a/src/content/docs/guides/update_fields.mdx b/src/content/docs/guides/update_fields.mdx
index 58eefed..01f72d3 100644
--- a/src/content/docs/guides/update_fields.mdx
+++ b/src/content/docs/guides/update_fields.mdx
@@ -1,6 +1,431 @@
---
-title: Update fields in a domain
-description: Learn how to update the records in a domain in Midnight
+title: Update Domain Fields
+description: Learn how to update custom fields in your .night domain
sidebar:
- label: Update fields in a domain
+ label: Update Domain Fields
---
+
+import { Aside, Steps } from "@astrojs/starlight/components";
+
+Learn how to update custom fields in your `.night` domain using the Midnames SDK. Fields allow you to store profile information, social links, and metadata on-chain.
+
+## What are Domain Fields?
+
+Domain fields are key-value pairs stored in your domain's contract. They allow you to:
+
+- Store profile information (name, bio, avatar, banner)
+- Add social media links (Twitter, GitHub, website, etc.)
+- Set privacy settings (encryption public key)
+- Store custom metadata specific to your application
+
+
+
+## Standard Fields
+
+These fields are recognized across the Midnames ecosystem:
+
+| Field | Purpose | Example |
+| ---------- | -----------------------------------| ------------------------- |
+| `name` | Display name | `"Alice Cooper"` |
+| `bio` | Short biography | `"Web3 Developer"` |
+| `avatar` | HTTPS URL or Contract Address/IPFS | see [Avatar Types](/reference/resolve/#avatar-types) |
+| `website` | Personal website | `"https://alice.dev"` |
+| `twitter` | Twitter handle | `"@alice"` or `"alice"` |
+| `github` | GitHub username | `"alice"` |
+| `location` | Location | `"San Francisco"` |
+| `epk` | Encryption public key | `"mn_shield-epk_test..."` |
+| `email` | Email address | `"alice@example.com"` |
+| `discord` | Discord handle | `"alice#1234"` |
+| `telegram` | Telegram username | `"@alice"` |
+
+
+
+## Prerequisites
+
+To update fields, you need:
+
+1. **Lace Wallet** installed and funded ([Get Lace](https://docs.midnight.network/develop/tutorial/using/chrome-ext))
+2. **Domain ownership** - You must own the domain to update its fields
+3. **Funded wallet** for blockchain transactions
+4. **SDK setup** with wallet providers (see [Domain Operations](/reference/operations/#prerequisites))
+
+## Update a Single Field
+
+### Using the SDK
+
+```typescript
+import { insertField } from '@midnames/sdk';
+
+async function updateBio(domain: string, providers) {
+ const result = await insertField(
+ domain,
+ 'bio',
+ 'Web3 Developer | Midnight Enthusiast',
+ providers
+ );
+
+ if (result.success) {
+ console.log('Field updated!', result.data.transactionId);
+ } else {
+ console.error('Update failed:', result.error.message);
+ }
+}
+
+await updateBio('alice.night', providers);
+```
+
+### Common Updates
+
+```typescript
+// Update profile name
+await insertField('alice.night', 'name', 'Alice Cooper', providers);
+
+// Set avatar
+await insertField('alice.night', 'avatar', 'https://avatars.example.com/alice.png', providers);
+
+// Add Twitter
+await insertField('alice.night', 'twitter', '@alice', providers);
+
+// Add website
+await insertField('alice.night', 'website', 'https://alice.dev', providers);
+
+// Set encryption key
+await insertField('alice.night', 'epk', 'mn_shield-epk_test1...', providers);
+```
+
+## Update Multiple Fields
+
+For efficiency, Midnames SDK provides batch addition for multiple fields in a single transaction:
+
+```typescript
+import { addMultipleFields } from '@midnames/sdk';
+
+async function setupProfile(domain: string, providers) {
+ const fields: Array<[string, string]> = [
+ ['name', 'Alice Cooper'],
+ ['bio', 'Web3 Developer | Midnight Enthusiast'],
+ ['avatar', 'https://avatars.example.com/alice.png'],
+ ['website', 'https://alice.dev'],
+ ['twitter', '@alice'],
+ ['github', 'alice'],
+ ['location', 'San Francisco'],
+ ];
+
+ const result = await addMultipleFields(domain, fields, providers);
+
+ if (result.success) {
+ console.log('Profile setup complete!', result.data.transactionId);
+ } else {
+ console.error('Setup failed:', result.error.message);
+ }
+}
+
+await setupProfile('alice.night', providers);
+```
+
+
+
+## Remove Fields
+
+### Remove a specific field
+
+```typescript
+import { clearField } from '@midnames/sdk';
+
+// Remove Twitter link
+const result = await clearField('alice.night', 'twitter', providers);
+
+if (result.success) {
+ console.log('Field removed:', result.data.transactionId);
+}
+```
+
+### Remove all fields
+
+```typescript
+import { clearAllFields } from '@midnames/sdk';
+
+// Clear entire profile
+const result = await clearAllFields('alice.night', providers);
+
+if (result.success) {
+ console.log('All fields cleared:', result.data.transactionId);
+}
+```
+
+
+
+## Complete Example: Profile Manager
+
+Here's a full React component for managing domain fields:
+
+```tsx
+import { useState } from 'react';
+import { insertField, getDomainProfile } from '@midnames/sdk';
+import type { ContractProviders } from '@midnight-ntwrk/midnight-js-contracts';
+
+function ProfileEditor({ domain, providers }: {
+ domain: string;
+ providers: ContractProviders;
+}) {
+ const [name, setName] = useState('');
+ const [bio, setBio] = useState('');
+ const [twitter, setTwitter] = useState('');
+ const [loading, setLoading] = useState(false);
+
+ const handleSave = async () => {
+ setLoading(true);
+
+ try {
+ // Update each field
+ if (name) {
+ const result = await insertField(domain, 'name', name, providers);
+ if (!result.success) throw result.error;
+ }
+
+ if (bio) {
+ const result = await insertField(domain, 'bio', bio, providers);
+ if (!result.success) throw result.error;
+ }
+
+ if (twitter) {
+ const result = await insertField(domain, 'twitter', twitter, providers);
+ if (!result.success) throw result.error;
+ }
+
+ alert('Profile updated successfully!');
+ } catch (error) {
+ console.error('Update failed:', error);
+ alert('Update failed. See console for details.');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
Edit Profile: {domain}
+
+
+
+ setName(e.target.value)}
+ placeholder="Your display name"
+ style={{ width: '100%', padding: '0.5rem' }}
+ />
+
+
+
+
+
+
+
+
+ setTwitter(e.target.value)}
+ placeholder="@username"
+ style={{ width: '100%', padding: '0.5rem' }}
+ />
+
+
+
+
+ );
+}
+```
+
+## Using Midnames Web App
+
+You can also update fields through the Midnames web interface at [ns.midnames.com](https://ns.midnames.com):
+
+
+
+1. **Connect your wallet**
+
+ Visit [ns.midnames.com](https://ns.midnames.com) and connect your Lace wallet
+
+2. **Search for your domain**
+
+ Enter your domain name in the search bar
+
+3. **Click "Edit Profile"**
+
+ You'll see an edit interface with all available fields
+
+4. **Update fields**
+
+ Fill in any fields you want to update or modify
+
+5. **Save changes**
+
+ Click "Save" and sign the transaction with your wallet
+
+
+
+
+
+## Best Practices
+
+### 1. Use Standard Field Names
+
+Stick to standard field names when possible for maximum compatibility:
+
+```typescript
+// Good - recognized by all MNS apps. Easy to remember.
+await insertField('alice.night', 'twitter', '@alice', providers);
+
+// Less ideal - custom field name. Hard to remember or query.
+await insertField('alice.night', 'twitter_handle', '@alice', providers);
+```
+
+### 2. Validate Before Updating
+
+```typescript
+import { getDomainInfo } from '@midnames/sdk';
+
+async function safeUpdateField(domain: string, key: string, value: string, providers, myAddress: string) {
+ // Verify ownership first
+ const info = await getDomainInfo(domain);
+
+ if (!info.success || info.data.owner !== myAddress) {
+ throw new Error('You do not own this domain');
+ }
+
+ // Now safe to update
+ return await insertField(domain, key, value, providers);
+}
+```
+
+### 3. Batch Updates for Efficiency
+
+```typescript
+// Less efficient - 3 separate transactions, gas for each transaction.
+await insertField('alice.night', 'name', 'Alice', providers);
+await insertField('alice.night', 'bio', 'Developer', providers);
+await insertField('alice.night', 'twitter', '@alice', providers);
+
+// More efficient - single transaction, less gas.
+await addMultipleFields('alice.night', [
+ ['name', 'Alice'],
+ ['bio', 'Developer'],
+ ['twitter', '@alice'],
+], providers);
+```
+
+### 4. Handle Errors Gracefully
+
+```typescript
+async function updateFieldWithFeedback(domain: string, key: string, value: string, providers: PublicDataProviders) {
+ const result = await insertField(domain, key, value, providers);
+
+ if (result.success) {
+ showSuccessToast(`${key} updated!`);
+ return result.data.transactionId;
+ } else {
+ // Handle specific errors
+ switch (result.error.code) {
+ case 'NETWORK_ERROR':
+ showErrorToast('Network error. Please try again.');
+ break;
+ case 'DOMAIN_NOT_FOUND':
+ showErrorToast('Domain not found.');
+ break;
+ default:
+ showErrorToast(`Update failed: ${result.error.message}`);
+ }
+ return null;
+ }
+}
+```
+
+## Field Value Formats
+
+### Avatar URLs
+
+Avatars support multiple formats:
+
+```typescript
+// Standard URL
+await insertField('alice.night', 'avatar', 'https://example.com/avatar.png', providers);
+
+// IPFS
+await insertField('alice.night', 'avatar', 'ipfs://Qm123abc...', providers);
+
+// Midnight NFT Contract : format
+await insertField('alice.night', 'avatar', '0200abc123...:42', providers);
+```
+
+### Social Media Handles
+
+```typescript
+// Twitter - with or without @
+await insertField('alice.night', 'twitter', '@alice', providers);
+await insertField('alice.night', 'twitter', 'alice', providers); // Both work
+
+// GitHub - username only
+await insertField('alice.night', 'github', 'alice', providers);
+
+// Website - include protocol
+await insertField('alice.night', 'website', 'https://alice.dev', providers);
+```
+
+## Troubleshooting
+
+**Transaction fails immediately**
+- Verify you own the domain
+- Check wallet balance (need funds for gas fee)
+- Ensure wallet is connected and unlocked
+
+**Field doesn't appear after update**
+- Wait for transaction confirmation (can take 10-30 seconds)
+- Refresh the page or re-query the domain
+- Check transaction succeeded by viewing on block explorer
+
+**"DOMAIN_NOT_FOUND" error**
+- Verify domain is correctly formatted: `alice.night`
+- Check domain actually exists (query with `getDomainInfo`)
+- Ensure you're on the correct network (TestNet vs MainNet)
+
+**Contact Support**
+- Midnames provides a 24/7 customer support email service for further troubleshooting enquiries.
+
+## Next Steps
+
+- Learn about [domain operations](/reference/operations/) for more advanced write operations
+- Explore the [Profile Widget](/reference/widget/) to display your updated fields
+- Read the [Domain Transfer Guide](/guides/transfer_domain/) to transfer domains
+
+Ready to customize your profile? Head over to [ns.midnames.com](https://ns.midnames.com) or integrate the SDK into your app!
diff --git a/src/content/docs/guides/valid_domains.mdx b/src/content/docs/guides/valid_domains.mdx
index a6de683..22dbf46 100644
--- a/src/content/docs/guides/valid_domains.mdx
+++ b/src/content/docs/guides/valid_domains.mdx
@@ -68,4 +68,4 @@ The following domains are all reserved and cannot be registered:
# Caveats
-All domain parts are valid in the contracts but the frontend (and more importantly the SDK for wallet integration) will restrict the user to only create and resolve domains that follow the above specification.
+All domain parts are valid at the contract level; however, the frontend—and more importantly, the SDK used for wallet integration—will limit users to creating and resolving domains that comply with the specification above.
\ No newline at end of file
diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx
index 677ad5a..ee92a4c 100644
--- a/src/content/docs/index.mdx
+++ b/src/content/docs/index.mdx
@@ -8,18 +8,33 @@ hero:
file: ../../assets/houston.webp
actions:
- text: Read the docs
- link: /guides/buy_domain/
+ link: /guides/quickstart/
icon: right-arrow
---
import { CardGrid, LinkCard } from "@astrojs/starlight/components";
+
+
+
+
+ />
diff --git a/src/content/docs/reference/index.mdx b/src/content/docs/reference/index.mdx
index dd148f8..7c8b50f 100644
--- a/src/content/docs/reference/index.mdx
+++ b/src/content/docs/reference/index.mdx
@@ -1,10 +1,93 @@
---
title: SDK Reference
-description: Here are some references to start using the Midnames SDK.
+description: Complete API reference for the Midnames SDK
sidebar:
hidden: true
---
-Here are some references to start using the Midnames SDK.
+import { CardGrid, LinkCard } from "@astrojs/starlight/components";
-Look through the list on the left to find a guide that suits your needs.
+Complete API documentation for the Midnames SDK. Learn how to resolve domains, manage domain operations, display profile widgets, and use utility functions.
+
+## Core Functionality
+
+
+
+
+
+
+## Components & UI
+
+
+
+
+
+## Utilities & Helpers
+
+
+
+
+
+
+## Quick Links
+
+- **New to the SDK?** Start with the [Quick Start Guide](/guides/quickstart/)
+- **Need examples?** Check out the code examples in each reference page
+- **Looking for guides?** Visit the [Guides section](/guides/)
+
+## Installation
+
+```bash
+npm install @midnames/sdk
+```
+
+For React components:
+
+```bash
+npm install @midnames/sdk react react-dom lucide-react
+```
+
+## Basic Usage
+
+```typescript
+import { resolveDomain, getDomainProfile } from "@midnames/sdk";
+
+// Resolve a domain
+const result = await resolveDomain("alice.night");
+if (result.success) {
+ console.log("Address:", result.data);
+}
+
+// Get full profile
+const profile = await getDomainProfile("alice.night");
+if (profile.success) {
+ console.log("Name:", profile.data.fields.get("name"));
+ console.log("Bio:", profile.data.fields.get("bio"));
+}
+```
+
+## Support
+
+- **Documentation**: Browse through the reference pages on the left
+- **GitHub**: [https://github.com/midnames/sdk](https://github.com/midnames/sdk)
+- **Issues**: [Report bugs or request features](https://github.com/midnames/sdk/issues)
diff --git a/src/content/docs/reference/operations.mdx b/src/content/docs/reference/operations.mdx
new file mode 100644
index 0000000..0225bdd
--- /dev/null
+++ b/src/content/docs/reference/operations.mdx
@@ -0,0 +1,854 @@
+---
+title: Domain Operations
+description: Write operations for managing .night domains
+sidebar:
+ label: Domain Operations
+---
+
+import { Aside, Code } from "@astrojs/starlight/components";
+
+Learn how to perform write operations on `.night` domains, including field management, transfers, and subdomain registration. These operations require a connected wallet with the Midnight SDK.
+
+
+
+The SDK provides the following write operations:
+
+**Field Management:**
+
+- `insertField()` - Add or update a single field
+- `clearField()` - Remove a specific field
+- `clearAllFields()` - Remove all fields
+- `addMultipleFields()` - Add up to 10 fields at once
+
+**Domain Management:**
+
+- `updateDomainTarget()` - Change where the domain resolves to
+- `changeDomainOwner()` - Transfer ownership (executed on domain contract)
+- `transferDomainOwnership()` - Transfer ownership (executed on parent contract)
+
+**Subdomain Operations:**
+
+- `registerDomainFor()` - Register a subdomain (free for parent owner)
+- `buyDomainFor()` - Purchase a subdomain (requires payment)
+
+**Settings:**
+
+- `updateDomainCost()` - Change subdomain pricing
+- `updateDomainColor()` - Change accepted token type
+- `setDomainResolver()` - Update resolver contract
+
+## Prerequisites
+
+### Setup Wallet Providers
+
+All write operations require `ContractProviders` which include your wallet connection:
+
+```typescript
+import { type ContractProviders } from "@midnight-ntwrk/midnight-js-contracts";
+import { leafContractInstance } from "@midnames/sdk";
+
+// Your wallet setup (example using Midnight wallet API)
+const providers: ContractProviders = {
+ privateStateProvider: myPrivateStateProvider,
+ ContractProviders: myContractProviders,
+ walletProvider: myWalletProvider,
+ zkConfigProvider: myZkConfigProvider,
+};
+```
+
+
+
+## Field Management
+
+
+
+
+
+
+
+
+### Insert or Update a Field
+
+Add or update a single field in your domain: {" "}
+
+**Signature:**
+
+```typescript
+async function insertField(domain: string, key: string, value: string, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The .night domain name to modify (e.g., "alice.night")
+- `key` (string) - The field name/key to insert or update (e.g., "twitter", "bio")
+- `value` (string) - The field value to set
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string}>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { insertField } from "@midnames/sdk";
+
+const result = await insertField(
+ "alice.night", // Your domain
+ "twitter", // Field key
+ "@alice", // Field value
+ providers // Wallet providers
+);
+
+if (result.success) {
+ console.log("Transaction ID:", result.data.transactionId);
+} else {
+ console.error("Failed:", result.error.message);
+}
+```
+
+**Common use cases:**
+
+```typescript
+// Update profile information
+await insertField("alice.night", "name", "Alice Cooper", providers);
+await insertField("alice.night", "bio", "Web3 developer", providers);
+await insertField(
+ "alice.night",
+ "avatar",
+ "https://example.com/avatar.png",
+ providers
+);
+
+// Add social links
+await insertField("alice.night", "twitter", "@alice", providers);
+await insertField("alice.night", "github", "alice", providers);
+await insertField("alice.night", "website", "https://alice.dev", providers);
+
+// Set encryption key for shielded addresses
+await insertField("alice.night", "epk", "mn_shield-epk_test1...", providers);
+```
+
+
+
+
+
+
+
+
+### Add Multiple Fields at Once
+
+Add up to 10 fields in a single transaction (more efficient than multiple `insertField` calls): {" "}
+
+**Signature:**
+
+```typescript
+async function addMultipleFields(domain: string, fields: Array<[string, string]>, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The .night domain name to modify
+- `fields` (Array[(string, string)]) - Array of [key, value] tuples, up to 10 entries
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { addMultipleFields } from "@midnames/sdk";
+
+const fields: Array<[string, string]> = [
+ ["name", "Alice Cooper"],
+ ["bio", "Web3 developer & educator"],
+ ["avatar", "https://example.com/avatar.png"],
+ ["twitter", "@alice"],
+ ["github", "alice"],
+ ["website", "https://alice.dev"],
+];
+
+const result = await addMultipleFields("alice.night", fields, providers);
+
+if (result.success) {
+ console.log("All fields added!", result.data.transactionId);
+}
+```
+
+
+
+
+
+
+
+
+
+
+### Clear a Specific Field
+
+Remove a field from your domain: {" "}
+
+**Signature:**
+
+```typescript
+async function clearField(domain: string, key: string, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The .night domain name to modify
+- `key` (string) - The field name/key to remove
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { clearField } from "@midnames/sdk";
+
+const result = await clearField("alice.night", "twitter", providers);
+
+if (result.success) {
+ console.log("Field cleared:", result.data.transactionId);
+}
+```
+
+
+
+
+
+
+
+
+### Clear All Fields
+
+Remove all custom fields from your domain: {" "}
+
+**Signature:**
+
+```typescript
+async function clearAllFields(domain: string, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The .night domain name to modify
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { clearAllFields } from "@midnames/sdk";
+
+const result = await clearAllFields("alice.night", providers);
+
+if (result.success) {
+ console.log("All fields cleared:", result.data.transactionId);
+}
+```
+
+
+
+
+
+
+
+## Domain Target Management
+
+### Update Domain Target
+
+Change where your domain resolves to. The target can be either a wallet address or a contract address: {" "}
+
+**Signature:**
+
+```typescript
+async function updateDomainTarget(domain: string, target: string, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The .night domain name to modify
+- `target` (string) - The target address (wallet address starting with "mn_" or contract address starting with "0200" or "0x")
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { updateDomainTarget } from "@midnames/sdk";
+
+// Point to a wallet address
+const result1 = await updateDomainTarget(
+ "alice.night",
+ "mn_shield-cpk_test1abc...", // Wallet address
+ providers
+);
+
+// Or point to a contract address
+const result2 = await updateDomainTarget(
+ "alice.night",
+ "0200abc123...", // Contract address
+ providers
+);
+```
+
+
+
+
+
+
+
+
+
+## Ownership Transfer
+
+### Transfer Domain Ownership (Method 1)
+
+Transfer ownership using the parent domain's contract: {" "}
+
+**Signature:**
+
+```typescript
+async function transferDomainOwnership(parent: string, subdomain: string, new_owner: string, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `parent` (string) - The parent domain name (e.g., "night" for "alice.night")
+- `subdomain` (string) - The subdomain name without the parent (e.g., "alice")
+- `new_owner` (string) - The wallet address of the new owner
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { transferDomainOwnership } from "@midnames/sdk";
+
+const result = await transferDomainOwnership(
+ "night", // Parent domain
+ "alice", // Subdomain name
+ "mn_shield-cpk_test1xyz...", // New owner's address
+ providers
+);
+
+if (result.success) {
+ console.log("Transfer complete:", result.data.transactionId);
+}
+```
+
+
+
+
+
+
+
+
+
+### Change Domain Owner (Method 2)
+
+Transfer ownership using the domain's own contract: {" "}
+
+**Signature:**
+
+```typescript
+async function changeDomainOwner(domain: string, new_owner: string, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The full domain name to transfer (e.g., "alice.night")
+- `new_owner` (string) - The wallet address of the new owner
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { changeDomainOwner } from "@midnames/sdk";
+
+const result = await changeDomainOwner(
+ "alice.night",
+ "mn_shield-cpk_test1xyz...", // New owner's address
+ providers
+);
+```
+
+**When to use each method:**
+
+- Use `transferDomainOwnership()` when you own the parent domain
+- Use `changeDomainOwner()` when you own the domain itself
+
+
+
+
+
+
+
+## Subdomain Registration
+
+### Register Subdomain (Free)
+
+As a domain owner, you can register subdomains for free: {" "}
+
+**Signature:**
+
+```typescript
+async function registerDomainFor(parent_domain: string, target_owner: string, subdomain: string, resolver: string, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `parent_domain` (string) - The parent domain you own (e.g., "alice.night")
+- `target_owner` (string) - The wallet address of the subdomain owner
+- `subdomain` (string) - The subdomain name to register (e.g., "work")
+- `resolver` (string) - The resolver contract address
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { registerDomainFor } from "@midnames/sdk";
+
+const result = await registerDomainFor(
+ "alice.night", // Parent domain you own
+ "mn_shield-cpk_test1bob...", // Subdomain owner address
+ "work", // Subdomain name
+ "0200contract123...", // Resolver contract address
+ providers
+);
+
+// This creates: work.alice.night
+```
+
+
+
+
+
+
+
+
+
+### Buy Subdomain (Paid)
+
+Purchase a subdomain when you're not the parent owner: {" "}
+
+**Signature:**
+
+```typescript
+async function buyDomainFor(parent_domain: string, subdomain_owner: string, name: string, resolver: string, tokens: bigint, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `parent_domain` (string) - The parent domain (e.g., "alice.night")
+- `subdomain_owner` (string) - The wallet address of the subdomain owner
+- `name` (string) - The subdomain name to purchase (e.g., "blog")
+- `resolver` (string) - The resolver contract address
+- `tokens` (bigint) - Payment amount that must match the parent domain's `domainCost` setting
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { buyDomainFor } from "@midnames/sdk";
+
+const result = await buyDomainFor(
+ "alice.night", // Parent domain
+ "mn_shield-cpk_test1bob...", // Subdomain owner address
+ "blog", // Subdomain name
+ "0200contract456...", // Resolver contract address
+ BigInt(1000), // Payment amount
+ providers
+);
+
+// This creates: blog.alice.night
+```
+
+The payment amount must match the `domainCost` setting of the parent domain.
+
+
+
+
+
+
+
+## Domain Settings
+
+### Update Subdomain Pricing
+Change the cost for others to buy subdomains under your domain:
+
+**Signature:**
+
+```typescript
+async function updateDomainCost(domain: string, new_cost: bigint, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The domain name to update pricing for
+- `new_cost` (bigint) - The new cost in the smallest token unit (use `BigInt(0)` for free)
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { updateDomainCost } from "@midnames/sdk";
+
+const result = await updateDomainCost(
+ "alice.night",
+ BigInt(5000), // New cost (in smallest token unit)
+ providers
+);
+```
+
+**Pricing strategy examples:**
+
+```typescript
+// Free subdomains
+await updateDomainCost("alice.night", BigInt(0), providers);
+
+// Paid subdomains
+await updateDomainCost("alice.night", BigInt(10000), providers);
+
+// Premium subdomains
+await updateDomainCost("premium.alice.night", BigInt(100000), providers);
+```
+
+
+
+
+
+
+
+### Update Accepted Token Type
+
+Change which token type is accepted for subdomain purchases:
+
+**Signature:**
+
+```typescript
+async function updateDomainColor(domain: string, colorBytes: Uint8Array, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The domain name to update token type for
+- `colorBytes` (Uint8Array) - A 32-byte Uint8Array representing the token identifier
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { updateDomainColor } from "@midnames/sdk";
+
+// colorBytes must be a 32-byte Uint8Array representing the token identifier
+const colorBytes = new Uint8Array(32); // Your token color
+
+const result = await updateDomainColor("alice.night", colorBytes, providers);
+```
+
+
+
+
+
+
+
+
+
+### Set Domain Resolver
+
+Update the resolver contract for a subdomain: {" "}
+
+**Signature:**
+
+```typescript
+async function setDomainResolver(domain: string, subdomain_name: string, resolver: string, providers: ContractProviders): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The parent domain name (e.g., "alice.night")
+- `subdomain_name` (string) - The subdomain name without the parent (e.g., "work")
+- `resolver` (string) - The new resolver contract address
+- `providers` (ContractProviders) - Wallet and provider instances for transaction signing
+
+**Returns:**
+
+A `Result<{ transactionId: string }>` containing either:
+- `success: true` with `data` containing the transaction details including `transactionId`
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { setDomainResolver } from "@midnames/sdk";
+
+const result = await setDomainResolver(
+ "alice.night", // Parent domain
+ "work", // Subdomain name
+ "0200newResolver...", // New resolver address
+ providers
+);
+
+// Updates resolver for: work.alice.night
+```
+
+
+
+
+
+
+
+## Error Handling
+
+All operations return a `Result` type:
+
+```typescript
+const result = await insertField("alice.night", "name", "Alice", providers);
+
+if (!result.success) {
+ // Handle errors
+ console.error("Error code:", result.error.code);
+ console.error("Message:", result.error.message);
+
+ switch (result.error.code) {
+ case "NETWORK_ERROR":
+ console.log("Check your network connection");
+ break;
+ case "DOMAIN_NOT_FOUND":
+ console.log("Domain does not exist");
+ break;
+ default:
+ console.log("Unexpected error:", result.error);
+ }
+}
+```
+
+
+
+
+
+
+
+## Transaction Monitoring
+
+All successful operations return a transaction ID:
+
+```typescript
+const result = await insertField("alice.night", "bio", "Hello!", providers);
+
+if (result.success) {
+ const txId = result.data.transactionId;
+ console.log("Transaction submitted:", txId);
+
+ // You can use the Midnight indexer to check transaction status
+ // (exact implementation depends on your setup)
+}
+```
+
+
+
+
+
+
+
+## Best Practices & Recommendations
+
+### 1. Batch Field Updates
+
+Use `addMultipleFields()` instead of multiple `insertField()` calls:
+
+```typescript
+// Less efficient (3 transactions)
+await insertField("alice.night", "name", "Alice", providers);
+await insertField("alice.night", "bio", "Developer", providers);
+await insertField("alice.night", "twitter", "@alice", providers);
+
+// More efficient (1 transaction)
+await addMultipleFields(
+ "alice.night",
+ [
+ ["name", "Alice"],
+ ["bio", "Developer"],
+ ["twitter", "@alice"],
+ ],
+ providers
+);
+```
+
+### 2. Verify Ownership Before Operations
+
+```typescript
+import { getDomainInfo } from "@midnames/sdk";
+
+const info = await getDomainInfo("alice.night");
+if (info.success && info.data.owner === myWalletAddress) {
+ // Safe to proceed with write operations
+ await insertField("alice.night", "bio", "Updated!", providers);
+}
+```
+
+### 3. Handle Transaction Failures Gracefully
+
+```typescript
+async function updateFieldWithRetry(
+ domain: string,
+ key: string,
+ value: string,
+ maxRetries = 3
+) {
+ for (let i = 0; i < maxRetries; i++) {
+ const result = await insertField(domain, key, value, providers);
+
+ if (result.success) {
+ return result.data.transactionId;
+ }
+
+ if (result.error.code !== "NETWORK_ERROR") {
+ // Non-retryable error
+ throw result.error;
+ }
+
+ // Wait before retry
+ await new Promise((resolve) => setTimeout(resolve, 2000 * (i + 1)));
+ }
+
+ throw new Error("Max retries exceeded");
+}
+```
+
+## Complete Example
+
+Here's a full example of setting up a domain profile:
+
+```typescript
+import {
+ addMultipleFields,
+ updateDomainTarget,
+ updateDomainCost,
+} from "@midnames/sdk";
+
+async function setupDomainProfile(
+ domain: string,
+ providers: ContractProviders
+) {
+ // 1. Set up profile fields
+ const fieldsResult = await addMultipleFields(
+ domain,
+ [
+ ["name", "Alice Cooper"],
+ ["bio", "Web3 Developer | Midnight Enthusiast"],
+ ["avatar", "https://avatars.example.com/alice.png"],
+ ["website", "https://alice.dev"],
+ ["twitter", "@alice"],
+ ["github", "alice"],
+ ["epk", "mn_shield-epk_test1..."],
+ ],
+ providers
+ );
+
+ if (!fieldsResult.success) {
+ console.error("Failed to set fields:", fieldsResult.error);
+ return;
+ }
+
+ console.log("Profile fields set:", fieldsResult.data.transactionId);
+
+ // 2. Set domain target
+ const targetResult = await updateDomainTarget(
+ domain,
+ "mn_shield-cpk_test1abc...",
+ providers
+ );
+
+ if (!targetResult.success) {
+ console.error("Failed to set target:", targetResult.error);
+ return;
+ }
+
+ console.log("Target updated:", targetResult.data.transactionId);
+
+ // 3. Configure subdomain pricing
+ const costResult = await updateDomainCost(
+ domain,
+ BigInt(1000), // Charge 1000 for subdomains
+ providers
+ );
+
+ if (!costResult.success) {
+ console.error("Failed to set cost:", costResult.error);
+ return;
+ }
+
+ console.log("Subdomain pricing set:", costResult.data.transactionId);
+ console.log("Domain setup complete!");
+}
+
+// Usage
+await setupDomainProfile("alice.night", providers);
+```
+
+## Next Steps
+
+- Learn about [domain resolution](/reference/resolve/) for reading domain data
+- Explore [utility functions](/reference/utils/) for domain validation and formatting
+- Check the [error handling guide](/reference/types/#error-types) for comprehensive error management
diff --git a/src/content/docs/reference/resolve.mdx b/src/content/docs/reference/resolve.mdx
index 174606a..c997ef5 100644
--- a/src/content/docs/reference/resolve.mdx
+++ b/src/content/docs/reference/resolve.mdx
@@ -1,4 +1,407 @@
---
title: Resolve a .night domain
description: How to use the SDK to resolve a .night domain.
+sidebar:
+ label: Domain Resolution
---
+
+import { Aside, Code, Tabs, TabItem } from "@astrojs/starlight/components";
+
+Learn how to resolve `.night` domains to their target addresses using the Midnames SDK. Domain resolution is the core functionality that allows you to translate human-readable names into blockchain addresses.
+
+The SDK provides several functions for reading domain data:
+
+- **`resolveDomain()`** - Resolve a domain to its target address
+- **`getDomainInfo()`** - Get ownership and resolver information
+- **`getDomainProfile()`** - Get complete profile data including fields
+- **`getDomainFields()`** - Get custom fields stored in a domain
+- **`getDomainSettings()`** - Get domain settings (cost, coin color)
+
+## Installation
+
+```bash
+npm install @midnames/sdk
+```
+
+## Basic Domain Resolution
+
+### Resolve a domain to its target address
+
+The `resolveDomain()` function returns the target address that a domain points to.
+
+**Signature:**
+
+```typescript
+async function resolveDomain(domain: string, options?: ResolveOptions): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The .night domain name to resolve (e.g., "alice.night")
+- `options` (optional) - Configuration object:
+ - `provider` - Custom provider instance for connecting to a specific network
+
+**Returns:**
+
+A `Result` containing either:
+- `success: true` with `data` being the resolved target address (CoinPublicKey or shielded address)
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { resolveDomain } from '@midnames/sdk';
+
+// Resolve a domain
+const result = await resolveDomain('alice.night');
+
+if (result.success) {
+ console.log('Target address:', result.data);
+ // Output: mn_shield-cpk_test1... or 0200...
+} else {
+ console.error('Error:', result.error.message);
+}
+```
+
+
+
+### Using a custom provider
+
+By default, the SDK connects to the Midnight TestNet. You can provide a custom provider:
+
+```typescript
+import { resolveDomain, createDefaultProvider } from "@midnames/sdk";
+import { NetworkId } from "@midnight-ntwrk/midnight-js-network-id";
+
+// Create a custom provider
+const provider = createDefaultProvider({
+ indexerUrl: "https://your-indexer.example.com/api/v1/graphql",
+ indexerWsUrl: "wss://your-indexer.example.com/api/v1/graphql/ws",
+ networkId: NetworkId.TestNet,
+});
+
+// Use it for resolution
+const result = await resolveDomain("alice.night", { provider });
+```
+
+## Get Domain Information
+
+### Get ownership and resolver details
+
+**Signature:**
+
+```typescript
+async function getDomainInfo(domain: string, options?: ResolveOptions): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The .night domain name to query
+- `options` (optional) - Configuration object:
+ - `provider` - Custom provider instance for connecting to a specific network
+
+**Returns:**
+
+A `Result` containing either:
+- `success: true` with `data` being the domain ownership information
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { getDomainInfo } from "@midnames/sdk";
+
+const result = await getDomainInfo("alice.night");
+
+if (result.success) {
+ const { owner, resolver, contractAddress } = result.data;
+ console.log("Owner:", owner); // Wallet address
+ console.log("Resolver:", resolver); // Contract address
+ console.log("Contract:", contractAddress); // Parent contract
+}
+```
+
+**Return type:**
+
+```typescript
+interface DomainInfo {
+ owner: string; // The wallet address that owns the domain
+ resolver: string; // The contract address that resolves the domain
+ contractAddress?: string; // The parent contract address
+}
+```
+
+## Get Complete Domain Profile
+
+### Fetch all domain data in one call
+
+The `getDomainProfile()` function aggregates all domain information including custom fields:
+
+**Signature:**
+
+```typescript
+async function getDomainProfile(domain: string, options?: ResolveOptions): Promise>
+```
+
+**Parameters:**
+
+- `domain` (string) - The .night domain name to query
+- `options` (optional) - Configuration object:
+ - `provider` - Custom provider instance for connecting to a specific network
+
+**Returns:**
+
+A `Result` containing either:
+- `success: true` with `data` being the complete domain profile including target, ownership info, custom fields, and settings
+- `success: false` with an `error` object containing the error details
+
+```typescript
+import { getDomainProfile } from "@midnames/sdk";
+
+const result = await getDomainProfile("id.alice.night");
+
+if (result.success) {
+ const profile = result.data;
+
+ console.log("Domain:", profile.fullDomain);
+ console.log("Target:", profile.resolvedTarget);
+ console.log("Owner:", profile.info?.owner);
+
+ // Access custom fields
+ const name = profile.fields.get("name");
+ const bio = profile.fields.get("bio");
+ const avatar = profile.fields.get("avatar");
+ const twitter = profile.fields.get("twitter");
+
+ console.log("Name:", name);
+ console.log("Bio:", bio);
+}
+```
+
+**Return type:**
+
+```typescript
+interface DomainProfileData {
+ fullDomain: string; // Normalized domain name
+ resolvedTarget: string | null; // Target address or null
+ info: DomainInfo | null; // Ownership info or null
+ fields: Map; // Custom fields as key-value pairs
+ settings: DomainSettings | null; // Domain settings or null
+}
+```
+
+### Common Profile Fields
+
+These fields are recognized by the MidNames ecosystem:
+
+| Field | Description | Example |
+| ---------- | ---------------------------------------- | ------------------------- |
+| `name` | Display name | `"Alice"` |
+| `bio` | Short biography | `"Web3 developer"` |
+| `avatar` | Midnight Contract Address or IPFS or URL | `see below` |
+| `website` | Personal website | `"alice.dev"` |
+| `twitter` | Twitter handle | `"@alice"` |
+| `github` | GitHub username | `"alice"` |
+| `location` | Location | `"San Francisco"` |
+| `epk` | Encryption public key | `"mn_shield-epk_test..."` |
+
+
+
+## Avatar Types
+
+The `avatar` field supports multiple input formats.
+This flexibility lets developers choose between centralized URLs, decentralized IPFS assets, or on-chain contract references.
+
+| Type | Description | Format Example |
+| --------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
+| **URL** | Direct link to an image hosted on the web. | `"https://example.com/avatar.png"` |
+| **IPFS** | Reference to a decentralized image on IPFS (can include a gateway). | `"ipfs://Qm123abc..."` or `"https://ipfs.io/ipfs/Qm123abc..."` |
+| **Midnight Contract** | On-chain avatar reference stored in a Midnight NFT contract, formatted as `:`. | `"0200abc123def456...:42"` |
+
+:::note
+If a contract-based avatar is provided, **Starlight automatically resolves** the NFT metadata and retrieves the associated image.
+:::
+
+## Get Domain Fields
+
+### Retrieve custom fields only
+
+**Signature:**
+
+```typescript
+async function getDomainFields(contractAddress: string, options?: ResolveOptions): Promise>>
+```
+
+**Parameters:**
+
+- `contractAddress` (string) - The contract address of the domain (in hex format starting with "0200...")
+- `options` (optional) - Configuration object:
+ - `provider` - Custom provider instance for connecting to a specific network
+
+**Returns:**
+
+A `Result