diff --git a/apps/site/.gitignore b/apps/site/.gitignore index 5047651..79baa44 100644 --- a/apps/site/.gitignore +++ b/apps/site/.gitignore @@ -18,3 +18,7 @@ yarn-debug.log* .DS_Store .env.local .env*.local +.source + +# T1 migration temp backup of TSX docs pages +_docs_old_tsx_backup/ diff --git a/apps/site/app/api/search/route.ts b/apps/site/app/api/search/route.ts new file mode 100644 index 0000000..d86bfc5 --- /dev/null +++ b/apps/site/app/api/search/route.ts @@ -0,0 +1,4 @@ +import { source } from "@/lib/source"; +import { createFromSource } from "fumadocs-core/search/server"; + +export const { GET } = createFromSource(source); diff --git a/apps/site/app/docs/[[...slug]]/page.tsx b/apps/site/app/docs/[[...slug]]/page.tsx new file mode 100644 index 0000000..d81e90e --- /dev/null +++ b/apps/site/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,95 @@ +import { notFound } from "next/navigation"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import type { Metadata } from "next"; +import type { ComponentType } from "react"; +import { source } from "@/lib/source"; +import { DocPage } from "@/components/docs/doc-page"; +import { CopyPageButton } from "@/components/docs/copy-page-button"; +import { getMDXComponents } from "@/lib/mdx-components"; + +type Props = { params: Promise<{ slug?: string[] }> }; + +// The frontmatter schema (defined in source.config.ts) doesn't flow into source.getPage().data +// as typed fields — fumadocs surfaces them as `unknown` by default. This interface is the +// runtime shape we know exists. +interface DocFrontmatter { + title: string; + description?: string; + importLine?: string; + breadcrumb?: string[]; + prev?: { href: string; label: string }; + next?: { href: string; label: string }; + body: ComponentType<{ components: ReturnType }>; + toc: Array<{ url: string; title: unknown; depth: number }>; +} + +export async function generateMetadata({ params }: Props): Promise { + const { slug } = await params; + const page = source.getPage(slug); + if (!page) return {}; + const data = page.data as unknown as DocFrontmatter; + return { + title: `${data.title} — cdr-kit`, + description: data.description, + }; +} + +export async function generateStaticParams() { + return source.generateParams(); +} + +export default async function Page({ params }: Props) { + const { slug } = await params; + const page = source.getPage(slug); + if (!page) notFound(); + + const data = page.data as unknown as DocFrontmatter; + const MDX = data.body; + + // Map fumadocs TOC ({ url: "#id", title, depth }) → DocTocItem ({ id, label }). + // Only h2/h3 land in the right rail to match the existing scrollspy density. + const tocItems = data.toc + .filter((node) => node.depth <= 3) + .map((node) => ({ + id: node.url.replace(/^#/, ""), + label: typeof node.title === "string" ? node.title : "", + })); + + // Raw MDX for the per-page Copy button. Server-read once; passed as a string + // to the client component so there's no extra fetch round-trip. The MDX file + // path is derived from the URL: /docs/components/x → content/docs/components/x.mdx; + // /docs → content/docs/index.mdx. + let rawMarkdown = ""; + try { + const rel = page.url.replace(/^\/docs\/?/, "") || "index"; + const mdxPath = join(process.cwd(), "content/docs", `${rel}.mdx`); + rawMarkdown = readFileSync(mdxPath, "utf-8"); + } catch (err) { + // Surface but don't crash — the page itself is already rendered via fumadocs + // page.data.body; the Copy button just degrades to an empty payload. + console.warn(`[docs] Failed to read raw MDX for ${page.url}:`, (err as Error).message); + } + + return ( + , + lede: data.description ?? "", + importLine: data.importLine, + prev: data.prev, + next: data.next, + sections: [ + { + id: "content", + title: "", + content: , + }, + ], + }} + tocItems={tocItems} + /> + ); +} diff --git a/apps/site/app/docs/agent-kit/agentkit/page.tsx b/apps/site/app/docs/agent-kit/agentkit/page.tsx deleted file mode 100644 index 138fb1d..0000000 --- a/apps/site/app/docs/agent-kit/agentkit/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const CODE = `import { CdrAgent } from "@cdr-kit/agent"; -import { cdrActionProvider } from "@cdr-kit/agentkit"; - -const agent = new CdrAgent({ privateKey, apiUrl }); -// Slot into Coinbase AgentKit's action providers: -const provider = cdrActionProvider(agent);`; - -export default function Page() { - return ( - @cdr-kit/agentkit, - lede: <>Coinbase AgentKit ActionProvider exposing the three CDR tools as on-chain actions., - importLine: 'import { cdrActionProvider } from "@cdr-kit/agentkit"', - sections: [{ id: "usage", title: "Usage", content: }], - prev: { href: "/docs/agent-kit/langchain", label: "LangChain" }, - next: { href: "/docs/agent-kit/goat", label: "GOAT SDK" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/agent-kit/goat/page.tsx b/apps/site/app/docs/agent-kit/goat/page.tsx deleted file mode 100644 index 032321b..0000000 --- a/apps/site/app/docs/agent-kit/goat/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const CODE = `import { CdrAgent } from "@cdr-kit/agent"; -import { cdrPlugin } from "@cdr-kit/goat"; - -const agent = new CdrAgent({ privateKey, apiUrl }); -const plugin = cdrPlugin(agent); // pass into GOAT's getOnChainTools`; - -export default function Page() { - return ( - @cdr-kit/goat, - lede: <>GOAT SDK plugin exposing the CDR tools to any GOAT-enabled agent stack., - importLine: 'import { cdrPlugin } from "@cdr-kit/goat"', - sections: [{ id: "usage", title: "Usage", content: }], - prev: { href: "/docs/agent-kit/agentkit", label: "Coinbase AgentKit" }, - next: { href: "/docs/agent-kit/mcp", label: "MCP server" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/agent-kit/langchain/page.tsx b/apps/site/app/docs/agent-kit/langchain/page.tsx deleted file mode 100644 index 20aa123..0000000 --- a/apps/site/app/docs/agent-kit/langchain/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const CODE = `import { ChatOpenAI } from "@langchain/openai"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; -import { CdrAgent } from "@cdr-kit/agent"; -import { getLangChainTools } from "@cdr-kit/langchain"; - -const cdr = new CdrAgent({ privateKey, apiUrl }); -const agent = createReactAgent({ - llm: new ChatOpenAI({ model: "gpt-4o" }), - tools: getLangChainTools(cdr), -}); -const res = await agent.invoke({ messages: [{ role: "user", content: "Read vault 4200." }] });`; - -export default function Page() { - return ( - @cdr-kit/langchain, - lede: <>Returns LangChain StructuredToolInterface[] — drop into createReactAgent or any LangChain agent constructor., - importLine: 'import { getLangChainTools } from "@cdr-kit/langchain"', - sections: [{ id: "usage", title: "Usage", content: }], - prev: { href: "/docs/agent-kit/openai", label: "OpenAI / Anthropic" }, - next: { href: "/docs/agent-kit/agentkit", label: "Coinbase AgentKit" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/agent-kit/mcp/page.tsx b/apps/site/app/docs/agent-kit/mcp/page.tsx deleted file mode 100644 index beb0d2c..0000000 --- a/apps/site/app/docs/agent-kit/mcp/page.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const INSTALL = `# Recommended: get the CLI (gives you cdr + cdr mcp + cdr skill install) -$ npm install -g @cdr-kit/cli - -# Alternative: just the MCP wrapper (used by claude mcp add) -$ npm install -g @cdr-kit/mcp`; - -const ADD = `$ claude mcp add cdr-kit npx @cdr-kit/mcp`; - -const JSON_CONFIG = `{ - "mcpServers": { - "cdr-kit": { - "command": "npx", - "args": ["-y", "@cdr-kit/mcp"], - "env": { - "CDR_PRIVATE_KEY": "0x_your_aeneid_testnet_key_here", - "CDR_NETWORK": "aeneid" - } - } - } -}`; - -const TOOLS_TABLE: { name: string; group: string; description: string }[] = [ - { name: "cdr_discover_vaults", group: "Discover + read", description: "Scan recent VaultCreated events; returns uuid, ipId, creator per vault." }, - { name: "cdr_subscribe_and_access", group: "Discover + read", description: "Pay the subscription, then read + decrypt — one composite call." }, - { name: "cdr_access_vault", group: "Discover + read", description: "Read + decrypt a vault the agent is already entitled to." }, - { name: "cdr_access_license_gated", group: "Discover + read", description: "Read a license-gated vault by presenting a Story license token the agent owns." }, - { name: "cdr_get_vault_info", group: "Introspection", description: "Resolve uuid → tokenId, ipId, creator, licenseTermsId. View-only." }, - { name: "cdr_creator_vaults", group: "Introspection", description: "List every vault a given creator has minted. View-only." }, - { name: "cdr_check_entitlement", group: "Introspection", description: "Is the agent (or any address) currently subscribed? Returns paidUntil + isEntitled. View-only." }, - { name: "cdr_estimate_cost", group: "Introspection", description: "Subscription plan: pricePerPeriod, period, payee, mode. View-only." }, - { name: "cdr_list_subscriptions", group: "Introspection", description: "Every vault the agent is currently subscribed to (active paidUntil)." }, - { name: "cdr_get_fees", group: "Introspection", description: "CDR allocate / write / read fees + operational threshold. View-only, no wallet needed." }, - { name: "cdr_create_vault", group: "Author / publish", description: "Mint NFT + register IP + allocate slot + configure read condition — one tx." }, - { name: "cdr_write_vault_data", group: "Author / publish", description: "Encrypt a small (<1KB) UTF-8 string and write it to a vault." }, - { name: "cdr_upload_file", group: "Author / publish", description: "Encrypt + IPFS-pin + allocate + write — for any >1KB payload." }, - // 0.5 advanced-condition vaults - { name: "cdr_create_time_window_vault", group: "Advanced conditions (0.5)", description: "Create a Story CDR vault gated by an absolute time (or block) window." }, - { name: "cdr_create_dead_man_vault", group: "Advanced conditions (0.5)", description: "Create a dead-man-switch vault — auto-unlocks to heirs if the creator stops poke()-ing." }, - { name: "cdr_create_escrow_vault", group: "Advanced conditions (0.5)", description: "Create a buyer-pays-then-confirms-delivery escrow vault with optional arbiter." }, - { name: "cdr_create_multi_sig_vault", group: "Advanced conditions (0.5)", description: "Create an N-of-M multi-sig vault — both off-chain EIP-712 sigs AND on-chain approve() paths supported. First-of-kind in the CDR ecosystem." }, - { name: "cdr_approve_multi_sig", group: "Advanced conditions (0.5)", description: "Safe-style on-chain approval — agent calls approve(uuid). Dashboards read currentApprovalsCount(uuid)." }, - // 0.5 Story IP integration - { name: "cdr_register_ip", group: "Story IP (0.5)", description: "Register an NFT as a Story IP asset (fresh-mint via SPG)." }, - { name: "cdr_attach_license_terms", group: "Story IP (0.5)", description: "Attach PIL license terms to a Story IP asset (required before minting license tokens)." }, - { name: "cdr_mint_license_token", group: "Story IP (0.5)", description: "Mint Story license tokens against an IP asset's licenseTermsId." }, - { name: "cdr_publish_data", group: "Story IP (0.5)", description: "Agent-as-publisher one-shot: register IP + attach commercial terms + create license-gated CDR vault + write encrypted secret. The highest-DX win for autonomous data sellers." }, -]; - -export default function Page() { - return ( - @cdr-kit/mcp22 tools · v0.5, - lede: <>One stdio binary that plugs into Claude Desktop, Cursor, Windsurf, and any MCP host. Exposes the full CDR surface — discover, subscribe, access, audit, publish, plus 4 advanced-condition vault creators and 4 Story IP wrappers (including the cdr_publish_data one-shot) — as 21 tools backed by the agent's own auto-generated wallet. Shares code with @cdr-kit/cli, so anything the MCP can do, cdr <cmd> can do at the terminal., - sections: [ - { - id: "install", - title: "Install", - content: , - }, - { - id: "add-to-claude", - title: "Add to Claude Desktop (one command)", - content: ( - <> -

- If you have Claude Code installed, the cleanest path is: -

- -

- This registers npx @cdr-kit/mcp as the cdr-kit server. The first run auto-generates a wallet at ~/.config/cdr-kit/wallet.json (chmod 600) and prints the address + faucet URL to stderr. Fund it with cdr fund before calling write/subscribe tools. -

- - ), - }, - { - id: "manual-config", - title: "Manual config (Claude Desktop / Cursor / Windsurf)", - content: ( - <> -

- Paste this into your host's MCP config (Claude Desktop:{" "} - ~/Library/Application Support/Claude/claude_desktop_config.json; Cursor:{" "} - ~/.cursor/mcp.json; Windsurf: ~/.codeium/windsurf/mcp_config.json). -

- -

- CDR_PRIVATE_KEY is optional — if omitted, the wallet is auto-generated and loaded from disk on every run. -

- - ), - }, - { - id: "tools", - title: "Tools (13)", - content: ( - <> -

- All tools come from a single source of truth in @cdr-kit/tools. Adapter packages (Vercel AI / OpenAI / LangChain / AgentKit / GOAT) iterate the same list, so every adapter gets all 13 automatically. -

- - - - - - {TOOLS_TABLE.map((t) => ( - - - - - - ))} - -
ToolGroupDescription
{t.name}{t.group}{t.description}
- - ), - }, - { - id: "env", - title: "Env reference", - content: ( - - - - - - - - - - -
VarDefaultPurpose
CDR_PRIVATE_KEY(auto-generated)Agent's wallet. Overrides the disk file at ~/.config/cdr-kit/wallet.json.
CDR_NETWORKaeneidaeneid (default) or mainnet (throws — not yet deployed).
CDR_RPC_URLnetwork's canonical RPCOverride the JSON-RPC endpoint (use a paid RPC for production).
CDR_API_URLnetwork's canonical Story-API RESTOverride the Story-API base URL.
LOG_LEVELinfopino level: trace, debug, info, warn, error.
PRIVATE_KEY(deprecated)Old name for CDR_PRIVATE_KEY. Still honored in 0.4 with a deprecation warning; removed in 0.5.
- ), - }, - ], - prev: { href: "/docs/agent-kit/goat", label: "GOAT SDK" }, - next: { href: "/docs/cli", label: "CLI: cdr" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/agent-kit/openai/page.tsx b/apps/site/app/docs/agent-kit/openai/page.tsx deleted file mode 100644 index 36059ac..0000000 --- a/apps/site/app/docs/agent-kit/openai/page.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const CODE = `import OpenAI from "openai"; -import { CdrAgent } from "@cdr-kit/agent"; -import { getOpenAITools } from "@cdr-kit/openai"; - -const agent = new CdrAgent({ privateKey, apiUrl }); -const { tools, dispatch } = getOpenAITools(agent); - -const openai = new OpenAI(); -const res = await openai.chat.completions.create({ - model: "gpt-4o", - tools, // JSON-schema tool definitions - messages: [{ role: "user", content: "Find and read vault 4200." }], -}); -// route tool calls back through dispatch(name, args)`; - -export default function Page() { - return ( - @cdr-kit/openai, - lede: <>JSON-Schema tools[] + a dispatch router for OpenAI Chat Completions / Anthropic Messages. Works with either provider., - importLine: 'import { getOpenAITools } from "@cdr-kit/openai"', - sections: [{ id: "usage", title: "Usage", content: }], - prev: { href: "/docs/agent-kit/vercel-ai", label: "Vercel AI SDK" }, - next: { href: "/docs/agent-kit/langchain", label: "LangChain" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/agent-kit/page.tsx b/apps/site/app/docs/agent-kit/page.tsx deleted file mode 100644 index fbeaf54..0000000 --- a/apps/site/app/docs/agent-kit/page.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import Link from "next/link"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const CODE = `import { CdrAgent } from "@cdr-kit/agent"; - -const agent = new CdrAgent({ - privateKey: process.env.PRIVATE_KEY, - apiUrl: process.env.CDR_API_URL, -}); - -const vaults = await agent.discover(); -const bytes = await agent.subscribeAndAccess({ - uuid: vaults[0].uuid, - periods: 1n, - maxPricePerPeriod: 5n * 10n ** 18n, - value: 5n * 10n ** 18n, -});`; - -export default function AgentKitPage() { - return ( - @cdr-kit/agent, - lede: <>Autonomous agent client: discover vaults on the factory, subscribe from its own wallet, decrypt, and use the data — no human in the loop. The headless object every framework adapter wraps., - importLine: 'import { CdrAgent } from "@cdr-kit/agent"', - sections: [ - { - id: "usage", - title: "Usage", - content: , - }, - { - id: "adapters", - title: "Framework adapters", - content: ( -
    -
  • @cdr-kit/vercel-aigenerateText tools
  • -
  • @cdr-kit/openai — OpenAI / Anthropic JSON-schema tools
  • -
  • @cdr-kit/langchainStructuredTools
  • -
  • @cdr-kit/agentkit — Coinbase AgentKit ActionProvider
  • -
  • @cdr-kit/goat — GOAT SDK plugin
  • -
  • @cdr-kit/mcp — MCP server
  • -
- ), - }, - ], - prev: { href: "/docs/hooks/use-cdr-wallet", label: "useCdrWallet" }, - next: { href: "/docs/agent-kit/vercel-ai", label: "Vercel AI SDK" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/agent-kit/vercel-ai/page.tsx b/apps/site/app/docs/agent-kit/vercel-ai/page.tsx deleted file mode 100644 index 924259a..0000000 --- a/apps/site/app/docs/agent-kit/vercel-ai/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const CODE = `import { generateText, stepCountIs } from "ai"; -import { anthropic } from "@ai-sdk/anthropic"; -import { CdrAgent } from "@cdr-kit/agent"; -import { getVercelAITools } from "@cdr-kit/vercel-ai"; - -const agent = new CdrAgent({ privateKey, apiUrl }); - -const { text } = await generateText({ - model: anthropic("claude-sonnet-4-6"), - tools: getVercelAITools(agent), - stopWhen: stepCountIs(8), - prompt: "Find a CDR vault, subscribe if needed, and tell me the signal.", -});`; - -export default function Page() { - return ( - @cdr-kit/vercel-ai, - lede: <>Returns a ToolSet for generateText / streamText. The model autonomously picks the three CDR tools and drives the loop., - importLine: 'import { getVercelAITools } from "@cdr-kit/vercel-ai"', - sections: [{ id: "usage", title: "Usage", content: }], - prev: { href: "/docs/agent-kit", label: "CdrAgent" }, - next: { href: "/docs/agent-kit/openai", label: "OpenAI / Anthropic" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/cli/page.tsx b/apps/site/app/docs/cli/page.tsx deleted file mode 100644 index dc50178..0000000 --- a/apps/site/app/docs/cli/page.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const INSTALL = `$ npm install -g @cdr-kit/cli -$ cdr --help`; - -const FIRST_RUN = `$ cdr wallet -# first run prints a banner with the auto-generated address + faucet URL → stderr -# subsequent runs return the wallet state as JSON / pretty-printed object`; - -const COMMANDS: { name: string; description: string }[] = [ - { name: "cdr mcp", description: "Start the stdio MCP server. Same surface @cdr-kit/mcp exposes." }, - { name: "cdr wallet [--json]", description: "Show address, network, balance, wallet path (doctor command)." }, - { name: "cdr wallet new [--force]", description: "Force-generate a new wallet (refuses to overwrite without --force)." }, - { name: "cdr wallet export --yes", description: "Print the private key (DANGEROUS — requires --yes to confirm)." }, - { name: "cdr fund", description: "Print address + open the Aeneid faucet in your browser (captcha-gated)." }, - { name: "cdr config", description: "Print resolved network / RPC / API URL / wallet path." }, - { name: "cdr fees", description: "Allocate / write / read fees + operational threshold (view-only)." }, - { name: "cdr discover [--from-block N]", description: "Scan factory VaultCreated events." }, - { name: "cdr vault info ", description: "Vault info + plan + your entitlement, in one call." }, - { name: "cdr vault list --creator ", description: "Every vault a creator has minted." }, - { name: "cdr vault create --read --read-config [--license-terms-id N]", description: "Create + configure + allocate — one tx." }, - { name: "cdr subscribe [--periods N] [--max-price wei]", description: "Subscribe to + read a subscription-gated vault." }, - { name: "cdr access [--aux-data hex]", description: "Read a vault you're already entitled to." }, - { name: "cdr access-license --license-token-id N", description: "Read a license-gated vault by presenting a Story license token." }, - { name: "cdr subscriptions", description: "Every vault the agent is currently subscribed to." }, - { name: "cdr tools", description: "Enumerate all 34 MCP tools (introspection)." }, - { name: "cdr skill install", description: "Install the cdr-kit Claude Code plugin into ~/.claude/skills/cdr-kit/." }, - // 0.5 advanced-condition vault creators - { name: "cdr create time-window --start --end [--block-based]", description: "Create a TimeWindowCondition vault — read allowed only during [startTs, endTs]." }, - { name: "cdr create dead-man --duration --heirs [--public-after]", description: "Create a DeadManSwitchCondition vault — auto-unlocks to heirs after the heartbeat lapses." }, - { name: "cdr create escrow --price --timeout [--arbiter ]", description: "Create a ConditionalEscrowCondition vault — buyer pays, confirms, then reads." }, - { name: "cdr create multi-sig --signers --threshold ", description: "Create an N-of-M MultiSigCondition vault (off-chain sigs OR on-chain approve)." }, - // 0.5 condition mutators - { name: "cdr poke ", description: "Reset the dead-man-switch heartbeat for a vault you created." }, - { name: "cdr multi-sig approve ", description: "On-chain Safe-style approval — agent must be a configured signer." }, - { name: "cdr multi-sig sign --caller --deadline ", description: "Produce an off-chain EIP-712 sig for collecting threshold-many off-band." }, - { name: "cdr multi-sig access --deadline --sigs ", description: "Read a multi-sig vault by submitting collected off-chain sigs." }, - { name: "cdr multi-sig rotate --signers --threshold ", description: "Creator-only signer rotation; bumps epoch (invalidates BOTH paths)." }, - { name: "cdr escrow pay --price ", description: "Buyer step 1 — escrow the listing price (excess refunded same tx)." }, - { name: "cdr escrow confirm ", description: "Buyer step 2 — confirm delivery, releases funds + grants read." }, - { name: "cdr escrow claim-timeout --buyer ", description: "Seller — claim funds + grant buyer read after timeoutSecs of silence." }, - { name: "cdr escrow arbiter-refund --buyer ", description: "Arbiter — refund a buyer who paid but disputes delivery." }, - // 0.5 Story IP - { name: "cdr ip register --spg [--metadata ]", description: "Register a freshly-minted SPG NFT as a Story IP asset." }, - { name: "cdr ip attach-terms --ip --terms-id ", description: "Attach existing PIL license terms to an IP." }, - { name: "cdr ip mint-license --licensor --terms-id [--amount N]", description: "Mint Story license tokens against an IP's licenseTermsId." }, - { name: "cdr ip register-derivative --child --parents --terms-ids ", description: "Register a derivative IP — child inherits parents' PIL terms." }, - { name: "cdr ip wrap-ip --amount ", description: "Wrap native IP into WIP (required before paying royalties)." }, - { name: "cdr ip approve-wip --spender --amount ", description: "Approve a spender (typically RoyaltyModule) to pull WIP." }, -]; - -const FLAGS = `--network aeneid|mainnet # default aeneid; mainnet throws (not yet deployed) ---json # machine-readable JSON output for any command`; - -export default function Page() { - return ( - @cdr-kit/cli0.5 · 25 commands, - lede: <>One binary, three surfaces. cdr ships every cdr-kit operation as a human-friendly CLI command (25 commands across wallet / discovery / advanced conditions / Story IP); cdr mcp starts the stdio MCP server (same 34 tools); cdr skill install drops the multi-skill Claude Code plugin into ~/.claude/skills/cdr-kit/. Auto-creates the agent's wallet on first run — no "bring your own private key" friction., - sections: [ - { id: "install", title: "Install", content: }, - { - id: "first-run", - title: "First run", - content: ( - <> - -

- The wallet is generated by viem's generatePrivateKey(), stored at ~/.config/cdr-kit/wallet.json (resolved cross-platform via env-paths), and written with chmod 600. Override anytime with CDR_PRIVATE_KEY=0x.... -

- - ), - }, - { - id: "commands", - title: "Commands", - content: ( - - - - {COMMANDS.map((c) => ( - - - - - ))} - -
CommandDescription
{c.name}{c.description}
- ), - }, - { - id: "flags", - title: "Global flags", - content: , - }, - { - id: "mcp", - title: "Use as MCP server", - content: ( - <> -

- cdr mcp is the same stdio server @cdr-kit/mcp ships. Either binary works for MCP host configs — most prefer npx @cdr-kit/mcp for zero install footprint. -

- - - ), - }, - ], - prev: { href: "/docs/agent-kit/mcp", label: "MCP server" }, - next: { href: "/docs/skill", label: "Claude Code plugin" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/access-stepper/page.tsx b/apps/site/app/docs/components/access-stepper/page.tsx deleted file mode 100644 index 0b6003d..0000000 --- a/apps/site/app/docs/components/access-stepper/page.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { AccessStepperDemo } from "@/components/gallery/access-stepper-demo"; - -const CODE = `import { AccessStepper } from "@cdr-kit/react-ui"; -import { useAccessVault } from "@cdr-kit/react"; - -function Stepper({ uuid }) { - const { status, progress } = useAccessVault(uuid); - return ; -}`; - -export default function Page() { - return ( - ", - badges: styled, - lede: <>Designed wait-state UI for the 2-step pay→access flow. Derives step state from useAccessVault's status + an optional {`{collected, threshold}`} for the determinate partial-collection bar., - importLine: 'import { AccessStepper } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: } code={CODE} badge={phase selector} />, - }, - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/components/condition-badge", label: "ConditionBadge" }, - next: { href: "/docs/components/subscribe-button", label: "SubscribeButton" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/cdr-error/page.tsx b/apps/site/app/docs/components/cdr-error/page.tsx deleted file mode 100644 index c8088fb..0000000 --- a/apps/site/app/docs/components/cdr-error/page.tsx +++ /dev/null @@ -1,60 +0,0 @@ -"use client"; - -import { CdrError } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const CODE = `import { CdrError } from "@cdr-kit/react-ui"; - - refetch()} -/>`; - -export default function Page() { - return ( - ", - badges: DX primitive, - lede: <>Soft-bordered danger state with an optional retry CTA. Pair with caught errors from useAccessVault or useSubscribeAndAccess., - importLine: 'import { CdrError } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - undefined} - /> - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - void", description: "When set, renders the retry button on the right." }, - { name: "retryLabel", type: "string", defaultValue: '"Retry"', description: "Retry button label." }, - ]} /> - ), - }, - ], - prev: { href: "/docs/components/cdr-progress", label: "CdrProgress" }, - next: { href: "/docs/agent-kit", label: "Agent kit" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/cdr-inspector/page.tsx b/apps/site/app/docs/components/cdr-inspector/page.tsx deleted file mode 100644 index 8497471..0000000 --- a/apps/site/app/docs/components/cdr-inspector/page.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { CdrInspectorDemo } from "@/components/docs/demos/headless-demos"; - -const CODE = `import { CdrInspector } from "@cdr-kit/react"; - -export function App() { - return ( - - {process.env.NODE_ENV !== "production" && } - {/* …rest of app */} - - ); -}`; - -export default function CdrInspectorPage() { - return ( - ", - badges: dev tool, - lede: ( - <> - Drop-in debug strip showing how the kit is wired (mock vs live, WASM ready, API - URL). Keep it in dev builds; remove or guard for production. - - ), - importLine: 'import { CdrInspector } from "@cdr-kit/react"', - sections: [ - { id: "preview", title: "Live preview", content: } code={CODE} /> }, - ], - prev: { href: "/docs/components/vault", label: "Vault compound" }, - next: { href: "/docs/components/cdr-skeleton", label: "CdrSkeleton" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/cdr-network-chip/page.tsx b/apps/site/app/docs/components/cdr-network-chip/page.tsx deleted file mode 100644 index c92272d..0000000 --- a/apps/site/app/docs/components/cdr-network-chip/page.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { CdrNetworkChip } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const CODE = `import { CdrNetworkChip } from "@cdr-kit/react-ui"; - - -`; - -export default function Page() { - return ( - ", - badges: DX primitive, - lede: <>Pill with a glowing status dot indicating live vs mock mode. Drop into your app chrome so users always know whether they're hitting Aeneid or the in-memory mock., - importLine: 'import { CdrNetworkChip } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - - - - - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/components/ip-price", label: "IpPrice" }, - next: { href: "/docs/components/cdr-spinner", label: "CdrSpinner" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/cdr-progress/page.tsx b/apps/site/app/docs/components/cdr-progress/page.tsx deleted file mode 100644 index 8e57087..0000000 --- a/apps/site/app/docs/components/cdr-progress/page.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { CdrProgress } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const CODE = `import { CdrProgress } from "@cdr-kit/react-ui"; - - -`; - -export default function Page() { - return ( - ", - badges: DX primitive, - lede: <>Determinate progress bar with a primary→signal gradient fill. Pass a value 0–100, or pass {`{collected, threshold}`} and the component derives it., - importLine: 'import { CdrProgress } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - - - - - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/components/cdr-spinner", label: "CdrSpinner" }, - next: { href: "/docs/components/cdr-error", label: "CdrError" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/cdr-provider/page.tsx b/apps/site/app/docs/components/cdr-provider/page.tsx deleted file mode 100644 index 6283c9c..0000000 --- a/apps/site/app/docs/components/cdr-provider/page.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; - -export default function CdrProviderPage() { - return ( - component, - lede: ( - <> - Batteries-included root provider. Wires WagmiProvider, react-query, and initializes the CDR - crypto WASM. Use CdrConfigProvider directly if you already have your own wagmi stack - (Privy / RainbowKit). - - ), - importLine: 'import { CdrProvider } from "@cdr-kit/react"', - sections: [ - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/theming", label: "Theming" }, - next: { href: "/docs/components/vault-gate", label: "VaultGate" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/cdr-skeleton/page.tsx b/apps/site/app/docs/components/cdr-skeleton/page.tsx deleted file mode 100644 index 30dec03..0000000 --- a/apps/site/app/docs/components/cdr-skeleton/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { CdrSkeletonDemo } from "@/components/docs/demos/headless-demos"; - -const CODE = `import { CdrSkeleton } from "@cdr-kit/react"; - - -`; - -export default function CdrSkeletonPage() { - return ( - ", - lede: <>Default placeholder rendered by <VaultGate> / <Vault.Loading> when no custom loading slot is supplied. Themeable via --cdr-skeleton., - importLine: 'import { CdrSkeleton } from "@cdr-kit/react"', - sections: [ - { id: "preview", title: "Live preview", content: } code={CODE} /> }, - { id: "props", title: "Props", content: }, - ], - prev: { href: "/docs/components/cdr-inspector", label: "CdrInspector" }, - next: { href: "/docs/components/empty-vaults", label: "EmptyVaults" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/cdr-spinner/page.tsx b/apps/site/app/docs/components/cdr-spinner/page.tsx deleted file mode 100644 index d627cdf..0000000 --- a/apps/site/app/docs/components/cdr-spinner/page.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { CdrSpinner } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const CODE = `import { CdrSpinner } from "@cdr-kit/react-ui"; - - -`; - -export default function Page() { - return ( - ", - badges: DX primitive, - lede: <>Indeterminate CSS spinner. Use when you don't have a determinate progress to show (e.g. wallet confirmation)., - importLine: 'import { CdrSpinner } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - - - - - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/components/cdr-network-chip", label: "CdrNetworkChip" }, - next: { href: "/docs/components/cdr-progress", label: "CdrProgress" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/components.css b/apps/site/app/docs/components/components.css deleted file mode 100644 index 2c1fe6b..0000000 --- a/apps/site/app/docs/components/components.css +++ /dev/null @@ -1,88 +0,0 @@ -/* Components index — grid of cards + a "live" sampler at the bottom. */ - -.comp-section { margin-top: 44px; } -.comp-section-head { margin-bottom: 18px; } -.comp-section-head h2 { - font-family: var(--display); font-size: 1.3rem; font-weight: 700; letter-spacing: -0.02em; - display: block; margin: 0 0 4px; -} -.comp-section-head h2::after { display: none; } -.comp-section-head p { font-size: 0.92rem; color: var(--ink-2); margin: 0; } - -.comp-subheading { - font-family: var(--mono); font-size: 0.74rem; font-weight: 500; - letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); - margin: 26px 0 12px; -} - -.comp-grid { - display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; -} -@media (max-width: 720px) { .comp-grid { grid-template-columns: 1fr; } } -.comp-card { - display: flex; flex-direction: column; gap: 6px; - padding: 14px 16px; - border: 1px solid var(--line); border-radius: var(--r-md); - background: var(--card); - transition: border-color .14s, transform .14s, box-shadow .14s; -} -.comp-card:hover { border-color: var(--line-2); transform: translateY(-2px); box-shadow: var(--sh-1); } -.comp-card-head { display: flex; align-items: center; gap: 8px; } -.comp-name { font-family: var(--mono); font-size: 0.84rem; color: var(--primary); font-weight: 500; } -.comp-tag { - font-family: var(--mono); font-size: 0.62rem; color: var(--ink-3); - border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; letter-spacing: 0.02em; -} -.comp-desc { font-size: 0.86rem; color: var(--ink-2); line-height: 1.5; margin: 0; } - -/* Live sampler bits (subset of the old gallery.css). */ -.spec-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; } - -.phasectl { - display: inline-flex; gap: 2px; padding: 3px; border: 1px solid var(--line); - border-radius: var(--r-md); background: var(--paper-2); margin-bottom: 22px; flex-wrap: wrap; -} -.phasectl button { - font-family: var(--mono); font-size: 0.74rem; padding: 6px 11px; border-radius: var(--r-sm); - color: var(--ink-2); transition: all .14s; -} -.phasectl button[aria-pressed="true"] { background: var(--card); color: var(--ink); box-shadow: var(--sh-1); } - -.vgrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; width: 100%; } -@media (max-width: 620px) { .vgrid { grid-template-columns: 1fr; } } - -.prim-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; } -@media (max-width: 620px) { .prim-grid { grid-template-columns: 1fr; } } -.prim { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--card); padding: 16px; } -.prim .pn { font-family: var(--mono); font-size: 0.78rem; color: var(--primary); margin-bottom: 10px; } -.prim .pdemo { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-height: 36px; } - -/* Unlockable demo prose styling — premium magazine feel without competing with the pill itself. */ -.unl-demo { font-family: var(--sans); color: var(--ink); max-width: 580px; } -.unl-demo-title { font-family: var(--display); font-size: 1.55rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.15; margin: 0 0 4px; color: var(--ink); } -.unl-demo-byline { font-family: var(--mono); font-size: 0.74rem; color: var(--ink-3); margin: 0 0 22px; letter-spacing: 0.04em; text-transform: uppercase; } -.unl-demo p { font-size: 1rem; line-height: 1.72; color: var(--ink-2); margin: 0 0 16px; } -.unl-demo p:last-child { margin-bottom: 0; } - -/* Docs-page CTA banner that points readers at the showcase. */ -.unl-doc-cta { - display: block; - padding: 18px 22px; - margin: 8px 0 26px; - border-radius: var(--r-md); - border: 1px solid var(--primary-line); - background: linear-gradient(135deg, var(--primary-soft), var(--card)); - text-decoration: none; - color: var(--ink); - transition: transform .14s, border-color .18s, box-shadow .18s; -} -.unl-doc-cta:hover { transform: translateY(-1px); border-color: var(--primary); box-shadow: var(--sh-2); } -.unl-doc-cta-eyebrow { - display: block; font-family: var(--mono); font-size: 0.68rem; - letter-spacing: 0.1em; text-transform: uppercase; color: var(--primary); margin-bottom: 6px; -} -.unl-doc-cta-title { - display: block; font-family: var(--display); font-size: 1.15rem; font-weight: 700; - letter-spacing: -0.01em; color: var(--ink); margin-bottom: 4px; -} -.unl-doc-cta-sub { display: block; font-size: 0.88rem; color: var(--ink-2); line-height: 1.5; } diff --git a/apps/site/app/docs/components/condition-badge/page.tsx b/apps/site/app/docs/components/condition-badge/page.tsx deleted file mode 100644 index cd8606d..0000000 --- a/apps/site/app/docs/components/condition-badge/page.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { ConditionBadge } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const CODE = `import { ConditionBadge } from "@cdr-kit/react-ui"; - - - - -`; - -export default function Page() { - return ( - ", - badges: styled, - lede: <>Color-mapped pill for a vault's read-condition kind. Pure presentational, zero app logic., - importLine: 'import { ConditionBadge } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - - - - - - - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/components/empty-vaults", label: "EmptyVaults" }, - next: { href: "/docs/components/access-stepper", label: "AccessStepper" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/copy-button/page.tsx b/apps/site/app/docs/components/copy-button/page.tsx deleted file mode 100644 index bc4973d..0000000 --- a/apps/site/app/docs/components/copy-button/page.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { CopyButton } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const CODE = `import { CopyButton } from "@cdr-kit/react-ui"; - -`; - -export default function Page() { - return ( - ", - badges: DX primitive, - lede: <>Minimal copy-to-clipboard control. Flashes a check icon for 1.4s on success. Composes inside other primitives (e.g. <ShortAddress>)., - importLine: 'import { CopyButton } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - - sample value - - - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/components/vault-card", label: "VaultCard" }, - next: { href: "/docs/components/short-address", label: "ShortAddress" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/empty-vaults/page.tsx b/apps/site/app/docs/components/empty-vaults/page.tsx deleted file mode 100644 index 7ba4365..0000000 --- a/apps/site/app/docs/components/empty-vaults/page.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { DocPage } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { EmptyVaultsDemo } from "@/components/docs/demos/headless-demos"; - -const CODE = `import { EmptyVaults } from "@cdr-kit/react"; - - -No vaults match your filter. - -// typical use: -{vaults.length === 0 - ? No vaults match your filter. - : }`; - -export default function EmptyVaultsPage() { - return ( - ", - lede: <>Semantic empty-state slot — a div[data-cdr-empty] with a default copy fallback. Style at the consumer level., - importLine: 'import { EmptyVaults } from "@cdr-kit/react"', - sections: [ - { id: "preview", title: "Live preview", content: } code={CODE} /> }, - ], - prev: { href: "/docs/components/cdr-skeleton", label: "CdrSkeleton" }, - next: { href: "/docs/components/condition-badge", label: "ConditionBadge" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/escrow-delivery-confirm/page.tsx b/apps/site/app/docs/components/escrow-delivery-confirm/page.tsx deleted file mode 100644 index 49bb9c8..0000000 --- a/apps/site/app/docs/components/escrow-delivery-confirm/page.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { EscrowDeliveryConfirmDemo } from "@/components/docs/demos/escrow-delivery-confirm-demo"; -import "../components.css"; - -const CODE = `import { EscrowDeliveryConfirm } from "@cdr-kit/react"; - - - -// Render-prop for the dashboard: - - {({ paid, delivered, timeoutInMs, confirmDelivery, pay }) => ( - paid === 0n - ? - : delivered - ? delivered ✓ - : - )} -`; - -export default function Page() { - return ( - ", - badges: <>new in 0.5headless, - lede: <>Buyer-side flow for ConditionalEscrowCondition: pay → confirm delivery → seller paid + buyer reads. Surfaces the timeout countdown after which the seller can claim unilaterally., - importLine: 'import { EscrowDeliveryConfirm } from "@cdr-kit/react"', - sections: [ - { - id: "preview", - title: "Live preview", - content: } code={CODE} badge={mock} />, - }, - { - id: "props", - title: "Props", - content: ( - ReactNode", description: "Render-prop. Receives the full EscrowState including seller, price, timeoutSecs, arbiter, paidAt, delivered, timeoutInMs, plus pay() and confirmDelivery() actions." }, - ]} /> - ), - }, - { - id: "intrinsic", - title: "Intrinsic CDR limitation", - content:

Once a buyer pays + confirms + reads, they hold plaintext forever. The dispute path (arbiter refund) can revoke future access but cannot "un-read." Document this in your buyer UX.

, - }, - ], - prev: { href: "/docs/components/multi-sig-signer", label: "MultiSigSigner" }, - next: { href: "/docs/components/condition-badge", label: "ConditionBadge" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/explorer-link/page.tsx b/apps/site/app/docs/components/explorer-link/page.tsx deleted file mode 100644 index 8ecf223..0000000 --- a/apps/site/app/docs/components/explorer-link/page.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { ExplorerLink } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const CODE = `import { ExplorerLink } from "@cdr-kit/react-ui"; - - - view on Aeneid -`; - -export default function Page() { - return ( - ", - badges: DX primitive, - lede: <>Mono primary-colored link with an external-link icon. Opens in a new tab with rel="noopener noreferrer"., - importLine: 'import { ExplorerLink } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - - view on Aeneid - - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/components/short-address", label: "ShortAddress" }, - next: { href: "/docs/components/ip-price", label: "IpPrice" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/heartbeat-timer/page.tsx b/apps/site/app/docs/components/heartbeat-timer/page.tsx deleted file mode 100644 index 95d42d8..0000000 --- a/apps/site/app/docs/components/heartbeat-timer/page.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { HeartbeatTimerDemo } from "@/components/docs/demos/heartbeat-timer-demo"; -import "../components.css"; - -const CODE = `import { HeartbeatTimer, useDeadManTimer } from "@cdr-kit/react"; - -// Default headless render — countdown + extend button: - - -// Custom render — full control via render-prop: - - {({ remainingMs, isCritical, isUnlocked, poke }) => ( -
- {isUnlocked ? "unlocked" : \`unlocks in \${remainingMs / 1000}s\`} - -
- )} -
`; - -export default function Page() { - return ( - ", - badges: <>new in 0.5headless, - lede: <>Countdown to DeadManSwitchCondition.unlockAt with a creator-side poke() button. Flips into critical mode once < 25% of the window remains, so the UI can prompt the creator before silence becomes irreversible., - importLine: 'import { HeartbeatTimer } from "@cdr-kit/react"', - sections: [ - { - id: "preview", - title: "Live preview", - content: } code={CODE} badge={mock} />, - }, - { - id: "props", - title: "Props", - content: ( - ReactNode", description: "Optional render-prop. Receives { unlocksAt, duration, remainingMs, isUnlocked, isCritical, poke, isLoading }." }, - ]} /> - ), - }, - { - id: "hook", - title: "Hook variant", - content:

Skip the component and consume useDeadManTimer(uuid) directly. Returns the same state object the render-prop receives.

, - }, - ], - prev: { href: "/docs/components/empty-vaults", label: "EmptyVaults" }, - next: { href: "/docs/components/time-window-badge", label: "TimeWindowBadge" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/ip-price/page.tsx b/apps/site/app/docs/components/ip-price/page.tsx deleted file mode 100644 index c103b71..0000000 --- a/apps/site/app/docs/components/ip-price/page.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { IpPrice } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const FIVE_IP = BigInt(5) * BigInt(10) ** BigInt(18); - -const CODE = `import { IpPrice } from "@cdr-kit/react-ui"; - - - {/* "License-gated" */}`; - -export default function Page() { - return ( - ", - badges: DX primitive, - lede: <>Formats wei as n IP with an optional period suffix. Pass null for license-gated vaults — renders the standard alt label., - importLine: 'import { IpPrice } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - - - - - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/components/explorer-link", label: "ExplorerLink" }, - next: { href: "/docs/components/cdr-network-chip", label: "CdrNetworkChip" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/multi-sig-approval-tracker/page.tsx b/apps/site/app/docs/components/multi-sig-approval-tracker/page.tsx deleted file mode 100644 index 351ae75..0000000 --- a/apps/site/app/docs/components/multi-sig-approval-tracker/page.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { MultiSigApprovalTrackerDemo } from "@/components/docs/demos/multi-sig-approval-tracker-demo"; -import "../components.css"; - -const CODE = `import { MultiSigApprovalTracker } from "@cdr-kit/react"; - -// signedBy is the list of signers who have already produced a sig OFF-CHAIN -// (the contract is stateless on approvals — no per-signer tx). -`; - -export default function Page() { - return ( - ", - badges: <>new in 0.5headless, - lede: <>X of Y approved + epoch — the read-side dashboard for MultiSigCondition. Combines the on-chain signer set with the off-chain set of collected sigs to render approval progress., - importLine: 'import { MultiSigApprovalTracker } from "@cdr-kit/react"', - sections: [ - { - id: "preview", - title: "Live preview", - content: } code={CODE} badge={mock} />, - }, - { - id: "props", - title: "Props", - content: ( - ReactNode", description: "Render-prop. Receives { signers, threshold, epoch, signedCount, isReady, isLoading }." }, - ]} /> - ), - }, - { - id: "rotation", - title: "Epoch rotation", - content:

Each call to rotateSigners() bumps epoch. The tracker re-reads on rotation; UI should prompt for a fresh sig collection because in-flight sigs against the previous epoch are invalidated.

, - }, - ], - prev: { href: "/docs/components/time-window-badge", label: "TimeWindowBadge" }, - next: { href: "/docs/components/multi-sig-signer", label: "MultiSigSigner" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/multi-sig-signer/page.tsx b/apps/site/app/docs/components/multi-sig-signer/page.tsx deleted file mode 100644 index 5ff05cb..0000000 --- a/apps/site/app/docs/components/multi-sig-signer/page.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; -import { Demo } from "@/components/docs/demo"; -import { MultiSigSignerDemo } from "@/components/docs/demos/multi-sig-signer-demo"; -import "../components.css"; - -const SIGN_CODE = `import { MultiSigSigner } from "@cdr-kit/react"; - -// Default render — button → on click signs EIP-712 → shows the sig + copy button. - - -// With a custom caller (default = connected wallet) and 30-min deadline: - - -// Render-prop for full custom UI: - - {({ sign, signature, isLoading, error, onSign }) => ( - signature - ? Sig: {signature} - : - )} -`; - -const SUBMIT_CODE = `// Buyer side — once threshold-many sigs collected from different signers: -import { CdrAgent } from "@cdr-kit/agent"; - -const bytes = await agent.accessMultiSig({ - uuid: 7331, - deadline, // MUST match every sig's deadline - sigs: [sigFromAlice, sigFromBob], // sorted by signer address ASC -});`; - -export default function Page() { - return ( - ", - badges: ( - <> - new in 0.5 - headless - signer-side - - ), - lede: ( - <> - Producer half of the off-chain dual-path MultiSigCondition flow: a button that - signs an EIP-712 Approval(uuid, caller, epoch, deadline) and surfaces the 65-byte sig - for the signer to share with the buyer. Pair with agent.accessMultiSig({"{ uuid, deadline, sigs[] }"}){" "} - on the buyer side to submit threshold-many sigs as accessAuxData. The complementary{" "} - <MultiSigApprovalTracker> is the buyer-side aggregator. - - ), - importLine: 'import { MultiSigSigner } from "@cdr-kit/react"', - sections: [ - { - id: "preview", - title: "Live preview", - content: } code={SIGN_CODE} badge={mock} />, - }, - { - id: "props", - title: "Props", - content: ( - ReactNode", - description: - "Render-prop. Receives { sign, signature, isLoading, error, onSign }. `onSign` is a bound zero-arg helper that calls `sign(...)` with the component's caller+deadline.", - }, - ]} - /> - ), - }, - { - id: "submit", - title: "Submit threshold-many sigs", - content: ( - <> -

- Once threshold-many signers have produced sigs, the buyer (or any caller) builds the - combined accessAuxData and reads the vault. agent.accessMultiSig handles the - abi-encoding; sigs must be ordered by recovered signer address ascending (the contract enforces a - strict-ascending dedupe). -

- - - ), - }, - { - id: "rotation", - title: "Epoch rotation invalidates in-flight sigs", - content: ( -

- The hook fetches the current epoch from getConfig(uuid) immediately before - signing. If rotateSigners lands between sign and submit, the contract recomputes the - digest with the new epoch — ecrecover returns a different address and the sig is - rejected. The signer can re-sign against the new epoch if they still want to authorize the new set - (use the "re-sign" button in the default render, or call sign() again). -

- ), - }, - { - id: "hook", - title: "Hook variant", - content: ( -

- Skip the component and use useSignMultiSigApproval(uuid) directly — returns{" "} - {`{ sign, signature, isLoading, error }`}. Useful when the sign trigger lives in a - non-button surface (drag-and-drop, gesture, programmatic flow). -

- ), - }, - ], - prev: { href: "/docs/components/multi-sig-approval-tracker", label: "MultiSigApprovalTracker" }, - next: { href: "/docs/components/escrow-delivery-confirm", label: "EscrowDeliveryConfirm" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/page.tsx b/apps/site/app/docs/components/page.tsx deleted file mode 100644 index 3387c8a..0000000 --- a/apps/site/app/docs/components/page.tsx +++ /dev/null @@ -1,172 +0,0 @@ -"use client"; - -import "./components.css"; - -import Link from "next/link"; -import { - ConditionBadge, - VaultCard, - ShortAddress, - ExplorerLink, - IpPrice, - CdrNetworkChip, - CdrSpinner, - CdrProgress, - CdrError, -} from "@cdr-kit/react-ui"; - -import { AccessStepperDemo } from "@/components/gallery/access-stepper-demo"; -import { SubscribeButtonDemo } from "@/components/gallery/subscribe-button-demo"; -import { Badge } from "@/components/primitives/badge"; - -const FIVE_IP = BigInt(5) * BigInt(10) ** BigInt(18); -const TWO_MIL_IP = BigInt(18) * BigInt(10) ** BigInt(15); - -const HEADLESS: { name: string; href: string; tag?: string; description: string }[] = [ - { name: "CdrProvider", href: "/docs/components/cdr-provider", description: "Root provider — wires WagmiProvider + react-query + initializes the CDR crypto WASM." }, - { name: "VaultGate", href: "/docs/components/vault-gate", description: "Declarative gate. Wrap encrypted data; renders the decrypted bytes via a render-prop." }, - { name: "Vault", href: "/docs/components/vault", tag: "compound", description: "Compound component — Vault.Locked / Vault.Loading / Vault.Unlocked slots." }, - { name: "CdrInspector", href: "/docs/components/cdr-inspector", description: "Dev panel showing mock / live mode + WASM ready state + API URL." }, - { name: "CdrSkeleton", href: "/docs/components/cdr-skeleton", description: "Default placeholder when no custom loading slot is supplied." }, - { name: "EmptyVaults", href: "/docs/components/empty-vaults", description: "Semantic empty-state slot." }, -]; - -const STYLED_CORE: { name: string; href: string; tag?: string; description: string }[] = [ - { name: "ConditionBadge", href: "/docs/components/condition-badge", description: "Color-mapped pill for the read condition kind." }, - { name: "AccessStepper", href: "/docs/components/access-stepper", description: "Designed wait-state stepper for the 2-step pay→access flow." }, - { name: "SubscribeButton", href: "/docs/components/subscribe-button", description: "Batteries-included CTA wrapping useSubscribeAndAccess + inline stepper + decoded JSON." }, - { name: "VaultCard", href: "/docs/components/vault-card", description: "Marketplace card with CSS pointer-tracking spotlight on hover." }, -]; - -const STYLED_PRIMITIVES: { name: string; href: string; description: string }[] = [ - { name: "CopyButton", href: "/docs/components/copy-button", description: "Minimal copy-to-clipboard control with check-mark feedback." }, - { name: "ShortAddress", href: "/docs/components/short-address", description: "Truncated mono address chip with inline copy." }, - { name: "ExplorerLink", href: "/docs/components/explorer-link", description: "Mono link with external-link icon — opens in new tab." }, - { name: "IpPrice", href: "/docs/components/ip-price", description: "Formats wei as IP with an optional period suffix." }, - { name: "CdrNetworkChip", href: "/docs/components/cdr-network-chip", description: "Pill with a glowing dot showing live vs mock mode." }, - { name: "CdrSpinner", href: "/docs/components/cdr-spinner", description: "Indeterminate CSS spinner." }, - { name: "CdrProgress", href: "/docs/components/cdr-progress", description: "Determinate progress bar with gradient fill." }, - { name: "CdrError", href: "/docs/components/cdr-error", description: "Soft-bordered danger state with optional retry CTA." }, -]; - -export default function ComponentsIndex() { - return ( -
-
- Components -
-
-

Components

- 18 components -
-

- Every component the kit ships, in one place. Headless render-prop slots from{" "} - @cdr-kit/react on top — drop in your own visuals, theme freely. Styled, batteries-included - variants from @cdr-kit/react-ui below — designed UI you can theme via{" "} - --cdr-ui-* CSS variables. Click any component for its live preview, code, props, and states. -

- -
-
-

Headless · @cdr-kit/react

-

Render-prop slots + hooks. Bring your own visuals.

-
-
- {HEADLESS.map((c) => ( - -
- {`<${c.name}>`} - {c.tag && {c.tag}} -
-

{c.description}

- - ))} -
-
- -
-
-

Styled · @cdr-kit/react-ui

-

Designed, batteries-included variants. Drop in and theme via CSS variables.

-
-

Vault-centric

-
- {STYLED_CORE.map((c) => ( - -
- {`<${c.name}>`} - {c.tag && {c.tag}} -
-

{c.description}

- - ))} -
- -

DX primitives

-
- {STYLED_PRIMITIVES.map((c) => ( - -
- {`<${c.name}>`} -
-

{c.description}

- - ))} -
-
- -
-
-

At a glance — live

-

A quick sampler of the styled set. Each component has a full page with Preview + Code + props.

-
- -
- - - - -
- -
- -
- -
- -
- -
- } - /> - } - /> -
- -
-
{``}
-
{``}
view on Aeneid
-
{``}
-
{``}
-
{``}
-
{``}
-
{``}
-
-
-
- ); -} diff --git a/apps/site/app/docs/components/short-address/page.tsx b/apps/site/app/docs/components/short-address/page.tsx deleted file mode 100644 index d976203..0000000 --- a/apps/site/app/docs/components/short-address/page.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { ShortAddress } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const CODE = `import { ShortAddress } from "@cdr-kit/react-ui"; - -`; - -export default function Page() { - return ( - ", - badges: DX primitive, - lede: <>Truncated mono address chip with an inline <CopyButton>. The chip's default truncation is 6 / 4 (head / tail)., - importLine: 'import { ShortAddress } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - - ), - }, - ], - prev: { href: "/docs/components/copy-button", label: "CopyButton" }, - next: { href: "/docs/components/explorer-link", label: "ExplorerLink" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/subscribe-button/page.tsx b/apps/site/app/docs/components/subscribe-button/page.tsx deleted file mode 100644 index 40357cc..0000000 --- a/apps/site/app/docs/components/subscribe-button/page.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { SubscribeButtonDemo } from "@/components/gallery/subscribe-button-demo"; - -const CODE = `import { CdrProvider } from "@cdr-kit/react"; -import { createMockCdrKit } from "@cdr-kit/core"; -import { SubscribeButton } from "@cdr-kit/react-ui"; - - - -`; - -export default function Page() { - return ( - ", - badges: <>styledmock-ready, - lede: <>Batteries-included CTA. Wraps useSubscribeAndAccess, renders an inline AccessStepper through the wait phases, then shows the decrypted JSON when access is granted., - importLine: 'import { SubscribeButton } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: } code={CODE} badge={mock kit} />, - }, - { - id: "props", - title: "Props", - content: ( - void", description: "Called with the decrypted bytes once the flow completes." }, - ]} /> - ), - }, - ], - prev: { href: "/docs/components/access-stepper", label: "AccessStepper" }, - next: { href: "/docs/components/vault-card", label: "VaultCard" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/time-window-badge/page.tsx b/apps/site/app/docs/components/time-window-badge/page.tsx deleted file mode 100644 index f7a8eb0..0000000 --- a/apps/site/app/docs/components/time-window-badge/page.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { TimeWindowBadgeDemo } from "@/components/docs/demos/time-window-badge-demo"; -import "../components.css"; - -const CODE = `import { TimeWindowBadge } from "@cdr-kit/react"; - - - -// Render-prop for custom presentation: - - {({ isOpen, opensInMs, closesInMs }) => - isOpen - ? open · closes in {Math.floor(closesInMs / 60_000)}m - : opens in {Math.floor(opensInMs / 3_600_000)}h - } -`; - -export default function Page() { - return ( - ", - badges: <>new in 0.5headless, - lede: <>Status badge for TimeWindowCondition-gated vaults: opens in 3d 4h, closes in 2h 15m, or closed. Ticks every second client-side, no extra RPC traffic after the first read., - importLine: 'import { TimeWindowBadge } from "@cdr-kit/react"', - sections: [ - { - id: "preview", - title: "Live preview", - content: } code={CODE} badge={cycles} />, - }, - { - id: "props", - title: "Props", - content: ( - ReactNode", description: "Optional render-prop. Receives { startTs, endTs, blockBased, isOpen, opensInMs, closesInMs, isLoading }." }, - ]} /> - ), - }, - { - id: "block-based", - title: "Block-based windows", - content:

For windows configured with blockBased: true, the client-side opensInMs/closesInMs return 0 — block.number can't be ticked client-side cheaply. Render the raw block bounds from the state object instead.

, - }, - ], - prev: { href: "/docs/components/heartbeat-timer", label: "HeartbeatTimer" }, - next: { href: "/docs/components/multi-sig-approval-tracker", label: "MultiSigApprovalTracker" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/unlockable/page.tsx b/apps/site/app/docs/components/unlockable/page.tsx deleted file mode 100644 index d3a2968..0000000 --- a/apps/site/app/docs/components/unlockable/page.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import Link from "next/link"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; -import { UnlockableDemo } from "@/components/docs/demos/unlockable-demo"; -import "../components.css"; - -const CODE = `import { CdrProvider } from "@cdr-kit/react"; -import { createMockCdrKit } from "@cdr-kit/core"; -import { UnlockablePill } from "@cdr-kit/react-ui"; - - -

- Arlo Vance told the press he was alone, but{" "} - - the woman beside him on the dock - {" "} - disagrees. -

-
`; - -const HOOK_CODE = `import { useUnlockable } from "@cdr-kit/react"; - -function CustomPill({ uuid }) { - const { status, data, isOpen, open, close, request } = - useUnlockable({ uuid, mode: "subscribe" }); - - return ( - - [click to unlock] - {isOpen && ( -
- {status === "ready" ? render(data) : ( - - )} -
- )} -
- ); -}`; - -export default function Page() { - return ( - ", - badges: <>stylednew in 0.2mock-ready, - lede: <>Inline "free to read, pay to unlock" paywall. Wrap any anchor text in a pill; the click opens a floating card that runs the full CDR subscribe → threshold-read → decrypt flow and reveals the attached payload (text, image, file) right where the pill stands., - importLine: 'import { UnlockablePill } from "@cdr-kit/react-ui"', - callout: ( - - live showcase - See <UnlockablePill> in a real blog post → - Five live unlocks across text, image, and prose attachments. Mock CDR — no wallet, no chain. - - ), - sections: [ - { - id: "preview", - title: "Live preview", - content: } code={CODE} badge={mock kit} />, - }, - { - id: "hook", - title: "Headless variant", - content: ( - <> -

- Prefer to render your own UI? useUnlockable exposes the entire state machine — status, data, error, isOpen, open/close, request, reset. The styled UnlockablePill is a 60-line wrapper on top of it. -

- Use the hook for full control. Snippet on the Code tab.} code={HOOK_CODE} language="tsx" /> - - ), - }, - { - id: "props", - title: "Props", - content: ( - ReactNode", defaultValue: "unlockedAuto", description: "Render the decrypted bytes. Default auto-detects PNG/JPEG/WebP/GIF, falls back to UTF-8 text, then to a download link." }, - { name: "subscriptionCondition", type: "Hex", description: "Override the default deployed SubscriptionCondition address." }, - ]} /> - ), - }, - { - id: "mobile", - title: "Mobile fallback", - content: ( -

- Below 560px the floating popover collapses to a bottom-sheet — the card pins to the bottom of the viewport with a safe-area-aware inset. No additional code; the same UnlockablePill handles both. -

- ), - }, - { - id: "anchor", - title: "The anchor is plaintext — that's intentional", - content: ( - <> -

- The text inside <UnlockablePill> is a public teaser. Search engines and inspect-element will see it. The encrypted payload is what the vault holds — an image, a file, a hidden paragraph — and that only exists in the DOM after a successful read. -

-

- This matches the onscroll.app pattern: highlighted phrases anchor the unlock UX, attached content is the secret. If you want the anchor itself to be the secret, use <VaultGate> instead. -

- - ), - }, - ], - prev: { href: "/docs/components/subscribe-button", label: "SubscribeButton" }, - next: { href: "/docs/components/vault-card", label: "VaultCard" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/vault-card/page.tsx b/apps/site/app/docs/components/vault-card/page.tsx deleted file mode 100644 index 0c2a849..0000000 --- a/apps/site/app/docs/components/vault-card/page.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { VaultCard, IpPrice } from "@cdr-kit/react-ui"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; -import { Demo } from "@/components/docs/demo"; - -const FIVE_IP = BigInt(5) * BigInt(10) ** BigInt(18); - -const CODE = `import { VaultCard, IpPrice } from "@cdr-kit/react-ui"; - -} - href="/vault/4200" -/>`; - -export default function Page() { - return ( - ", - badges: styled, - lede: <>Marketplace card with a CSS pointer-tracking spotlight on hover. Renders the condition badge, title, description, optional data type, creator, and price., - importLine: 'import { VaultCard } from "@cdr-kit/react-ui"', - sections: [ - { - id: "preview", - title: "Live preview", - content: ( - - } - /> - - } - code={CODE} - /> - ), - }, - { - id: "props", - title: "Props", - content: ( - ." }, - { name: "href", type: "string", description: "Render the card as an linking to the vault detail page." }, - ]} /> - ), - }, - ], - prev: { href: "/docs/components/subscribe-button", label: "SubscribeButton" }, - next: { href: "/docs/components/copy-button", label: "CopyButton" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/components/vault-gate/page.tsx b/apps/site/app/docs/components/vault-gate/page.tsx deleted file mode 100644 index f80ee2d..0000000 --- a/apps/site/app/docs/components/vault-gate/page.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { Breadcrumb, Callout, DocTitle, H2, PrevNext, PropsTable } from "@/components/docs/parts"; -import { Demo } from "@/components/docs/demo"; -import { CodePanel } from "@/components/docs/code-panel"; -import { Toc } from "@/components/docs/toc"; -import { VaultGateDemo } from "@/components/docs/demos/vault-gate-demo"; - -const CODE = `import { CdrProvider, VaultGate } from "@cdr-kit/react"; -import { createMockCdrKit } from "@cdr-kit/core"; - -export function SignalCard() { - return ( - - } - loading={}> - {(data) =>
{new TextDecoder().decode(data)}
} -
-
- ); -}`; - -const TOC = [ - { id: "preview", label: "Live preview" }, - { id: "usage", label: "Usage" }, - { id: "props", label: "Props" }, - { id: "states", label: "States" }, - { id: "mock", label: "Mock mode" }, -]; - -export default function VaultGatePage() { - return ( - <> -
- - - component - mock-ready - - } - /> -

- A declarative gate. Wrap it around the data you want to protect; it checks the vault's on-chain read condition, - collects key shares, and renders the decrypted bytes via a render-prop once access is granted. -

-
- import {`{ VaultGate }`} from "@cdr-kit/react" -
- - - Mock by default. Every example on this page runs against an in-memory CDR — no wallet, no chain, no testnet - funds. Swap mockKit for config + apiUrl to go live on Aeneid. - - -

Live preview

-

- Press subscribe to run the full mock flow — condition check, payment, threshold key-share collection, and local - decryption. It mirrors the real 2-step subscribeAndAccess path against the actual{" "} - createMockCdrKit() from @cdr-kit/core. -

- } code={CODE} badge={mock kit} /> - -

Usage

-

- The simplest gate: pass a uuid and a render-prop. With auto, VaultGate{" "} - requests access on mount; without it, it waits for an imperative trigger from the access hook. -

- }> - {(data) => } -`} /> - -

Props

- - The CDR vault id. Read it from the VaultCreated event — never predict it (it's a global - counter). - - ), - }, - { - name: "children", - type: "(data: Uint8Array) => ReactNode", - required: true, - description: "Render-prop called with the decrypted bytes once the condition is satisfied.", - }, - { - name: "auto", - type: "boolean", - defaultValue: "false", - description: "Request access on mount instead of waiting for an imperative trigger.", - }, - { - name: "fallback", - type: "ReactNode", - defaultValue: "null", - description: "Rendered while the condition is unmet — typically your subscribe / pay button.", - }, - { - name: "loading", - type: "ReactNode", - defaultValue: "", - description: "Rendered during the ~15s threshold read while key shares are collected.", - }, - { - name: "accessAuxData", - type: "Hex", - defaultValue: '"0x"', - description: ( - <> - Optional ABI-encoded auxiliary data passed to the read condition (e.g. a tier-gate license tokenId). - - ), - }, - ]} - /> - -

States

-

- VaultGate is a thin wrapper over useAccessVault, whose discriminated{" "} - status drives what renders: -

-
    -
  • - idle / error — condition unmet → renders fallback. -
  • -
  • - collecting-partials — collecting key shares (the ~15s read) → renders loading. -
  • -
  • - ready — threshold met, decrypted → renders children(data). -
  • -
- -

Mock mode

-

- Wrap your tree in a CdrProvider with a createMockCdrKit() and the entire component - surface works with zero chain dependencies — ideal for Storybook, tests, and the previews on this page. Going - live is a one-line swap: -

- … - -// live on Aeneid — same children, real round-trip -`} /> - - -
- - - ); -} diff --git a/apps/site/app/docs/components/vault/page.tsx b/apps/site/app/docs/components/vault/page.tsx deleted file mode 100644 index 93fb32e..0000000 --- a/apps/site/app/docs/components/vault/page.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const CODE = ` - - - {(data) => } -`; - -export default function VaultCompoundPage() { - return ( - componentcompound, - lede: ( - <> - Compound component — Clerk's SignedIn / SignedOut pattern adapted to CDR. A - single access drives the shared state; Vault.Locked, Vault.Loading, and{" "} - Vault.Unlocked render against it. - - ), - importLine: 'import { Vault } from "@cdr-kit/react"', - sections: [ - { - id: "usage", - title: "Usage", - content: ( - - ), - }, - { - id: "slots", - title: "Slots", - content: ( -
    -
  • Vault.Locked — status is idle or error.
  • -
  • Vault.Loading — status is paying or collecting-partials. Optional render-prop receives {`{ collected, threshold }`}.
  • -
  • Vault.Unlocked — status is ready. Render-prop receives the decrypted bytes.
  • -
- ), - }, - ], - prev: { href: "/docs/components/vault-gate", label: "VaultGate" }, - next: { href: "/docs/components/cdr-inspector", label: "CdrInspector" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/cdr-kit-vault/page.tsx b/apps/site/app/docs/contracts/cdr-kit-vault/page.tsx deleted file mode 100644 index ec98ef3..0000000 --- a/apps/site/app/docs/contracts/cdr-kit-vault/page.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { aeneid } from "@cdr-kit/contracts"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - factorydeployed, - lede: <>The atomic factory: createVault mints the vault NFT, registers it as a Story IP asset, allocates the CDR slot, configures the read condition, and (optionally) attaches PIL license terms — all in one transaction. The configure step is permissioned to the factory only, closing the race a permissionless setConfig would open., - importLine: `address = ${aeneid.cdrKitVault}`, - sections: [ - { - id: "create", - title: "createVault signature", - content: ( - - ), - }, - { - id: "events", - title: "Events", - content:

Emits VaultCreated(tokenId, uuid, ipId, creator, licenseTermsId) — read the uuid from the tx receipt; never predict it (global counter).

, - }, - { - id: "gas", - title: "Gas note", - content:

The factory nests a CDR precompile call (allocate) whose gas eth_estimateGas underestimates. Always set an explicit gas limit (3_000_000 is the SDK default).

, - }, - ], - prev: { href: "/docs/contracts/creator-write-condition", label: "CreatorWriteCondition" }, - next: { href: "/docs/scaffolder", label: "npm create cdr-kit" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/composable-condition/page.tsx b/apps/site/app/docs/contracts/composable-condition/page.tsx deleted file mode 100644 index 2e8968e..0000000 --- a/apps/site/app/docs/contracts/composable-condition/page.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { aeneid } from "@cdr-kit/contracts"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; - -export default function Page() { - return ( - deployedboolean, - lede: <>Boolean AND / OR over child conditions, up to 8 deep. Compose "Subscription OR Tier" or "Royalty AND License" — natively, on chain, in one read check., - importLine: `address = ${aeneid.composableCondition}`, - sections: [ - { - id: "config", - title: "Config shape", - content: ( -
    -
  • mode: uint8 — 0 = AND, 1 = OR.
  • -
  • children: address[] — child condition addresses (1–8).
  • -
- ), - }, - { - id: "aux", - title: "accessAuxData", - content:

ABI-encoded bytes[] of per-child aux, aligned to the configured children order.

, - }, - ], - prev: { href: "/docs/contracts/tier-gate-condition", label: "TierGateCondition" }, - next: { href: "/docs/contracts/open-condition", label: "OpenCondition" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/conditional-escrow-condition/page.tsx b/apps/site/app/docs/contracts/conditional-escrow-condition/page.tsx deleted file mode 100644 index c97af42..0000000 --- a/apps/site/app/docs/contracts/conditional-escrow-condition/page.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; - -// Hardcoded until @cdr-kit/contracts@0.5.0 publishes (apps/site consumes ^0.4.0 from npm). -const ESCROW_ADDRESS = "0x7fcDe02DB7c14fD3587aB2fED064a1D8355b7584"; - -export default function Page() { - return ( - deployednew in 0.5, - lede: <>Buyer pays → confirms delivery → seller paid + buyer reads. Optional arbiter can refund. Seller can claimAfterTimeout(buyer) if the buyer goes silent., - importLine: `address = ${ESCROW_ADDRESS}`, - sections: [ - { - id: "config", - title: "Config shape", - content: ( - - ), - }, - { - id: "flow", - title: "Flow", - content: ( -
    -
  1. pay(uuid) — buyer escrows the price (excess refunded same tx).
  2. -
  3. confirmDelivery(uuid) — buyer signs off → seller paid + buyer reads.
  4. -
  5. claimAfterTimeout(uuid, buyer) — seller only, after paidAt + timeoutSecs.
  6. -
  7. arbiterRefund(uuid, buyer) — arbiter only; resets paidAt and refunds the buyer.
  8. -
- ), - }, - { - id: "intrinsic", - title: "Intrinsic CDR limitation", - content:

CDR has no confidential compute — once a buyer reads, they hold plaintext forever. The dispute path can revoke future access but cannot "un-read." Document this in your buyer UX.

, - }, - ], - prev: { href: "/docs/contracts/dead-man-switch-condition", label: "DeadManSwitchCondition" }, - next: { href: "/docs/contracts/multi-sig-condition", label: "MultiSigCondition" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/creator-write-condition/page.tsx b/apps/site/app/docs/contracts/creator-write-condition/page.tsx deleted file mode 100644 index e9f7534..0000000 --- a/apps/site/app/docs/contracts/creator-write-condition/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { aeneid } from "@cdr-kit/contracts"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; - -export default function Page() { - return ( - deployed, - lede: <>The default write gate when you mint through CdrKitVault: only the original creator (vault NFT owner) can write encrypted payloads. Factory-aware variant of OwnerWriteCondition., - importLine: `address = ${aeneid.creatorWriteCondition}`, - sections: [ - { id: "config", title: "Config", content:

No config bytes required — the factory wires the creator at allocation time.

}, - ], - prev: { href: "/docs/contracts/open-condition", label: "OpenCondition" }, - next: { href: "/docs/contracts/cdr-kit-vault", label: "CdrKitVault" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/dead-man-switch-condition/page.tsx b/apps/site/app/docs/contracts/dead-man-switch-condition/page.tsx deleted file mode 100644 index 7cb1fe5..0000000 --- a/apps/site/app/docs/contracts/dead-man-switch-condition/page.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; - -// Hardcoded until @cdr-kit/contracts@0.5.0 publishes (apps/site consumes ^0.4.0 from npm). -const DEAD_MAN_ADDRESS = "0x37226f97e184843aB0b8d4f08A55969801B97766"; - -export default function Page() { - return ( - deployednew in 0.5, - lede: <>Auto-unlock to heir(s) (or public) if the creator stops calling poke() within duration. The wallet-recovery / estate-planning / leak-on-disappearance primitive Story docs reference., - importLine: `address = ${DEAD_MAN_ADDRESS}`, - sections: [ - { - id: "config", - title: "Config shape", - content: ( - 0." }, - { name: "heirs", type: "address[]", required: true, description: "Allowed readers post-unlock if publicAfterUnlock = false. Empty array forces publicAfterUnlock to true." }, - { name: "blockBased", type: "bool", required: true, description: "true = interpret duration as block count." }, - { name: "creatorCanReadWhileLocked", type: "bool", required: true, description: "Creator reads their own vault pre-unlock (default true via agent helper)." }, - { name: "publicAfterUnlock", type: "bool", required: true, description: "true = anyone reads post-unlock; false = restricted to heirs." }, - ]} /> - ), - }, - { - id: "trapdoor", - title: "The trapdoor", - content:

Post-unlock, the creator gets NO special treatment. If publicAfterUnlock = false AND the creator isn't in heirs, they lose read access permanently at unlock — by design. agent.createDeadManVault defaults creatorCanReadWhileLocked = true and recommends adding the creator to heirs for post-unlock access.

, - }, - { - id: "poke", - title: "poke()", - content:

Creator-only. Cannot be called after unlockAt (one-way trapdoor — reviving would let a late-poking creator block heirs forever). Most operational risk is forgetting to poke; consider a self-hosted cron or Gelato Automate for long durations.

, - }, - ], - prev: { href: "/docs/contracts/time-window-condition", label: "TimeWindowCondition" }, - next: { href: "/docs/contracts/conditional-escrow-condition", label: "ConditionalEscrowCondition" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/multi-sig-condition/page.tsx b/apps/site/app/docs/contracts/multi-sig-condition/page.tsx deleted file mode 100644 index a8545e1..0000000 --- a/apps/site/app/docs/contracts/multi-sig-condition/page.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; - -// Hardcoded until @cdr-kit/contracts@0.5.0 publishes (apps/site consumes ^0.4.0 from npm). -// 0x61061c… is the 0.5 redeploy with on-chain `approve()` path added; previous 0xb22EBF… -// retired (off-chain-only — same epoch + sig logic but no on-chain approve fn). -const MULTI_SIG_ADDRESS = "0x61061CCb8BD4C9E0AfF67ed4d2226f0Fc140FB87"; - -export default function Page() { - return ( - deployedfirst-of-kindnew in 0.5, - lede: <>N-of-M read gate with two parallel approval paths: off-chain EIP-712 sigs (gas-free; buyer collects + submits at read time) OR Safe-style on-chain approve() (signers pay gas; dashboards read chain truth). A read passes when EITHER path meets threshold. First-of-kind in the CDR ecosystem., - importLine: `address = ${MULTI_SIG_ADDRESS}`, - sections: [ - { - id: "config", - title: "Config shape", - content: ( - - ), - }, - { - id: "eip712", - title: "EIP-712 Approval", - content: ( -
    -
  • Domain: cdr-kit:MultiSigCondition, version 1, chainId 1315, verifyingContract = condition address.
  • -
  • Type: Approval(uint32 uuid, address caller, uint64 epoch, uint64 deadline).
  • -
  • caller binding prevents sig replay against a different reader; epoch rotation invalidates in-flight sigs.
  • -
- ), - }, - { - id: "onchain-approve", - title: "On-chain approve() — the Safe-style path", - content: ( - <> -

For dashboards that prefer chain-truth over off-chain sig collection, signers call approve(uuid) on-chain. Each approval costs ~50k gas. currentApprovalsCount(uuid) returns the count for the active epoch — read it directly in your UI via useMultiSigStatus.

-

Storage shape (epoch-scoped, so rotation auto-invalidates): hasApproved[uuid][epoch][signer] + approvalsCount[uuid][epoch]. Emits Approved(uuid, signer, epoch) for indexers.

- - ), - }, - { - id: "rotation", - title: "rotateSigners()", - content:

Creator-only. Validates the new signer set + threshold, bumps epoch — invalidates BOTH off-chain sigs (signed against the old epoch) AND on-chain approvals (the count under the old epoch key no longer matters since reads check the new epoch). Use this to remove a compromised signer immediately.

, - }, - { - id: "limitations", - title: "Limitations", - content:

EIP-1271 (Safe / contract-wallet signers) not supported in 0.5 — ecrecover handles EOAs only. Workaround: have a Safe-owned EOA sign on behalf and register that EOA.

, - }, - ], - prev: { href: "/docs/contracts/conditional-escrow-condition", label: "ConditionalEscrowCondition" }, - next: { href: "/docs/contracts/cdr-kit-vault", label: "CdrKitVault" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/open-condition/page.tsx b/apps/site/app/docs/contracts/open-condition/page.tsx deleted file mode 100644 index 4ff5c43..0000000 --- a/apps/site/app/docs/contracts/open-condition/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { aeneid } from "@cdr-kit/contracts"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; - -export default function Page() { - return ( - deployed, - lede: <>Always returns true. Use as a fallback / sanity gate, or as the read condition for genuinely public data., - importLine: `address = ${aeneid.openCondition}`, - sections: [{ id: "config", title: "Config", content:

No config bytes required — pass 0x.

}], - prev: { href: "/docs/contracts/composable-condition", label: "ComposableCondition" }, - next: { href: "/docs/contracts/creator-write-condition", label: "CreatorWriteCondition" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/page.tsx b/apps/site/app/docs/contracts/page.tsx deleted file mode 100644 index 46801c8..0000000 --- a/apps/site/app/docs/contracts/page.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import Link from "next/link"; -import { aeneid } from "@cdr-kit/contracts"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function ContractsPage() { - return ( - @cdr-kit/contracts, - lede: <>A tested Solidity standard library + a factory (CdrKitVault) that mints, registers IP, allocates the CDR slot, and configures the read condition in one transaction. All deployed to Aeneid testnet (chain id {aeneid.chainId})., - importLine: 'import { aeneid } from "@cdr-kit/contracts"', - sections: [ - { - id: "library", - title: "Library", - content: ( -
    -
  • SubscriptionCondition
  • -
  • TierGateCondition
  • -
  • ComposableCondition
  • -
  • OpenCondition
  • -
  • CreatorWriteCondition
  • -
  • CdrKitVault — the factory
  • -
- ), - }, - { - id: "interface", - title: "Condition interface", - content: ( - <> -

Conditions are pure view functions the validator network calls at read/write time. The 4-param signature:

- - - ), - }, - { - id: "addresses", - title: "Deployed (Aeneid)", - content: ( -
    -
  • CdrKitVault: {aeneid.cdrKitVault}
  • -
  • SubscriptionCondition: {aeneid.subscriptionCondition}
  • -
  • TierGateCondition: {aeneid.tierGateCondition}
  • -
  • ComposableCondition: {aeneid.composableCondition}
  • -
  • OpenCondition: {aeneid.openCondition}
  • -
  • CreatorWriteCondition: {aeneid.creatorWriteCondition}
  • -
- ), - }, - ], - prev: { href: "/docs/agent-kit/mcp", label: "MCP server" }, - next: { href: "/docs/contracts/subscription-condition", label: "SubscriptionCondition" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/subscription-condition/page.tsx b/apps/site/app/docs/contracts/subscription-condition/page.tsx deleted file mode 100644 index 634cd36..0000000 --- a/apps/site/app/docs/contracts/subscription-condition/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { aeneid } from "@cdr-kit/contracts"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; - -export default function Page() { - return ( - deployedrecurring, - lede: <>Recurring paid access. The buyer calls subscribe(uuid, periods, maxPricePerPeriod) with the right value; subsequent reads pass until the subscription expires., - importLine: `address = ${aeneid.subscriptionCondition}`, - sections: [ - { - id: "config", - title: "Config shape", - content: ( - - ), - }, - ], - prev: { href: "/docs/contracts", label: "Condition library" }, - next: { href: "/docs/contracts/tier-gate-condition", label: "TierGateCondition" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/tier-gate-condition/page.tsx b/apps/site/app/docs/contracts/tier-gate-condition/page.tsx deleted file mode 100644 index 1cddd80..0000000 --- a/apps/site/app/docs/contracts/tier-gate-condition/page.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { aeneid } from "@cdr-kit/contracts"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; - -export default function Page() { - return ( - deployedlicensed, - lede: <>Gate by a held Story IP license-token tier. The buyer passes the tokenId of their license as accessAuxData; the condition verifies ownership + that the tier is in the allowed set., - importLine: `address = ${aeneid.tierGateCondition}`, - sections: [ - { - id: "config", - title: "Config shape", - content: ( -
    -
  • ipId: address — the IP asset the license must reference.
  • -
  • allowedTermsIds: uint256[] — accepted PIL terms ids (≥1).
  • -
- ), - }, - { - id: "aux", - title: "accessAuxData", - content:

ABI-encoded uint256 tokenId of the license the caller holds.

, - }, - ], - prev: { href: "/docs/contracts/subscription-condition", label: "SubscriptionCondition" }, - next: { href: "/docs/contracts/composable-condition", label: "ComposableCondition" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/contracts/time-window-condition/page.tsx b/apps/site/app/docs/contracts/time-window-condition/page.tsx deleted file mode 100644 index 36fac04..0000000 --- a/apps/site/app/docs/contracts/time-window-condition/page.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage, PropsTable } from "@/components/docs/doc-page"; - -// Hardcoded until @cdr-kit/contracts@0.5.0 publishes (apps/site consumes ^0.4.0 from npm). -const TIME_WINDOW_ADDRESS = "0x67911435F262e7e4EC4F7FEB4e868a67b9dd90b1"; - -export default function Page() { - return ( - deployednew in 0.5, - lede: <>Read access is allowed only during [startTs, endTs]. endTs == 0 means open-ended (release-on-date pattern). Block-based mode (blockBased: true) is preferred for short horizons., - importLine: `address = ${TIME_WINDOW_ADDRESS}`, - sections: [ - { - id: "config", - title: "Config shape", - content: ( - - ), - }, - { - id: "presets", - title: "Agent presets", - content: ( -
    -
  • releaseOnDate(startTs)(startTs, 0, false) — open-ended after a date.
  • -
  • availableDuring(startTs, endTs)(startTs, endTs, false) — bounded window.
  • -
  • releaseAfterBlocks(blockNum)(0, blockNum, true) — block-based release.
  • -
- ), - }, - ], - prev: { href: "/docs/contracts/cdr-kit-vault", label: "CdrKitVault" }, - next: { href: "/docs/contracts/dead-man-switch-condition", label: "DeadManSwitchCondition" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/docs.css b/apps/site/app/docs/docs.css index 157cdaf..d6f62fc 100644 --- a/apps/site/app/docs/docs.css +++ b/apps/site/app/docs/docs.css @@ -234,3 +234,107 @@ .doc-nav-foot { flex-direction: column; gap: 10px; } .doc-nav-foot .next { text-align: left; } } + +/* T1-F: per-page Copy Page button — appears in the title row as a "badge". + * Style mirrors the existing .badge with a hover affordance + flash on copy. */ +.copy-page-btn { + display: inline-flex; align-items: center; gap: 6px; + padding: 6px 10px; + border-radius: 8px; + border: 1px solid var(--line, oklch(22% 0.012 90)); + background: color-mix(in oklab, var(--paper, oklch(17% 0.012 90)) 80%, transparent); + color: var(--ink-2, oklch(70% 0.012 90)); + font-family: ui-monospace, monospace; + font-size: 0.74rem; + line-height: 1; + cursor: pointer; + transition: background 120ms ease, color 120ms ease, border-color 120ms ease; +} +.copy-page-btn:hover { + border-color: color-mix(in oklab, var(--accent, oklch(78% 0.16 70)) 50%, var(--line)); + color: var(--ink, oklch(94% 0.01 90)); + background: color-mix(in oklab, var(--paper, oklch(17% 0.012 90)) 92%, transparent); +} +.copy-page-btn[data-copied] { + color: oklch(72% 0.18 145); + border-color: color-mix(in oklab, oklch(72% 0.18 145) 60%, var(--line)); +} + +/* T2-C: docs Demo live overlay — frosted backdrop with a connect-wallet CTA + * shown over the preview when the user has no wallet or is on the wrong chain. */ +.docs-live-wrap { position: relative; } +.docs-live-overlay { + position: absolute; inset: 0; z-index: 5; + display: grid; place-items: center; + border-radius: inherit; + background: color-mix(in oklab, var(--paper, oklch(17% 0.012 90)) 70%, transparent); + backdrop-filter: blur(10px) saturate(140%); +} +.docs-live-card { + text-align: center; + padding: 18px 22px; + max-width: 320px; + background: color-mix(in oklab, var(--paper, oklch(17% 0.012 90)) 92%, transparent); + border: 1px solid var(--line, oklch(22% 0.012 90)); + border-radius: 12px; + box-shadow: 0 20px 40px -16px color-mix(in oklab, oklch(0% 0 0) 60%, transparent); +} +.docs-live-eyebrow { + font-family: ui-monospace, monospace; font-size: 0.66rem; + color: var(--accent, oklch(78% 0.16 70)); + letter-spacing: 0.10em; text-transform: uppercase; margin: 0 0 8px; +} +.docs-live-title { font-size: 0.96rem; font-weight: 700; margin: 0 0 6px; color: var(--ink, oklch(94% 0.01 90)); } +.docs-live-sub { font-size: 0.84rem; line-height: 1.5; color: var(--ink-2, oklch(70% 0.01 90)); margin: 0 0 14px; } +.docs-live-card [data-rk] { display: inline-block; } + +/* M2: components gallery grid — "at a glance" tiles for /docs/components */ +[data-components-gallery] { display: flex; flex-direction: column; gap: 48px; margin-top: 8px; } +[data-gallery-section-head] { margin: 0 0 18px; } +[data-gallery-section-head] h3 { margin: 0 0 4px; font-size: 1.05rem; font-weight: 700; letter-spacing: -0.01em; } +[data-gallery-hint] { margin: 0; font-size: 0.86rem; color: var(--ink-2, oklch(70% 0.012 90)); } +[data-gallery-grid] { + display: grid; gap: 14px; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); +} +[data-gallery-tile] { + display: flex; flex-direction: column; + min-height: 130px; + padding: 14px 16px 12px; + background: var(--paper, oklch(17% 0.012 90)); + border: 1px solid var(--line, oklch(22% 0.012 90)); + border-radius: 12px; + text-decoration: none; color: inherit; + transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease; +} +[data-gallery-tile]:hover { + border-color: color-mix(in oklab, var(--accent, oklch(78% 0.16 70)) 50%, var(--line)); + transform: translateY(-1px); + box-shadow: 0 6px 16px -8px color-mix(in oklab, oklch(0% 0 0) 50%, transparent); +} +[data-tile-preview] { + flex: 1; + display: grid; place-items: center; + padding: 10px 6px; + margin-bottom: 10px; + border-radius: 8px; + background: color-mix(in oklab, var(--paper-2, oklch(20% 0.012 90)) 60%, transparent); + min-height: 48px; + text-align: center; +} +[data-tile-headless] { + font-family: ui-monospace, monospace; + font-size: 0.74rem; + line-height: 1.4; + color: var(--ink-3, oklch(56% 0.01 90)); +} +[data-tile-meta] { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; min-width: 0; } +[data-tile-label] { + font-family: ui-monospace, monospace; font-size: 0.82rem; font-weight: 600; + color: var(--ink, oklch(94% 0.01 90)); + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; +} +[data-tile-import] { + font-family: ui-monospace, monospace; font-size: 0.66rem; + color: var(--ink-3, oklch(56% 0.01 90)); white-space: nowrap; +} diff --git a/apps/site/app/docs/hooks/use-access-vault/page.tsx b/apps/site/app/docs/hooks/use-access-vault/page.tsx deleted file mode 100644 index a9c1a14..0000000 --- a/apps/site/app/docs/hooks/use-access-vault/page.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const SIG = `function useAccessVault(uuid: number): { - access: (accessAuxData?: Hex) => Promise; - status: "idle" | "collecting-partials" | "ready" | "error"; - data?: Uint8Array; - error?: CdrError; - progress?: { collected: number; threshold: number }; // mock-mode only -};`; - -export default function UseAccessVaultPage() { - return ( - hook, - lede: <>Imperative access to one vault. Returns a discriminated status + the decrypted bytes when ready. The state machine behind <VaultGate> and <Vault>., - importLine: 'import { useAccessVault } from "@cdr-kit/react"', - sections: [ - { - id: "signature", - title: "Signature", - content: , - }, - { - id: "states", - title: "States", - content: ( -
    -
  • idle — initial; call access() to begin.
  • -
  • collecting-partials — the ~15s threshold read.
  • -
  • readydata populated.
  • -
  • error — see error for the typed reason.
  • -
- ), - }, - ], - prev: { href: "/docs/components/empty-vaults", label: "EmptyVaults" }, - next: { href: "/docs/hooks/use-subscribe-and-access", label: "useSubscribeAndAccess" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-attach-license-terms/page.tsx b/apps/site/app/docs/hooks/use-attach-license-terms/page.tsx deleted file mode 100644 index fa0becb..0000000 --- a/apps/site/app/docs/hooks/use-attach-license-terms/page.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const SIG = `function useAttachLicenseTerms(client: StoryClient | undefined): { - attach: (params: { - ipId: Hex; - licenseTermsId: bigint; - licenseTemplate?: Hex; // defaults to the canonical PIL template - }) => Promise<{ txHash: Hex }>; - isLoading: boolean; - error?: Error; -};`; - -const EXAMPLE = `import { useStoryClient, useAttachLicenseTerms } from "@cdr-kit/react"; - -function AttachTerms({ ipId, licenseTermsId }) { - const client = useStoryClient(); - const { attach, isLoading, error } = useAttachLicenseTerms(client); - return ( - <> - - {error && {error.message}} - - ); -}`; - -export default function Page() { - return ( - - hook - new in 0.5 - Story IP - - ), - lede: ( - <> - Attach an existing PIL licenseTermsId to an IP asset — required before any - buyer can mintLicenseTokens against it. Idempotent: calling twice with the - same args is a no-op tx (still costs gas, so check first if you can). - - ), - importLine: 'import { useAttachLicenseTerms } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: }, - { id: "example", title: "Example", content: }, - { - id: "ordering", - title: "Call ordering", - content: ( -

- The flow is: (1) registerIpAsset → ipId, (2) registerPilTerms{" "} - → licenseTermsId (or use a previously registered set), (3) attachLicenseTerms{" "} - links the two. Only then can buyers mint license tokens against your IP. -

- ), - }, - { - id: "template", - title: "License template", - content: ( -

- licenseTemplate defaults to the canonical Story PIL template. Override - only if you've registered a custom template at the protocol level — rare. -

- ), - }, - ], - prev: { href: "/docs/hooks/use-mint-license-token", label: "useMintLicenseToken" }, - next: { href: "/docs/hooks/use-publish", label: "usePublish" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-cdr-wallet/page.tsx b/apps/site/app/docs/hooks/use-cdr-wallet/page.tsx deleted file mode 100644 index 65bde61..0000000 --- a/apps/site/app/docs/hooks/use-cdr-wallet/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hook, - lede: <>Lightweight wallet connect for the simple path: pairs with <CdrProvider>'s built-in injected connector. Bring your own wallet stack (Privy / RainbowKit) for the rich path., - importLine: 'import { useCdrWallet } from "@cdr-kit/react"', - sections: [{ id: "signature", title: "Signature", content: void; - disconnect: () => void; -};`} /> }], - prev: { href: "/docs/hooks/use-creator-vaults", label: "useCreatorVaults" }, - next: { href: "/docs/agent-kit", label: "Agent kit" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-create-vault/page.tsx b/apps/site/app/docs/hooks/use-create-vault/page.tsx deleted file mode 100644 index 1b6d21d..0000000 --- a/apps/site/app/docs/hooks/use-create-vault/page.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hook, - lede: <>Seller-side: call the CdrKitVault factory to mint the NFT, register the IP asset, allocate the CDR slot, and configure the read condition — in one transaction., - importLine: 'import { useCreateVault } from "@cdr-kit/react"', - sections: [{ id: "signature", title: "Signature", content: Promise;`} /> }], - prev: { href: "/docs/hooks/use-subscribe-and-access", label: "useSubscribeAndAccess" }, - next: { href: "/docs/hooks/use-discover-vaults", label: "useDiscoverVaults" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-creator-vaults/page.tsx b/apps/site/app/docs/hooks/use-creator-vaults/page.tsx deleted file mode 100644 index bc7ec5e..0000000 --- a/apps/site/app/docs/hooks/use-creator-vaults/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hook, - lede: <>Returns the token ids owned by a given creator address — wraps the factory's getCreatorVaults(address). Standard wagmi useReadContract result shape., - importLine: 'import { useCreatorVaults } from "@cdr-kit/react"', - sections: [{ id: "signature", title: "Signature", content: }], - prev: { href: "/docs/hooks/use-vault-events", label: "useVaultEvents" }, - next: { href: "/docs/hooks/use-cdr-wallet", label: "useCdrWallet" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-dead-man-timer/page.tsx b/apps/site/app/docs/hooks/use-dead-man-timer/page.tsx deleted file mode 100644 index 1690dc5..0000000 --- a/apps/site/app/docs/hooks/use-dead-man-timer/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hooknew in 0.5, - lede: <>Live countdown to DeadManSwitchCondition.unlockAt + a creator-only poke() action. The data source for <HeartbeatTimer>., - importLine: 'import { useDeadManTimer } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: Promise; - isLoading: boolean; -};`} /> }, - { id: "address-override", title: "Address override", content:

The default reads from aeneid.deadManSwitchCondition. Pass address to point at a custom deployment (e.g. mainnet once it ships).

}, - ], - prev: { href: "/docs/hooks/use-cdr-wallet", label: "useCdrWallet" }, - next: { href: "/docs/hooks/use-time-window-state", label: "useTimeWindowState" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-discover-vaults/page.tsx b/apps/site/app/docs/hooks/use-discover-vaults/page.tsx deleted file mode 100644 index c618522..0000000 --- a/apps/site/app/docs/hooks/use-discover-vaults/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hook, - lede: <>One-shot historical scan of the factory's VaultCreated events. Paginates inside a bounded RPC window. For live feeds, pair with useVaultEvents., - importLine: 'import { useDiscoverVaults } from "@cdr-kit/react"', - sections: [{ id: "signature", title: "Signature", content: }], - prev: { href: "/docs/hooks/use-create-vault", label: "useCreateVault" }, - next: { href: "/docs/hooks/use-vault", label: "useVault" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-escrow-state/page.tsx b/apps/site/app/docs/hooks/use-escrow-state/page.tsx deleted file mode 100644 index f2d591e..0000000 --- a/apps/site/app/docs/hooks/use-escrow-state/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hooknew in 0.5, - lede: <>The buyer-side state machine for ConditionalEscrowCondition: listing + paid status + delivery + timeout countdown, plus the two write actions (pay, confirmDelivery)., - importLine: 'import { useEscrowState } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: Promise; - confirmDelivery: () => Promise; - isLoading: boolean; -};`} /> }, - ], - prev: { href: "/docs/hooks/use-multi-sig-status", label: "useMultiSigStatus" }, - next: { href: "/docs/hooks/use-storage-backend", label: "useStorageBackend" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-mint-license-token/page.tsx b/apps/site/app/docs/hooks/use-mint-license-token/page.tsx deleted file mode 100644 index 6bb7097..0000000 --- a/apps/site/app/docs/hooks/use-mint-license-token/page.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const SIG = `function useMintLicenseToken(client: StoryClient | undefined): { - mint: (params: { - licensorIpId: Hex; - licenseTermsId: bigint; - amount?: bigint; // default 1n - receiver?: Hex; // default connected wallet - maxMintingFee?: bigint; // default 0n (be careful with commercial flavors!) - }) => Promise<{ licenseTokenIds: bigint[]; txHash: Hex }>; - isLoading: boolean; - error?: Error; -};`; - -const EXAMPLE = `import { useStoryClient, useMintLicenseToken } from "@cdr-kit/react"; - -function BuyAccess({ ipId, licenseTermsId, priceWei }) { - const client = useStoryClient(); - const { mint, isLoading } = useMintLicenseToken(client); - return ( - - ); -}`; - -export default function Page() { - return ( - - hook - new in 0.5 - Story IP - - ), - lede: ( - <> - Buyer-side helper: mint Story license token(s) against an IP's{" "} - licenseTermsId. For commercial flavors the mint is the payment — - the fee flows from the buyer's wallet via WIP. The returned token id is the proof - the buyer holds the license; pass it as accessAuxData to read a - license-gated CDR vault. - - ), - importLine: 'import { useMintLicenseToken } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: }, - { id: "example", title: "Example", content: }, - { - id: "wip", - title: "WIP wrap + approval", - content: ( -

- Commercial PIL flavors charge in WIP (the ERC-20 wrap of native IP). Before - mint succeeds, the buyer wallet needs (1) enough WIP to cover the - fee × amount and (2) an allowance for the RoyaltyModule. Call agent.wrapIp{" "} - + agent.approveWip in the buyer flow, or wire matching hooks if you - build them in your dashboard. -

- ), - }, - { - id: "maxfee", - title: "Always set maxMintingFee", - content: ( -

- Default maxMintingFee is 0n — which means commercial - mints will revert! Pass the buyer-facing price you displayed in the UI to cap the - exposure if the seller changes the fee mid-tx. -

- ), - }, - ], - prev: { href: "/docs/hooks/use-register-ip", label: "useRegisterIp" }, - next: { href: "/docs/hooks/use-attach-license-terms", label: "useAttachLicenseTerms" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-multi-sig-status/page.tsx b/apps/site/app/docs/hooks/use-multi-sig-status/page.tsx deleted file mode 100644 index 2176d84..0000000 --- a/apps/site/app/docs/hooks/use-multi-sig-status/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hooknew in 0.5, - lede: <>Reads the configured signers + threshold + epoch for a MultiSigCondition vault. Sigs themselves live off-chain — combine this with your own collection state to render approval progress., - importLine: 'import { useMultiSigStatus } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: }, - ], - prev: { href: "/docs/hooks/use-time-window-state", label: "useTimeWindowState" }, - next: { href: "/docs/hooks/use-escrow-state", label: "useEscrowState" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-publish/page.tsx b/apps/site/app/docs/hooks/use-publish/page.tsx deleted file mode 100644 index 0889bd3..0000000 --- a/apps/site/app/docs/hooks/use-publish/page.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const SIG = `function usePublish(): { - publish: ( - agent: { publish: (p: PublishParams) => Promise }, - params: PublishParams, - ) => Promise; - isLoading: boolean; - error?: Error; - result?: PublishResult; -}; - -interface PublishParams { - data: Uint8Array; - spgNftContract: Hex; - pilTerms: unknown; // PILFlavor.commercialUse({...}) etc. - ipMetadata?: { ipMetadataURI?: string; ipMetadataHash?: Hex; nftMetadataURI?: string; nftMetadataHash?: Hex; }; -} - -interface PublishResult { - ipId: Hex; - tokenId: bigint; - licenseTermsId: bigint; - vaultUuid: number; - vaultTxHash: Hex; - ipRegisterTxHash: Hex; - writeTxHash: Hex; -}`; - -const EXAMPLE = `import { CdrAgent } from "@cdr-kit/agent"; -import { PILFlavor } from "@cdr-kit/story"; -import { usePublish } from "@cdr-kit/react"; -import { useAccount, useWalletClient } from "wagmi"; - -function PublishButton({ secret }: { secret: string }) { - const { data: walletClient } = useWalletClient(); - const { publish, isLoading, result, error } = usePublish(); - - const onClick = async () => { - if (!walletClient) return; - const agent = new CdrAgent({ - privateKey: "0x...", // server-side; in browser, pass walletClient.account - network: "aeneid", - }); - await publish(agent, { - data: new TextEncoder().encode(secret), - spgNftContract: "0xYourSpgCollection", - pilTerms: PILFlavor.commercialUse({ - defaultMintingFee: 1_000_000_000_000_000_000n, - commercialRevShare: 5, - }), - }); - }; - - return ( - <> - - {result && ( -
-{\`ipId:          \${result.ipId}
-licenseTermsId: \${result.licenseTermsId}
-vaultUuid:      \${result.vaultUuid}\`}
-        
- )} - {error && {error.message}} - - ); -}`; - -export default function Page() { - return ( - - hook - new in 0.5 - one-shot - Story IP - - ), - lede: ( - <> - Render-side wrapper for agent.publish() — the agent-as-publisher one-shot - that collapses register-IP + register-PIL-terms + attach-terms + create-license-gated-vault - + write-encrypted-data into a single call. Returns every artifact the buyer needs to - subscribe + read. - - ), - importLine: 'import { usePublish } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: }, - { id: "example", title: "Example", content: }, - { - id: "agent-required", - title: "Why does it take an `agent` argument?", - content: ( -

- agent.publish() needs a wallet client + private key for the - multi-step orchestration (4 contract writes across IP-registry, PIL-template, - CDR-precompile). The React hook stays headless — you construct the{" "} - CdrAgent however your app does (server-side env, browser RPC over the - connected wallet) and the hook handles loading/error/result state around it. -

- ), - }, - { - id: "buyer", - title: "Buyer flow", - content: ( -

- After publish resolves, share {`{ ipId, licenseTermsId, vaultUuid }`}{" "} - with the buyer (URL param, QR, on-chain event). They call agent.wrapIp →{" "} - agent.approveWipuseMintLicenseToken.mint →{" "} - agent.accessLicenseGated to pay + decrypt. See{" "} - /docs/story for the full buyer code. -

- ), - }, - ], - prev: { href: "/docs/hooks/use-attach-license-terms", label: "useAttachLicenseTerms" }, - next: { href: "/docs/storage", label: "Storage adapters" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-register-ip/page.tsx b/apps/site/app/docs/hooks/use-register-ip/page.tsx deleted file mode 100644 index 8a4dd59..0000000 --- a/apps/site/app/docs/hooks/use-register-ip/page.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const SIG = `function useRegisterIp(client: StoryClient | undefined): { - registerIp: (params: { - spgNftContract: Hex; - recipient?: Hex; - ipMetadataURI?: string; - ipMetadataHash?: Hex; - }) => Promise<{ ipId: Hex; tokenId: bigint; txHash: Hex }>; - isLoading: boolean; - error?: Error; -};`; - -const EXAMPLE = `import { useStoryClient, useRegisterIp } from "@cdr-kit/react"; - -function RegisterButton() { - const client = useStoryClient(); - const { registerIp, isLoading, error } = useRegisterIp(client); - return ( - - ); -}`; - -export default function Page() { - return ( - - hook - new in 0.5 - Story IP - - ), - lede: ( - <> - Mint a fresh NFT (via your SPG collection) and register it as a Story IP asset in a - single tx. Pair with useAttachLicenseTerms to make the IP licensable, then{" "} - useMintLicenseToken on the buyer side. - - ), - importLine: 'import { useRegisterIp } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: }, - { id: "example", title: "Example", content: }, - { - id: "prereq", - title: "Prerequisites", - content: ( -

- You need an existing SPG NFT collection. Create one via Story's registration - workflows (registrationWorkflows.createCollection) or use a previously - deployed collection address. The connected wallet must be allowed to mint into it. -

- ), - }, - ], - prev: { href: "/docs/hooks/use-story-client", label: "useStoryClient" }, - next: { href: "/docs/hooks/use-mint-license-token", label: "useMintLicenseToken" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-storage-backend/page.tsx b/apps/site/app/docs/hooks/use-storage-backend/page.tsx deleted file mode 100644 index b594ff6..0000000 --- a/apps/site/app/docs/hooks/use-storage-backend/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hooknew in 0.5, - lede: <>Config-driven CdrStorageProvider factory. A dashboard switches backends at runtime by passing a JSON config (Pinata / Supabase / IPFS / read-only gateway / in-memory)., - importLine: 'import { useStorageBackend } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: }; - -function useStorageBackend(config: StorageBackendConfig | undefined): CdrStorageProvider | undefined;`} /> }, - { id: "memoization", title: "Memoization", content:

The provider instance is memoized on config identity. Pass a stable config object (typically from your environment variables, not a fresh literal every render).

}, - ], - prev: { href: "/docs/hooks/use-escrow-state", label: "useEscrowState" }, - next: { href: "/docs/contracts", label: "Condition library" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-story-client/page.tsx b/apps/site/app/docs/hooks/use-story-client/page.tsx deleted file mode 100644 index 462d227..0000000 --- a/apps/site/app/docs/hooks/use-story-client/page.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const SIG = `function useStoryClient(chainId?: number): StoryClient | undefined;`; - -const EXAMPLE = `import { useStoryClient } from "@cdr-kit/react"; - -function Publish() { - const client = useStoryClient(); // bound to the connected wagmi wallet - if (!client) return

connect a wallet to publish

; - // client is the StoryClient from @story-protocol/core-sdk — - // pass it to useRegisterIp, useMintLicenseToken, etc. - return ; -}`; - -export default function Page() { - return ( - - hook - new in 0.5 - Story IP - - ), - lede: ( - <> - Lazy-load and memoize a StoryClient from @story-protocol/core-sdk{" "} - bound to the connected wagmi wallet. Returns undefined until the wallet - connects and the lazy import resolves. Pair with useRegisterIp,{" "} - useMintLicenseToken, useAttachLicenseTerms, or any other Story - SDK call. - - ), - importLine: 'import { useStoryClient } from "@cdr-kit/react"', - sections: [ - { - id: "signature", - title: "Signature", - content: , - }, - { - id: "example", - title: "Example", - content: , - }, - { - id: "lazy", - title: "Lazy-loaded peer dep", - content: ( -

- @cdr-kit/story is an optional peer dep on @cdr-kit/react{" "} - — the hook does a dynamic import("@cdr-kit/story") on first - call, so dashboards that never publish IP don't pay the bundle cost. If the - peer dep isn't installed, the hook throws with a clear install hint. -

- ), - }, - { - id: "chain", - title: "Custom chain", - content: ( -

- The default chainId is 1315 (Story Aeneid). Pass an explicit value to - bind the client to a different chain (e.g. Story mainnet once it ships). -

- ), - }, - ], - prev: { href: "/docs/hooks/use-storage-backend", label: "useStorageBackend" }, - next: { href: "/docs/hooks/use-register-ip", label: "useRegisterIp" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-subscribe-and-access/page.tsx b/apps/site/app/docs/hooks/use-subscribe-and-access/page.tsx deleted file mode 100644 index 17c651a..0000000 --- a/apps/site/app/docs/hooks/use-subscribe-and-access/page.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const SIG = `function useSubscribeAndAccess( - uuid: number, - subscriptionCondition?: Hex, -): { - run: (p: { - periods: bigint; - maxPricePerPeriod: bigint; - value: bigint; - accessAuxData?: Hex; - }) => Promise; - status: "idle" | "paying" | "collecting-partials" | "ready" | "error"; - data?: Uint8Array; -};`; - -export default function UseSubscribeAndAccessPage() { - return ( - hook, - lede: <>The full 2-step flow — pay (real subscribe tx) then access (threshold read). Five status values; design the "paying" and "collecting-partials" states legibly., - importLine: 'import { useSubscribeAndAccess } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: }, - ], - prev: { href: "/docs/hooks/use-access-vault", label: "useAccessVault" }, - next: { href: "/docs/hooks/use-create-vault", label: "useCreateVault" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-time-window-state/page.tsx b/apps/site/app/docs/hooks/use-time-window-state/page.tsx deleted file mode 100644 index d454c66..0000000 --- a/apps/site/app/docs/hooks/use-time-window-state/page.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hooknew in 0.5, - lede: <>Reads a TimeWindowCondition vault's [startTs, endTs] window + ticks a 1-second client-side timer to surface opensInMs/closesInMs., - importLine: 'import { useTimeWindowState } from "@cdr-kit/react"', - sections: [ - { id: "signature", title: "Signature", content: }, - { id: "block-based", title: "Block-based windows", content:

For blockBased: true windows, opensInMs/closesInMs return 0block.number isn't ticked client-side. Read the raw block bounds from the result object.

}, - ], - prev: { href: "/docs/hooks/use-dead-man-timer", label: "useDeadManTimer" }, - next: { href: "/docs/hooks/use-multi-sig-status", label: "useMultiSigStatus" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-vault-events/page.tsx b/apps/site/app/docs/hooks/use-vault-events/page.tsx deleted file mode 100644 index 3b334a5..0000000 --- a/apps/site/app/docs/hooks/use-vault-events/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hook, - lede: <>Live subscription to VaultCreated events on the factory. Returns events accumulated since mount — pair with useDiscoverVaults for backfill + live., - importLine: 'import { useVaultEvents } from "@cdr-kit/react"', - sections: [{ id: "signature", title: "Signature", content: }], - prev: { href: "/docs/hooks/use-vault", label: "useVault" }, - next: { href: "/docs/hooks/use-creator-vaults", label: "useCreatorVaults" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/hooks/use-vault/page.tsx b/apps/site/app/docs/hooks/use-vault/page.tsx deleted file mode 100644 index a753a0d..0000000 --- a/apps/site/app/docs/hooks/use-vault/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - hook, - lede: <>Resolve a vault's on-chain metadata from its uuid via the CdrKitVault factory (token id, IP id, creator, license terms id)., - importLine: 'import { useVault } from "@cdr-kit/react"', - sections: [{ id: "signature", title: "Signature", content: }], - prev: { href: "/docs/hooks/use-discover-vaults", label: "useDiscoverVaults" }, - next: { href: "/docs/hooks/use-vault-events", label: "useVaultEvents" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/page.tsx b/apps/site/app/docs/page.tsx deleted file mode 100644 index 2eb9eeb..0000000 --- a/apps/site/app/docs/page.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import Link from "next/link"; -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; - -export default function IntroductionPage() { - return ( - v0.5.0, - lede: ( - <> - cdr-kit is the developer toolkit for Story Protocol's Confidential Data Rails — the{" "} - wagmi-style layer that makes it possible to - ship private, paid, license-gated data on Story without hand-writing Solidity, hand-rolling encryption - flows, or wiring IP licensing primitives by hand. - - ), - sections: [ - { - id: "what", - title: "What's in the kit", - content: ( - <> -

- 15 packages, MIT-licensed, all published to{" "} - - npmjs.com/org/cdr-kit - {" "} - at v0.5.0: -

-
    -
  • - - @cdr-kit/react - {" "} - — components + hooks + theming (5 new 0.5 components, 7 new hooks) -
  • -
  • - @cdr-kit/react-ui — styled drop-ins built on the headless layer -
  • -
  • - - @cdr-kit/core - {" "} - — typed SDK (condition encoders, 2-step flows, 8 storage adapters, mock kit, WASM init) -
  • -
  • - - @cdr-kit/contracts - {" "} - — Solidity ABIs + deployed addresses for 9 conditions (5 base + 4 advanced in 0.5) -
  • -
  • - - @cdr-kit/agent - {" "} - — autonomous-agent client (discover → subscribe → access; +12 advanced helpers in 0.5) -
  • -
  • - - @cdr-kit/story - {" "} - — Story IP creator surface (NEW in 0.5): registerIpAsset / PIL flavors / mintLicenseTokens -
  • -
  • - @cdr-kit/tools — framework-agnostic tool definitions (34 tools) -
  • -
  • - Framework adapters:{" "} - - @cdr-kit/vercel-ai - {" "} - ·{" "} - - @cdr-kit/openai - {" "} - ·{" "} - - @cdr-kit/langchain - {" "} - ·{" "} - - @cdr-kit/agentkit - {" "} - ·{" "} - - @cdr-kit/goat - -
  • -
  • - - @cdr-kit/mcp - {" "} - — the MCP server (Claude Desktop / Cursor / Windsurf / OpenClaw) -
  • -
  • - - @cdr-kit/cli - {" "} - — the cdr binary (25 commands across vault / multi-sig / escrow / IP) -
  • -
  • - - create-cdr-kit-app - {" "} - — the scaffolder -
  • -
- - ), - }, - { - id: "where", - title: "Where to start", - content: ( - <> -
    -
  • - Quickstart — install, gate encrypted data in under 60s. -
  • -
  • - VaultGate component — the canonical drop-in. -
  • -
  • - Agent kit overview — autonomous agents that buy data. -
  • -
  • - Condition library — the Solidity standard library. -
  • -
- - ), - }, - ], - next: { href: "/docs/quickstart", label: "Quickstart" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/quickstart/page.tsx b/apps/site/app/docs/quickstart/page.tsx deleted file mode 100644 index 1a4c4e5..0000000 --- a/apps/site/app/docs/quickstart/page.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const PROVIDER_CODE = `import { CdrProvider } from "@cdr-kit/react"; -import { wagmiConfig } from "./wagmi"; - -export function App({ children }) { - return ( - - {children} - - ); -}`; - -const GATE_CODE = `import { VaultGate } from "@cdr-kit/react"; - -export function SignalCard() { - return ( - }> - {(data) =>
{new TextDecoder().decode(data)}
} -
- ); -}`; - -export default function QuickstartPage() { - return ( - ≈ 60 seconds, - lede: <>Install the React layer, wrap your app in a provider, drop in a <VaultGate>. That's it., - sections: [ - { - id: "install", - title: "Install", - content: , - }, - { - id: "provider", - title: "Wrap in ", - content: ( - <> -

- <CdrProvider> wires WagmiProvider, react-query, and initializes the CDR - crypto WASM. Pass config + apiUrl for live mode, or mockKit for - offline dev. -

- - - ), - }, - { - id: "gate", - title: "Gate your data", - content: ( - <> -

- <VaultGate> checks the on-chain condition, collects key shares, and hands you the - decrypted bytes. Pass a fallback for the "not yet entitled" state. -

- - - ), - }, - { - id: "scaffold", - title: "Or scaffold a starter", - content: , - }, - ], - prev: { href: "/docs", label: "Introduction" }, - next: { href: "/docs/theming", label: "Theming" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/scaffolder/page.tsx b/apps/site/app/docs/scaffolder/page.tsx deleted file mode 100644 index 1369ac1..0000000 --- a/apps/site/app/docs/scaffolder/page.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -export default function Page() { - return ( - create-cdr-kit-app9 templates · 0.3, - lede: <>One command per pattern. Pick a template and you have a working consumer app — paywalled blog, single-page Subscribe, stdio MCP server, or any of five agent-framework wirings — running locally in under a minute. Mock CDR out of the box; swap one provider to go live on Aeneid., - sections: [ - { - id: "invoke", - title: "Invoke", - content: ( - - ), - }, - { - id: "ui", - title: "UI templates", - content: ( - <> -

blog — Next.js 16 + React 19 + @cdr-kit/react-ui. Three inline <UnlockablePill>s on a real-looking blog post. The onscroll.app pattern. Recommended first.

-

paywall — Next.js single-page <SubscribeButton> gating a whole content block. Classic Substack/Patreon pattern.

- - ), - }, - { - id: "mcp", - title: "MCP server template", - content: ( - <> -

mcp-server — stdio Model Context Protocol server. Exposes cdr_discover_vaults, cdr_subscribe_and_access, cdr_access_vault to any MCP host (Claude Desktop, Cursor, Windsurf). The agent pays from its own wallet — the LLM never sees the key.

-

Ships with a ready-to-paste claude_desktop_config.json.

- - ), - }, - { - id: "agents", - title: "Agent templates (one per framework)", - content: ( - <> -

Each template instantiates new CdrAgent({"{"} privateKey, apiUrl {"}"}) and wires CDR tools into the named framework. Pick the one your stack uses; the rest of your agent logic stays untouched.

-

agent-vercel-ai — Vercel AI SDK chatbot using getVercelAITools(agent) with generateText.

-

agent-openai — Raw OpenAI / Anthropic tool-calling loop using getOpenAITools(agent).{"{"}tools, dispatch{"}"}.

-

agent-langchain — LangChain ReAct agent via createReactAgent({"{"}llm, tools: getLangChainTools(agent){"}"}).

-

agent-agentkit — Coinbase AgentKit action provider via getCdrActionProvider(agent). Compose with your wallet provider.

-

agent-goat — GOAT SDK ToolBase[] via getGoatTools(agent).

- - ), - }, - { - id: "starter", - title: "starter template", - content: ( - <> -

starter — Two-file Node TypeScript script that runs createMockCdrKit() + accessVault() end-to-end. Good for verifying the kit works in your env or for backend-only CDR work.

- - - ), - }, - ], - prev: { href: "/docs/contracts/cdr-kit-vault", label: "CdrKitVault" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/skill/page.tsx b/apps/site/app/docs/skill/page.tsx deleted file mode 100644 index 275de70..0000000 --- a/apps/site/app/docs/skill/page.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const INSTALL_PATHS = `# 1. via the cdr CLI (recommended) -$ npm install -g @cdr-kit/cli -$ cdr skill install - -# 2. via Claude Code's plugin marketplace -$ claude -/plugin marketplace add Blockchain-Oracle/cdr-kit -/plugin install cdr-kit@cdr-kit - -# 3. manual -$ git clone https://github.com/Blockchain-Oracle/cdr-kit -$ cp -r cdr-kit/packages/plugin/cdr-kit ~/.claude/skills/cdr-kit`; - -const SKILLS: { name: string; trigger: string; what: string }[] = [ - { name: "design-condition", trigger: "Which CDR condition should I use for X?", what: "Decision tree for picking among open / subscription / tier-gate / composable / license-read. Encoding cheatsheet per condition." }, - { name: "wire-allocate-pay-read", trigger: "How do I create a vault and read it?", what: "The canonical 4-step flow (creator + consumer sides). Gotchas: OOG, uuid-from-receipt, value-must-match-price." }, - { name: "debug-cdr-precompile", trigger: "OOG / ReentrancySentryOOG / AlreadyConfigured / partial-collection timeout", what: "7 failure modes with root cause + fix. Backed by the gotchas in context/research/cdr-protocol-truth.md." }, - { name: "audit-vault-config", trigger: "Should I subscribe to this? / Did my deploy configure right?", what: "4-call view-only audit. Red-flag checklist (payee mismatch, never-expiring period, missing licenseTermsId)." }, - { name: "explain-cdr-error", trigger: "(Any raw error message)", what: "Lookup table from error code → root cause + fix. Maps every @piplabs/cdr-sdk error class." }, - // 0.5 — advanced features - { name: "design-storage-adapter", trigger: "Which storage backend for my CDR file vault? Pinata / Supabase / R2 / Storacha?", what: "Decision tree for picking among the 6 official adapters + 3 ecosystem packages. Wiring examples, common failure modes (CORS, RLS, CID drift)." }, - { name: "design-multisig-condition", trigger: "Multi-sig CDR vault / N-of-M approval / off-chain signing", what: "N-of-M EIP-712 setup, signer rotation, sig-collection UX, caller binding, ECDSA-malleability dedupe, EIP-1271 gap." }, - { name: "design-deadman-switch", trigger: "Dead-man switch / wallet recovery / leak-on-disappearance / heartbeat", what: "Trapdoor semantics, poke() cadence, block-vs-timestamp tradeoff, heir variants, operational risk (forgotten heartbeat)." }, -]; - -export default function Page() { - return ( - cdr-kit plugin8 skills · v0.5, - lede: <>A multi-skill Claude Code plugin (Trail-of-Bits density) that teaches any agent the cdr-kit workflows. Each SKILL.md is under 500 lines (per Anthropic's hard cap); reference docs (ABIs, error catalog) live in a references/ subdir loaded on demand. Pairs with the cdr CLI and the @cdr-kit/mcp server — three coordinated surfaces, one bundle., - sections: [ - { id: "install", title: "Install (three paths)", content: }, - { - id: "skills", - title: "Skills (8)", - content: ( - - - - {SKILLS.map((s) => ( - - - - - - ))} - -
SkillWhen it firesWhat it teaches
{s.name}{s.trigger}{s.what}
- ), - }, - { - id: "layout", - title: "Plugin layout", - content: ( - - ), - }, - { - id: "boundary", - title: "Skill vs MCP vs CLI", - content: ( - <> -

- Per the Anthropic-blessed boundary (guide): MCP = let Claude access external systems; Skill = let Claude know how to do something; CLI = the same operations exposed for a human in the terminal. -

-

- cdr-kit ships all three from one shared core: the 21 CDR operations are MCP tools in @cdr-kit/mcp; this plugin's 8 SKILL.mds teach Claude the procedural knowledge for designing, wiring, and debugging around those tools; cdr exposes the same surface for terminal use. -

- - ), - }, - ], - prev: { href: "/docs/cli", label: "CLI: cdr" }, - next: { href: "/docs/contracts", label: "Contracts" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/storage/page.tsx b/apps/site/app/docs/storage/page.tsx deleted file mode 100644 index 750f401..0000000 --- a/apps/site/app/docs/storage/page.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const PINATA_CODE = `import { createPinataStorage, uploadFile } from "@cdr-kit/core"; - -const storage = createPinataStorage({ jwt: process.env.PINATA_JWT! }); -const { uuid, cid, txHashes } = await uploadFile(client, { - content: fileBytes, - storage, - readConditionAddr, - readConditionData, -});`; - -const SUPABASE_CODE = `import { createSupabaseStorage } from "@cdr-kit/core"; - -const storage = createSupabaseStorage({ - supabaseUrl: process.env.SUPABASE_URL!, - key: process.env.SUPABASE_SERVICE_ROLE_KEY!, - bucket: "cdr-secrets", - pathPrefix: "vaults/", // optional, default "cdr/" - bucketIsPublic: false, // download uses /authenticated/ when private -});`; - -const READ_ONLY_CODE = `import { createReadOnlyGatewayStorage, downloadFile } from "@cdr-kit/core"; - -// Buyer-side: read from any public IPFS gateway. Throws on upload() — by design. -const storage = createReadOnlyGatewayStorage({ gatewayUrl: "https://gateway.pinata.cloud" }); -const { content } = await downloadFile(client, { uuid, storage });`; - -const IPFS_CODE = `import { createIpfsStorage } from "@cdr-kit/core"; - -// Self-hosted Kubo, or any pinning service with a multipart POST + JSON CID response. -const storage = createIpfsStorage({ - addUrl: "http://kubo:5001/api/v0/add", - gatewayUrl: "http://kubo:8080", - headers: { Authorization: "Bearer ..." }, -});`; - -const MEMORY_CODE = `import { createMemoryStorage } from "@cdr-kit/core"; - -// Unit tests, CI, mocks. Content-addressed, returns a real CIDv1. -const storage = createMemoryStorage();`; - -const S3_CODE = `import { createS3Storage } from "@cdr-kit/core"; - -// Works against AWS S3, Cloudflare R2, MinIO, or any S3-compatible store. -// Lazy-loads @aws-sdk/client-s3 via dynamic import — install it yourself. -const storage = await createS3Storage({ - bucket: "cdr-secrets", - region: "auto", // R2: "auto"; AWS: "us-east-1" etc. - endpoint: "https://.r2.cloudflarestorage.com", // omit for AWS - accessKeyId: process.env.S3_ACCESS_KEY_ID!, - secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!, - publicUrlBase: "https://.r2.dev/cdr-secrets", // for browser-readable downloads - prefix: "cdr/", -});`; - -const STORACHA_CODE = `import { createStorachaStorage } from "@cdr-kit/core"; - -// Storacha-server (UCAN-backed pinning over @web3-storage/w3up-client). -// Install: pnpm add @web3-storage/w3up-client -const storage = await createStorachaStorage({ - key: process.env.STORACHA_KEY!, - spaceDid: process.env.STORACHA_SPACE_DID!, - proof: process.env.STORACHA_PROOF!, // base64 UCAN delegation - gatewayUrl: "https://w3s.link", // optional, default w3s.link -});`; - -const HELIA_CODE = `import { createHeliaStorage } from "@cdr-kit/core"; - -// Browser-side embedded IPFS via Helia — no remote pinner, the user is the node. -// Install: pnpm add helia @helia/unixfs -// Pin @peculiar/webcrypto: 1.7.0 in pnpm.overrides (Helia's wasm setup is fragile). -const storage = await createHeliaStorage({ - gatewayUrl: "https://ipfs.io", // optional, only used by downloadFile if user is offline -});`; - -const ROUTING_CODE = `import { shouldUseFile, getInlineLimit } from "@cdr-kit/core"; - -const limit = await getInlineLimit(client); // reads CDR.maxEncryptedDataSize() once + caches -if (shouldUseFile(content, limit)) { - await uploadFile(client, { content, storage, readConditionAddr, readConditionData }); -} else { - await writeVaultData(client, { uuid, dataKey: content }); -}`; - -export default function Page() { - return ( - @cdr-kit/core0.5, - lede: <>CDR vaults route payloads by size: ≤ 1 KB goes inline on-chain, larger payloads go off-chain with a CDR-secured key reference. The off-chain path needs a CdrStorageProvider8 ship in @cdr-kit/core (5 core + 3 ecosystem: S3-compat / Storacha / Helia). All speak the same 2-method interface: upload(bytes) → cid, download(cid) → bytes., - importLine: 'import { createPinataStorage, createSupabaseStorage, /* ... */ } from "@cdr-kit/core"', - sections: [ - { - id: "decision", - title: "Pick the right adapter", - content: ( -
    -
  • Buyer-only / dashboardscreateReadOnlyGatewayStorage (no pin creds needed, throws on upload).
  • -
  • Hosted IPFS pinningcreatePinataStorage (JWT, default Pinata gateway).
  • -
  • Already-have-Supabase shopscreateSupabaseStorage (bucket + service-role key, bare REST — no @supabase/supabase-js dep).
  • -
  • Self-hosted Kubo / custom pinnercreateIpfsStorage (multipart POST + JSON CID response).
  • -
  • AWS S3 / R2 / MinIOcreateS3Storage (signed-URL downloads, lazy-loads @aws-sdk/client-s3).
  • -
  • UCAN-backed pinningcreateStorachaStorage (peer-dep @web3-storage/w3up-client).
  • -
  • Browser-embedded IPFScreateHeliaStorage (peer-dep helia, user is the node).
  • -
  • Tests / CIcreateMemoryStorage (content-addressed, real CIDv1).
  • -
- ), - }, - { - id: "pinata", - title: "createPinataStorage", - content: , - }, - { - id: "supabase", - title: "createSupabaseStorage", - content: ( - <> - -

The "CID" is the bucket-relative path the object was uploaded to. Supabase doesn't speak IPFS, but CdrStorageProvider only requires a string round-trip handle.

- - ), - }, - { - id: "gateway", - title: "createReadOnlyGatewayStorage", - content: ( - <> - -

For dashboards that consume but never produce. Pair with a seller using createPinataStorage (or any IPFS pinner) on the write side.

- - ), - }, - { - id: "ipfs", - title: "createIpfsStorage", - content: , - }, - { - id: "memory", - title: "createMemoryStorage", - content: , - }, - { - id: "routing", - title: "Inline cap + routing", - content: ( - <> -

CDR sizes payloads at write time. The hard cap comes from the on-chain CDR.maxEncryptedDataSize() (currently ≈ 1 KB after TDH2 overhead). getInlineLimit(client) reads it once + caches; shouldUseFile(content, limit) picks the routing.

- - - ), - }, - { - id: "s3", - title: "createS3Storage", - content: ( - <> -

Works against AWS S3, Cloudflare R2, or any S3-compatible store. The SDK is loaded lazily via dynamic import so non-S3 deployments don't pay the bundle cost. Install @aws-sdk/client-s3 yourself in your project.

- - - ), - }, - { - id: "storacha", - title: "createStorachaStorage", - content: ( - <> -

UCAN-backed pinning service. Lazy-loads @web3-storage/w3up-client; install it yourself. The agent address must be authorized for the Space via a base64 UCAN proof.

- - - ), - }, - { - id: "helia", - title: "createHeliaStorage", - content: ( - <> -

Browser-side embedded IPFS. The user's tab IS the IPFS node — no remote pinner needed. Lazy-loads helia + @helia/unixfs. Pin @peculiar/webcrypto: 1.7.0 in pnpm.overrides (Helia's WASM init is sensitive to webcrypto version drift).

- - - ), - }, - ], - prev: { href: "/docs/hooks/use-storage-backend", label: "useStorageBackend" }, - next: { href: "/docs/contracts", label: "Condition library" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/story/page.tsx b/apps/site/app/docs/story/page.tsx deleted file mode 100644 index 8f9d524..0000000 --- a/apps/site/app/docs/story/page.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { Badge } from "@/components/primitives/badge"; -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const PUBLISH_CODE = `import { CdrAgent } from "@cdr-kit/agent"; -import { PILFlavor } from "@cdr-kit/story"; - -const agent = new CdrAgent({ privateKey: process.env.CDR_PRIVATE_KEY!, network: "aeneid" }); - -const result = await agent.publish({ - data: new TextEncoder().encode("the secret data"), - spgNftContract: "0xYourSpgCollection", - pilTerms: PILFlavor.commercialUse({ - defaultMintingFee: 1_000_000_000_000_000_000n, // 1 WIP per license - commercialRevShare: 5, // 5% derivative revenue - }), -}); - -// → { ipId, tokenId, licenseTermsId, vaultUuid, -// vaultTxHash, ipRegisterTxHash, writeTxHash }`; - -const BUYER_CODE = `// Buyer flow once they have { ipId, licenseTermsId, vaultUuid }: -await agent.wrapIp({ amountWei: 1_000_000_000_000_000_000n }); -await agent.approveWip({ spender: ROYALTY_MODULE, amountWei: 1_000_000_000_000_000_000n }); - -const { licenseTokenIds } = await agent.mintLicenseTokens({ - licensorIpId: ipId, - licenseTermsId, - amount: 1n, - maxMintingFee: 1_000_000_000_000_000_000n, -}); - -const bytes = await agent.accessLicenseGated({ - uuid: vaultUuid, - licenseTokenId: licenseTokenIds[0]!, -});`; - -export default function Page() { - return ( - @cdr-kit/story0.5, - lede: <>Thin TypeScript wrappers over @story-protocol/core-sdk: register an IP asset, attach PIL license terms, mint license tokens, register derivatives, wrap IP into WIP. Plus the headline agent.publish() one-shot that collapses register-IP + attach-terms + create-license-gated-vault + write-encrypted-data into a single agent call., - importLine: 'import { PILFlavor, createStoryClient } from "@cdr-kit/story"', - sections: [ - { - id: "publish", - title: "agent.publish() — the one-shot", - content: ( - <> -

Collapses 4 normally-separate Story SDK calls into a single agent method. Returns the IP / license / vault artifacts a buyer needs to subscribe + read.

- - - ), - }, - { - id: "buyer", - title: "Buyer flow", - content: ( - <> -

Once the seller publishes, share {`{ ipId, licenseTermsId, vaultUuid }`} with buyers (URL, QR, whatever). Buyer wraps IP → mints license token → reads vault:

- - - ), - }, - { - id: "flavors", - title: "PIL flavors", - content: ( -
    -
  • PILFlavor.nonCommercialSocialRemixing() — open-source / free public IP (0 fee, 0 rev share).
  • -
  • PILFlavor.commercialUse({"{ defaultMintingFee, commercialRevShare }"}) — paid one-off use, no derivatives.
  • -
  • PILFlavor.commercialRemix({"{ defaultMintingFee, commercialRevShare }"}) — paid use + derivative works allowed, revenue flows back.
  • -
  • PILFlavor.creativeCommonsAttribution() — CC-BY style (0 fee, attribution required).
  • -
- ), - }, - { - id: "individual", - title: "Lower-level wrappers", - content: ( -

If publish() doesn't fit, the individual wrappers stay accessible from the agent: registerIpAsset, attachLicenseTerms, mintLicenseTokens, registerDerivative, registerPilTerms, wrapIp, approveWip. Each is a thin @story-protocol/core-sdk wrapper with normalized return shapes.

- ), - }, - { - id: "react", - title: "React hooks", - content: ( -

@cdr-kit/react exposes useStoryClient (memoized client bound to the wagmi wallet), useRegisterIp, useAttachLicenseTerms, useMintLicenseToken, and usePublish (the one-shot delegator). Both @cdr-kit/agent and @cdr-kit/story are optional peer deps on the React package — pay only when you publish.

- ), - }, - { - id: "skill", - title: "Design skill", - content: ( -

See design-publish-with-story SKILL.md for the decision tree on picking PIL flavor, prerequisites (SPG NFT collection), common failure modes, and the agent / CLI / MCP triangulation.

- ), - }, - ], - prev: { href: "/docs/agent-kit", label: "Agent kit" }, - next: { href: "/docs/contracts", label: "Condition library" }, - }} - /> - ); -} diff --git a/apps/site/app/docs/theming/page.tsx b/apps/site/app/docs/theming/page.tsx deleted file mode 100644 index 04713ad..0000000 --- a/apps/site/app/docs/theming/page.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { DocPage } from "@/components/docs/doc-page"; -import { CodePanel } from "@/components/docs/code-panel"; - -const APPEARANCE_CODE = ``; - -export default function ThemingPage() { - return ( - - @cdr-kit/react is intentionally headless. The components ship minimal default visuals; you theme - the look through CSS custom properties passed via CdrProvider.appearance.variables (or by setting - them on a parent stylesheet). - - ), - sections: [ - { - id: "tokens", - title: "Recognized tokens", - content: ( -
    -
  • --cdr-accent — primary accent
  • -
  • --cdr-border — hairline border color
  • -
  • --cdr-skeleton — placeholder background
  • -
  • --cdr-fg, --cdr-muted — text colors
  • -
- ), - }, - { - id: "passing", - title: "Passing tokens", - content: ( - - ), - }, - { - id: "styled", - title: "Styled variants", - content: ( -

- Want batteries-included pre-styled components instead of headless slots? See{" "} - @cdr-kit/react-ui in the component gallery. -

- ), - }, - ], - prev: { href: "/docs/quickstart", label: "Quickstart" }, - next: { href: "/docs/components/cdr-provider", label: "CdrProvider" }, - }} - /> - ); -} diff --git a/apps/site/app/globals.css b/apps/site/app/globals.css index bd681ce..23165e8 100644 --- a/apps/site/app/globals.css +++ b/apps/site/app/globals.css @@ -495,3 +495,67 @@ h1, h2, h3 { font-family: var(--display); font-weight: 700; letter-spacing: -0.0 .footer-bottom .mono { font-size: 0.76rem; color: var(--ink-3); } @media (max-width: 760px) { .footer-inner { grid-template-columns: 1fr 1fr; gap: 30px; } } + +/* T1-F: docs search — compact icon button in nav, popover dialog with results */ +.nav-search-btn { display: inline-flex; align-items: center; gap: 6px; padding: 0 9px; font-family: ui-monospace, monospace; font-size: 0.72rem; } +.nav-search-btn svg { width: 14px; height: 14px; } +.nav-search-kbd { color: var(--ink-2); opacity: 0.7; } +@media (max-width: 720px) { .nav-search-kbd { display: none; } } + +.nav-search-overlay { + position: fixed; inset: 0; z-index: 200; + display: grid; place-items: start center; + padding: 8vh 20px 20px; + background: color-mix(in oklab, oklch(0% 0 0) 50%, transparent); + backdrop-filter: blur(6px); +} +.nav-search-panel { + width: 100%; max-width: 640px; + background: var(--paper, oklch(17% 0.012 90)); + border: 1px solid var(--line, oklch(22% 0.012 90)); + border-radius: 14px; + box-shadow: 0 24px 48px -16px color-mix(in oklab, oklch(0% 0 0) 60%, transparent); + overflow: hidden; +} +.nav-search-inputrow { + display: flex; align-items: center; gap: 10px; + padding: 14px 16px; + border-bottom: 1px solid var(--line, oklch(22% 0.012 90)); + color: var(--ink-2, oklch(70% 0.012 90)); +} +.nav-search-inputrow input { + flex: 1; min-width: 0; + background: transparent; border: 0; outline: none; + color: var(--ink, oklch(94% 0.01 90)); + font: inherit; font-size: 1rem; +} +.nav-search-inputrow input::placeholder { color: var(--ink-3, oklch(56% 0.01 90)); } +.nav-search-esckbd { + padding: 2px 6px; border-radius: 4px; font-family: ui-monospace, monospace; font-size: 0.7rem; + background: var(--paper-2, oklch(20% 0.012 90)); + border: 1px solid var(--line, oklch(24% 0.012 90)); + color: var(--ink-2, oklch(70% 0.012 90)); +} +.nav-search-results { max-height: min(60vh, 520px); overflow-y: auto; } +.nav-search-result { + display: flex; flex-direction: column; gap: 2px; + padding: 10px 16px; + border-bottom: 1px solid color-mix(in oklab, var(--line) 60%, transparent); + text-decoration: none; +} +.nav-search-result.is-focused, .nav-search-result:hover { + background: color-mix(in oklab, var(--accent, oklch(78% 0.16 70)) 10%, transparent); +} +.nav-search-title { + color: var(--ink, oklch(94% 0.01 90)); + font-size: 0.94rem; line-height: 1.3; +} +.nav-search-url { + color: var(--ink-3, oklch(56% 0.01 90)); + font-family: ui-monospace, monospace; font-size: 0.74rem; +} +.nav-search-empty, .nav-search-hint { + padding: 18px 16px; margin: 0; + color: var(--ink-3, oklch(56% 0.01 90)); + font-size: 0.9rem; +} diff --git a/apps/site/app/layout.tsx b/apps/site/app/layout.tsx index 481a04e..ddbbc6c 100644 --- a/apps/site/app/layout.tsx +++ b/apps/site/app/layout.tsx @@ -4,6 +4,7 @@ import { fontVariables } from "@/lib/fonts"; import { Nav } from "@/components/nav"; import { Footer } from "@/components/footer"; import { Reveal } from "@/components/reveal"; +import { SiteProviders } from "./providers"; import "./globals.css"; import "@cdr-kit/react-ui/styles.css"; @@ -24,10 +25,12 @@ export default function RootLayout({ children }: { children: ReactNode }) {