Skip to content

crs48/xNet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,116 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

xNet

CI npm: @xnetjs/react Electron App Demo App Hub Image Demo Hub Docs GitHub Stars License: MIT TypeScript pnpm Turborepo PRs Welcome

Decentralized data infrastructure and application. Local-first, P2P-synced, user-owned data.

xNet is both the underlying infrastructure and the user-facing app — one product, one brand. It starts with documents and databases, then expands via plugins to support ERP, MCP integrations, and more.

Try It Now

Try the demo at xnet.fyi/app — no signup required, just use your device's passkey (Touch ID, Face ID, Windows Hello).

Demo mode: Your data is stored locally in your browser (local-first). Encrypted backups sync to our demo hub with a 10MB quota and expire after 24 hours of inactivity. For reliable cross-device sync and permanent backups, download the desktop app.

Deploy a Hub

Deploy on Railway

Getting Started

# Install dependencies
pnpm install

# Run the root Storybook catalog and workbenches
pnpm dev:stories

# Build the static Storybook site
pnpm build:stories

# Build all packages
pnpm build

# Run unit tests (~2400 tests across 148 test files)
pnpm test

# Run integration tests (real browser via Playwright)
pnpm --filter @xnetjs/integration-tests test

# Type check
pnpm typecheck

# Lint
pnpm lint

Component Development

xNet now ships a root Storybook workspace for isolated component development across shared UI and app-facing surfaces.

  • Run pnpm dev:stories from the repo root to launch Storybook on http://127.0.0.1:6006.
  • Use pnpm build:stories to produce the static catalog and pnpm test:stories to run Storybook tests against a running server.
  • In Electron dev builds, open the embedded Storybook surface from Open Stories in the system menu or command palette.
  • In Web dev builds, open the embedded route at /stories.

Current Storybook coverage includes:

  • @xnetjs/ui primitives, composed components, comments, settings, and devtools catalogs
  • @xnetjs/editor rich collaborative editor workbench
  • @xnetjs/views database surface workbench
  • @xnetjs/canvas canvas workbench
  • selected Electron and Web renderer stories

Monorepo Structure

packages/           # 21 core SDK packages (@xnetjs/*)
apps/               # Electron, Web, Expo applications
site/               # Astro + Starlight documentation website
tests/              # Browser-based integration tests (Playwright)
docs/               # Vision, explorations, implementation plans

See the README in each directory for details:

Packages

Foundation

Package Description
@xnetjs/core Types, content addressing (CIDs), permissions, RBAC
@xnetjs/crypto BLAKE3 hashing, Ed25519 signing, XChaCha20 encryption
@xnetjs/identity DID:key generation, UCAN tokens, passkey storage

Infrastructure

Package Description
@xnetjs/storage SQLite/memory adapters, blob store, chunk manager, snapshots
@xnetjs/sync Change<T>, Lamport clocks, hash chains, Yjs security layer
@xnetjs/data Schema system, NodeStore, 15 property types, Yjs CRDT, built-in schemas
@xnetjs/network libp2p node, y-webrtc provider, peer scoring, security suite
@xnetjs/query Local query engine, MiniSearch full-text search, federated router
@xnetjs/hub Signaling server, sync relay, backup, FTS5 search, sharding, federation

Application

Package Description
@xnetjs/react useQuery, useMutate, useNode, hub hooks, plugin hooks, sync infrastructure
@xnetjs/sdk Unified client, browser/node presets, re-exports
@xnetjs/editor TipTap collaborative editor, slash commands, wikilinks, drag-drop, mermaid
@xnetjs/ui Radix UI primitives, composed components, theme system, design tokens
@xnetjs/views Table, Board, Gallery, Timeline, Calendar views with property renderers
@xnetjs/canvas Infinite canvas, R-tree spatial indexing, ELK.js auto-layout, Yjs-backed store
@xnetjs/devtools 9-panel debug suite (node explorer, sync monitor, Yjs inspector, ...)
@xnetjs/history Time machine, undo/redo, audit trails, blame, diff, verification
@xnetjs/plugins Plugin registry, sandboxed scripts, AI generation, MCP server, webhooks
@xnetjs/telemetry Privacy-preserving telemetry, tiered consent, k-anonymity, scrubbing
@xnetjs/formula Expression parser, AST evaluator, built-in function library
@xnetjs/vectors HNSW vector index, semantic search, hybrid keyword+semantic search

Apps

App Tech Description
Electron Electron + Vite + React + TanStack Router + Tailwind Desktop (macOS/Windows/Linux)
Web Vite + React + TanStack Router + Workbox PWA Browser progressive web app
Expo Expo SDK 52 + React Native + React Navigation Mobile (iOS/Android)

Architecture

flowchart TB
    subgraph Apps["Applications"]
        Electron["Electron<br/>(Desktop)"]
        Web["Web PWA"]
        Expo["Expo<br/>(Mobile)"]
    end

    subgraph UI["UI Layer"]
        Editor["@xnetjs/editor<br/><small>TipTap, slash commands,<br/>drag-drop, mermaid</small>"]
        Views["@xnetjs/views<br/><small>Table, Board, Calendar,<br/>Timeline, Gallery</small>"]
        Canvas["@xnetjs/canvas<br/><small>Infinite canvas,<br/>R-tree, ELK.js</small>"]
        UILib["@xnetjs/ui<br/><small>Radix primitives,<br/>theme system</small>"]
    end

    subgraph Client["Client Layer"]
        React["@xnetjs/react<br/><small>useQuery, useMutate,<br/>useNode, SyncManager</small>"]
        SDK["@xnetjs/sdk<br/><small>Unified client,<br/>browser/node presets</small>"]
        Devtools["@xnetjs/devtools<br/><small>9-panel debug suite</small>"]
        Plugins["@xnetjs/plugins<br/><small>Registry, sandbox,<br/>AI generation, MCP</small>"]
        Telemetry["@xnetjs/telemetry<br/><small>Privacy-first,<br/>consent-gated</small>"]
        History["@xnetjs/history<br/><small>Time machine,<br/>undo/redo, audit</small>"]
    end

    subgraph Data["Data Layer"]
        DataPkg["@xnetjs/data<br/><small>Schema system, NodeStore,<br/>Yjs CRDT, 15 property types</small>"]
        Query["@xnetjs/query<br/><small>Local engine,<br/>MiniSearch FTS</small>"]
        Vectors["@xnetjs/vectors<br/><small>HNSW index,<br/>hybrid search</small>"]
        Formula["@xnetjs/formula<br/><small>Expression parser,<br/>computed properties</small>"]
    end

    subgraph Infra["Infrastructure Layer"]
        Sync["@xnetjs/sync<br/><small>Change&lt;T&gt;, Lamport clocks,<br/>hash chains, Yjs security</small>"]
        Storage["@xnetjs/storage<br/><small>SQLite, blobs,<br/>snapshots</small>"]
        Network["@xnetjs/network<br/><small>libp2p, y-webrtc,<br/>peer scoring</small>"]
    end

    subgraph Foundation["Foundation"]
        Identity["@xnetjs/identity<br/><small>DID:key, UCAN tokens,<br/>passkey storage</small>"]
        Crypto["@xnetjs/crypto<br/><small>BLAKE3, Ed25519,<br/>XChaCha20</small>"]
        Core["@xnetjs/core<br/><small>CIDs, types,<br/>permissions, RBAC</small>"]
    end

    Apps --> UI & Client
    UI --> Client
    Client --> Data
    Data --> Infra
    Infra --> Foundation

    subgraph Server["Server"]
        Hub["@xnetjs/hub<br/><small>Signaling, sync relay,<br/>backup, FTS5, federation</small>"]
    end

    Network <--> Hub
Loading

Hybrid Sync Model

flowchart LR
    subgraph Local["Local Device"]
        UI["UI"]
        NodeStore["NodeStore<br/>(structured data)"]
        YDoc["Y.Doc<br/>(rich text)"]
        DB[("SQLite")]
    end

    subgraph Remote["Remote Peers"]
        Peer1["Peer<br/>(desktop)"]
        Peer2["Peer<br/>(mobile)"]
        HubNode["Hub<br/>(always-on)"]
    end

    UI -->|"mutate()"| NodeStore
    UI -->|"edit"| YDoc
    NodeStore -->|"Change&lt;T&gt;<br/>LWW"| DB
    YDoc -->|"Yjs updates<br/>CRDT"| DB

    Local <-->|"WebRTC / WebSocket"| Remote
Loading

Data Model

Everything is a Node (universal container). A Schema defines what the Node is.

import { defineSchema, text, number, select } from '@xnetjs/data'

const InvoiceSchema = defineSchema({
  name: 'Invoice',
  namespace: 'xnet://myapp/',
  document: 'yjs',
  properties: {
    title: text({ required: true }),
    amount: number(),
    status: select({
      options: [
        { id: 'draft', name: 'Draft' },
        { id: 'sent', name: 'Sent' },
        { id: 'paid', name: 'Paid' }
      ] as const
    })
  }
})

Sync Strategies

Data Type Sync Mechanism Conflict Resolution
Rich text (documents) Yjs CRDT Character-level merge
Structured data (nodes) NodeStore + Lamport Field-level LWW

Identity, Roles, and Authorization

xNet schemas can include an authorization block that maps identity (DID) to roles and actions.

  • Identity: Every node has createdBy: did:key:...
  • Roles: Resolved from creator, person properties, or related nodes
  • Actions: Canonical actions are read, write, delete, share, admin
  • Delegation: Grants (UCAN-backed) allow secure permission delegation
const ProjectDocSchema = defineSchema({
  name: 'ProjectDoc',
  namespace: 'xnet://myapp/',
  document: 'yjs',
  properties: {
    title: text({ required: true }),
    owner: person(),
    editors: person(),
    project: relation({ schema: 'xnet://myapp/Project@1.0.0' })
  },
  authorization: {
    roles: {
      owner: role.creator(),
      editor: role.property('editors'),
      projectAdmin: role.relation('project', 'admin')
    },
    actions: {
      read: allow('owner', 'editor', 'projectAdmin'),
      write: allow('owner', 'editor', 'projectAdmin'),
      delete: allow('owner', 'projectAdmin'),
      share: allow('owner', 'projectAdmin'),
      admin: allow('projectAdmin')
    },
    publicProps: ['title']
  }
})

Authorization builders (allow, role, etc.) come from the data auth module and compile to schema-level policy metadata.

Primary React Hooks

import { useQuery, useMutate, useNode, useIdentity, useCan, useGrants } from '@xnetjs/react'

// Structured data
function TaskList() {
  const { data: tasks, loading } = useQuery(TaskSchema)
  const { create, update, remove } = useMutate()

  return (
    <ul>
      {tasks.map((task) => (
        <li key={task.id}>{task.title}</li>
      ))}
      <button onClick={() => create(TaskSchema, { title: 'New', status: 'todo' })}>Add</button>
    </ul>
  )
}

// Rich text with Yjs CRDT
function PageEditor({ nodeId }: { nodeId: string }) {
  const { data: page, doc, syncStatus, peerCount } = useNode(PageSchema, nodeId)
  if (!doc) return null
  return <RichTextEditor ydoc={doc} />
}

// Identity + permissions
function SharingPanel({ nodeId }: { nodeId: string }) {
  const { did } = useIdentity()
  const { allowed: canShare } = useCan(nodeId, 'share')
  const { grant } = useGrants(nodeId)

  return (
    <button
      disabled={!canShare}
      onClick={() =>
        canShare && grant({ to: 'did:key:z6MkRecipient...', actions: ['read', 'write'] })
      }
    >
      Share as {did.slice(0, 16)}...
    </button>
  )
}

Hook Quick Reference

Hook Use for
useQuery Read lists/single nodes with realtime updates
useMutate Create/update/delete/transactional writes
useNode Rich text nodes (Y.Doc), sync status, presence
useIdentity Current DID identity context
useCan Check action permissions on a node
useCanEdit Quick editable state for UI gating
useGrants Grant, revoke, and inspect delegated access

Key Technologies

Layer Technology
Sync Event-sourced immutable logs, Lamport clocks, LWW
CRDT Yjs (conflict-free collaboration)
P2P libp2p + WebRTC
Storage SQLite (OPFS in browser, native on desktop/mobile)
Identity DID:key + UCAN authorization
Signing Ed25519 (via @noble/curves)
Hashing BLAKE3 (via @noble/hashes)
Encryption XChaCha20-Poly1305
Search MiniSearch (local), FTS5 (hub)
Build Turborepo, tsup, Vite
Testing Vitest, Playwright (browser mode)

Roadmap Status (Mar 2026)

Phase Focus Status
Phase 1 Product reliability (navigation, search, daily-driver polish) In progress
Phase 2 Collaboration + trust (invites, sharing UX, presence reliability) Next
Phase 3 Platform clarity (package lifecycle, API simplification, multi-hub integration) Planned

See docs/ROADMAP.md for the detailed execution plan.

Documentation

  • Site -- Astro + Starlight documentation website
  • Vision -- The big picture: micro-to-macro data sovereignty
  • Tradeoffs -- Why hybrid sync (Yjs + event sourcing)
  • Roadmap -- current 6-month execution plan (Mar-Sep 2026)

License

MIT

About

Local-first infrastructure and app for user-owned data: offline-first sync, CRDT collaboration, typed schemas, and secure identity/permissions

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

  •  

Packages

 
 
 

Contributors