npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xnetjs/data

v0.0.2

Published

Schema system, NodeStore, and Yjs CRDT engine for xNet. This is the central data package -- it defines how structured data and rich text documents are created, stored, and synced.

Readme

@xnetjs/data

Schema system, NodeStore, and Yjs CRDT engine for xNet. This is the central data package -- it defines how structured data and rich text documents are created, stored, and synced.

Installation

pnpm add @xnetjs/data

Features

  • Schema system -- defineSchema() with 16 typed property helpers
  • NodeStore -- Event-sourced LWW (Last-Writer-Wins) storage engine
  • Built-in schemas -- Page, Database, Task, Canvas, Comment
  • Yjs CRDT -- Y.Doc helpers for signed updates and merge/state-vector workflows
  • Awareness/presence -- Real-time user presence
  • Blob service -- File upload/download with content addressing
  • Storage adapters -- SQLite and in-memory NodeStore adapters
  • Temp ID mapping -- Optimistic creates with server-assigned IDs

Usage

Define a Schema

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

const TaskSchema = defineSchema({
  name: 'Task',
  namespace: 'myapp://',
  document: 'yjs', // Enable rich text body
  properties: {
    title: text({ required: true }),
    priority: number(),
    done: checkbox(),
    dueDate: date(),
    status: select({
      options: [
        { id: 'todo', name: 'To Do' },
        { id: 'in-progress', name: 'In Progress' },
        { id: 'done', name: 'Done' }
      ] as const
    }),
    assignee: relation({ schema: 'myapp://Person' })
  }
})

Property Helpers

| Type | Import | Description | | ------------- | --------------- | --------------------------- | | text | text() | String values | | number | number() | Numeric values | | checkbox | checkbox() | Boolean toggle | | date | date() | Single date | | dateRange | dateRange() | Start + end date | | select | select() | Single choice | | multiSelect | multiSelect() | Multiple choices | | person | person() | DID reference | | relation | relation() | Link to another node | | url | url() | URL string | | email | email() | Email address | | phone | phone() | Phone number | | file | file() | File attachment | | created | created() | Auto-set creation timestamp | | updated | updated() | Auto-set update timestamp | | createdBy | createdBy() | Auto-set author DID |

NodeStore

import { NodeStore, MemoryNodeStorageAdapter } from '@xnetjs/data'

const store = new NodeStore({
  storage: new MemoryNodeStorageAdapter(),
  authorDID: identity.did,
  signingKey: privateKey
})

// Create
const task = await store.create(TaskSchema, { title: 'Buy milk', status: 'todo' })

// Read
const loaded = await store.get(TaskSchema, task.id)

// Update
await store.update(TaskSchema, task.id, { status: 'done' })

// List
const tasks = await store.list(TaskSchema)

// Delete (soft)
await store.remove(task.id)

Yjs Documents

import { YDoc, captureUpdate, applySignedUpdate, signUpdate, mergeDocuments } from '@xnetjs/data'

const authorDID = identity.did
const signingKey = keyBundle.signingKey

const docA = new YDoc()
const docB = new YDoc()

// Edit rich text content
docA.getText('content').insert(0, 'Hello world')

// Capture and sign update bytes
const update = captureUpdate(docA)
const signed = signUpdate(update, { authorDID, signingKey })

// Verify/apply to another replica
applySignedUpdate(docB, signed)

// Merge full state from one doc into another
mergeDocuments(docA, docB)

Architecture

flowchart TD
    Schema["defineSchema()<br/><small>16 property helpers</small>"]
    Store["NodeStore<br/><small>Event-sourced LWW</small>"]
    Doc["Yjs Documents<br/><small>CRDT rich text</small>"]
    Blob["BlobService<br/><small>File attachments</small>"]
    Builtin["Built-in Schemas<br/><small>Page, Database, Task,<br/>Canvas, Comment</small>"]

    Schema --> Store
    Schema --> Builtin
    Store --> Doc
    Store --> Blob
    Builtin --> Store

    subgraph Adapters["Storage Adapters"]
        SQLite["SQLite<br/>Adapter"]
        Mem["Memory<br/>Adapter"]
    end

    Store --> Adapters

Storage Adapters

| Adapter | Platform | Description | | -------------------------- | -------- | -------------------------------------- | | SQLiteNodeStorageAdapter | All | Primary adapter using @xnetjs/sqlite | | MemoryNodeStorageAdapter | All | In-memory storage for testing |

Recommended: Use SQLiteNodeStorageAdapter with the appropriate @xnetjs/sqlite adapter for your platform:

import { NodeStore, SQLiteNodeStorageAdapter } from '@xnetjs/data'
import { ElectronSQLiteAdapter } from '@xnetjs/sqlite/electron' // or /web, /expo

const sqliteAdapter = new ElectronSQLiteAdapter()
await sqliteAdapter.open({ path: 'xnet.db' })

const storage = new SQLiteNodeStorageAdapter(sqliteAdapter)
await storage.open()

const store = new NodeStore({
  storage,
  authorDID: identity.did,
  signingKey: privateKey
})

Telemetry Integration

NodeStore supports optional telemetry for tracking CRUD operations, performance, and errors:

import { NodeStore } from '@xnetjs/data'
import { TelemetryCollector, ConsentManager } from '@xnetjs/telemetry'

const consent = new ConsentManager()
const telemetry = new TelemetryCollector({ consent })

const store = new NodeStore({
  storage,
  authorDID: identity.did,
  signingKey: privateKey,
  telemetry // <-- Add telemetry collector
})

When telemetry is enabled, NodeStore automatically reports:

  • Performance metrics: data.create, data.update, data.delete, data.list, data.applyRemoteChange
  • Usage metrics: Operation counts
  • Security events: Hash/signature verification failures, unauthorized remote changes
  • Crash reports: Errors with context

All telemetry respects user consent settings and privacy buckets (no exact values, no PII).

Modules

| Module | Description | | ------------------------- | -------------------------------------- | | schema/define.ts | defineSchema() factory | | schema/node.ts | FlatNode type (flattened properties) | | schema/registry.ts | Schema registry | | store/store.ts | NodeStore engine | | store/sqlite-adapter.ts | SQLite NodeStore adapter (recommended) | | store/memory-adapter.ts | In-memory NodeStore adapter | | store/tempids.ts | Temp ID mapping for optimistic creates | | updates.ts | Signed update and merge utilities | | blob/blob-service.ts | File blob storage | | sync/awareness.ts | Presence awareness | | blocks/registry.ts | Block type registry |

Dependencies

  • @xnetjs/core, @xnetjs/crypto, @xnetjs/identity, @xnetjs/storage, @xnetjs/sync, @xnetjs/sqlite
  • yjs, y-protocols -- CRDT engine
  • nanoid -- ID generation

Testing

pnpm --filter @xnetjs/data test

10 test files covering schema system, NodeStore, comments, and blob service.