clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

fix/175-template-quality-pass
lofi / website / src / pages / node.tsx
node.tsx 9.3K
1import type { ReactNode } from "react";2import Link from "@docusaurus/Link";3import useDocusaurusContext from "@docusaurus/useDocusaurusContext";4import Layout from "@theme/Layout";5import NodePlayground from "../components/NodePlayground";6import TicketAnatomy from "../components/TicketAnatomy";7import SliceMerge from "../components/SliceMerge";89import "../css/landing.css";10import "../css/node-landing.css";1112// The /node landing: lofi-node's front door. Shares the brand tokens with the13// root landing but none of its furniture. The page is three interactive14// rigs: a node you operate, a ticket you open, and a store two apps share.15// lofi-node is an END USER capability (owning where their data syncs), not a16// way to host a lofi app; the copy keeps that audience.1718export default function NodeHome(): ReactNode {19 const { siteConfig } = useDocusaurusContext();20 const version = siteConfig.customFields?.lofiNodeVersion as string;2122 return (23 <Layout24 title="lofi-node"25 description="lofi apps let their users choose where data syncs. lofi-node makes that choice real. One daemon a user runs, with an embedded Jazz sync server, iroh node-to-node transport, and a ticket-based access gate."26 >27 <main className="landing landing--node">28 {/* ===================== HERO: MARK + THE PLAYABLE NODE ===================== */}29 <div className="wrap">30 <header className="node-hero">31 <div className="node-hero-top">32 <h1 className="nmark" aria-label="lofi-node">33 <span className="lo">lo</span>34 <span className="fi">fi</span>35 <span className="dash">-</span>36 <span className="node">node</span>37 </h1>38 <div className="node-hero-side">39 <p className="eyebrow">40 <span>user-owned sync</span>41 <span className="pill">v{version} · alpha · MIT</span>42 </p>43 <div className="cta-row">44 <Link45 className="btn btn--primary"46 to="/node/docs/self-host-a-sync-node"47 >48 Host your first node49 </Link>50 <Link className="btn" to="/node/docs">docs</Link>51 <Link52 className="btn"53 href="https://github.com/FelineStateMachine/lofi-node"54 >55 source56 </Link>57 </div>58 </div>59 </div>60 <NodePlayground />61 </header>62 </div>6364 {/* ===================== TICKET ANATOMY ===================== */}65 <div className="wrap">66 <section className="band band--rule">67 <div className="band-head">68 <p className="eyebrow">A singular entry</p>69 <h2>Open the ticket.</h2>70 <p className="lede band-lede">71 No accounts, no OAuth, no server-side user table. A{" "}72 <code className="inline-mono">lofisync1.</code>{" "}73 string carries the store's identity and a bearer secret riding74 the URL path, which is why the app needs zero changes to sync75 somewhere new. And when enrollment binds a ticket to its76 device, the string alone stops being enough: a key that never77 leaves the device signs a fresh proof at every connect. Click a78 field.79 </p>80 </div>81 <TicketAnatomy />82 <p className="dim intro-note">83 The normative spec lives with the node and renders here from the84 pinned source:{" "}85 <Link to="/node/docs/app-ticket">the app-ticket contract</Link>.86 <br />87 Both repos test against the same conformance fixtures, so the88 string above can't drift quietly.89 </p>90 </section>91 </div>9293 {/* ===================== SHARED STORE ===================== */}94 <div className="wrap">95 <section className="band band--rule">96 <div className="band-head">97 <p className="eyebrow">many apps, one store, no folklore</p>98 <h2>Apps are tenants. The store is yours.</h2>99 <p className="lede band-lede">100 A user's node can hold several lofi apps' data at once. Each app101 may provision only the tables under its own namespaces;102 everything else, a neighbor's tables{" "}103 <em>and its access rules</em>, rides through byte-for-byte. Run104 the story below; every step of it is a real, conformance-tested105 flow.106 </p>107 </div>108 <SliceMerge />109 <p className="dim intro-note">110 The full model:{" "}111 <Link to="/node/docs/sliceable-apps-and-shared-stores">112 sliceable apps and shared stores113 </Link>{" "}114 and the hands-on version,{" "}115 <Link to="/node/docs/provision-a-store">116 provision a store117 </Link>.118 </p>119 </section>120 </div>121122 {/* ===================== HONESTY + PATHS ===================== */}123 <div className="wrap">124 <section className="band band--rule">125 <div className="two-up">126 <div>127 <div className="band-head band-head--tight">128 <h2>Still curious?</h2>129 </div>130 <ul className="limits">131 <li>132 <b>The data plane is Jazz 2 alpha, pinned exactly.</b>{" "}133 A node must run the same alpha as the apps it serves; bumps134 are coordinated.135 </li>136 <li>137 <b>Windows runs LAN-only.</b>{" "}138 A documented native-build gap; the store works, pairing139 reports itself unavailable instead of degrading silently.140 </li>141 <li>142 <b>Tickets start as bearer strings.</b>{" "}143 Enrolling a provision ticket binds the derived credential144 to a device key, so a stolen string alone no longer145 connects — but binding defeats credential theft, not a146 compromised page. Plain http is for trusted LANs; beyond147 one, front the gate with TLS.148 </li>149 <li>150 <b>Storage is SQLite or memory</b>, the engine's honest151 surface today. Replicate the file for off-site durability.152 </li>153 </ul>154 </div>155 <div>156 <div className="band-head band-head--tight">157 <h2>Keep going.</h2>158 </div>159 <ul className="node-paths">160 <li>161 <b>162 <Link to="/node/docs/self-host-a-sync-node">163 Self-host a node164 </Link>165 </b>: compile, init, ticket, enroll.166 </li>167 <li>168 <b>169 <Link to="/node/docs/pair-two-homes">Pair two homes</Link>170 </b>: hole-punched, no static IPs.171 </li>172 <li>173 <b>174 <Link to="/node/docs/provision-a-store">175 Provision a store176 </Link>177 </b>: the merge, end to end.178 </li>179 <li>180 <b>181 <Link to="/node/docs/tickets-explained">182 Tickets explained183 </Link>184 </b>: scopes, device binding, revocation.185 </li>186 <li>187 <b>188 <Link to="/node/docs/write-verdicts">189 Write verdicts190 </Link>191 </b>: every rejection permanent or transient, never192 folklore — plus the health contract and last-seen per193 ticket.194 </li>195 <li>196 <b>197 <Link to="/node/docs/cli">CLI</Link> ·{" "}198 <Link to="/node/docs/configuration">Configuration</Link> ·199 {" "}200 <Link to="/node/docs/http-surface">HTTP</Link>201 </b>: the reference shelf.202 </li>203 <li>204 <b>205 <Link to="/node/api">API reference</Link>206 </b>: <code className="inline-mono">createSyncNode</code>207 {" "}208 and friends, generated from source.209 </li>210 <li>211 <b>212 <Link to="/node/llms.txt" target="_blank">213 /node/llms.txt214 </Link>215 </b>: the node corpus for agents, separate from the216 framework's.217 </li>218 </ul>219 </div>220 </div>221 </section>222 </div>223 </main>224 </Layout>225 );226}