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

silosdk

v0.0.10

Published

Silo SDK provides local-first persistence primitives for Expo apps. It owns local storage and returns TanStack-compatible option objects instead of wrapping TanStack hooks.

Readme

Silo SDK

Silo SDK provides local-first persistence primitives for Expo apps. It owns local storage and returns TanStack-compatible option objects instead of wrapping TanStack hooks.

Silo owns:

  • local platform persistence
  • flat primitive document constraints
  • defaults-first source shape
  • settings storage
  • media file ownership and resolution
  • ID generation through expo-crypto

TanStack owns:

  • createCollection() and live collection queries
  • useQuery() and useMutation()
  • query and mutation state

Install

yarn add silosdk @tanstack/react-db @tanstack/react-query expo-crypto expo-sqlite expo-file-system

Native apps use Expo SQLite, Expo FileSystem, and Expo SQLite KV storage. Web builds use IndexedDB for stores, settings, and media blobs through browser export entrypoints, so the web bundle does not need to load the native SQLite or filesystem storage modules.

Stores

Stores define locally persisted document collections and a link collection for relationships between them. Native storage uses SQLite; web storage uses IndexedDB. Stores produce options for TanStack DB collections.

import { createCollection } from '@tanstack/react-db'
import { createID, createStore } from 'silosdk/store'

type Post = {
  title: string
  body: string
  published: boolean
  coverImage: string | null
}

type Tag = {
  name: string
}

export const store = createStore<{
  posts: Post
  tags: Tag
}>({
  posts: {
    title: '',
    body: '',
    published: false,
    coverImage: null,
  },
  tags: {
    name: '',
  },
})

export const posts = createCollection(store.collectionOptions('posts'))
export const tags = createCollection(store.collectionOptions('tags'))
export const links = createCollection(store.linkCollectionOptions())

Query and mutate with TanStack DB directly:

import { eq, useLiveQuery } from '@tanstack/react-db'

const { data: docs = [] } = useLiveQuery((q) =>
  q.from({ posts }).where(({ posts }) => eq(posts.published, true)),
)

const doc = docs[0]
const post = doc?.data()

doc?.id
post?.title
const id = createID()

const tx = posts.insert({
  id,
  data: {
    title: 'Hello',
    body: '',
    published: false,
    coverImage: null,
  },
})

await tx.isPersisted.promise

await posts.update(id, (doc) => {
  doc.set({ published: true })
}).isPersisted.promise

await posts.delete(id).isPersisted.promise

Source rows are intentionally flat. Field values must be:

type FieldValue = string | number | boolean | null

Create links with the link collection utilities:

await links.utils.link('posts', postId, 'tags', tagId)
await links.utils.unlink('posts', postId, 'tags', tagId)

const isLinked = links.utils.has('posts', postId, 'tags', tagId)

Link storage is flat and directionless. Collection names are sorted lexicographically and IDs are stored in the same order. Query rows expose nested paths for each collection pair:

import { eq, useLiveQuery } from '@tanstack/react-db'

const { data: taggedPosts = [] } = useLiveQuery((q) =>
  q
    .from({ posts })
    .join({ links }, ({ posts, links }) =>
      eq(posts.id, links.tags.posts.id),
    )
    .join({ tags }, ({ links, tags }) =>
      eq(links.posts.tags.id, tags.id),
    ),
)

For a posts to tags link:

links.tags.posts.id // post id
links.posts.tags.id // tag id

Same-collection links are not supported. Define another collection when you need a different semantic relationship.

Sources

The lower-level source() API remains available from silosdk/store when you only need one collection definition.

Settings

Settings are small persisted primitive values. Native storage uses expo-sqlite/kv-store; web storage uses IndexedDB. Settings produce TanStack Query options.

import { setting } from 'silosdk/settings'

export const theme = setting<'system' | 'light' | 'dark'>('theme', 'system')
export const reduceMotion = setting('reduceMotion', false)
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'

const queryClient = useQueryClient()
const { data: value } = useQuery(theme.queryOptions())
const setTheme = useMutation(theme.mutationOptions({ queryClient }))

setTheme.mutate('dark')
setTheme.mutate((current) => (current === 'dark' ? 'light' : 'dark'))

Setting values must also be flat primitives:

type SettingValue = string | number | boolean | null

Media

Media is singleton infrastructure for app-owned files. Domain documents store stable media refs as plain strings, keeping source rows flat.

Native media imports copy files into Silo-owned document storage and persist the mapping in SQLite. Web media imports store metadata and blobs in IndexedDB and resolve refs to cached blob: URLs.

import { media, type MediaRef } from 'silosdk/media'

Import a file with TanStack Query mutation options:

import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'

const queryClient = useQueryClient()
const importMedia = useMutation(media.mutationOptions({ queryClient }))

const coverImage = await importMedia.mutateAsync({
  uri: pickedFile.uri,
  kind: 'image',
  name: pickedFile.name,
  mimeType: pickedFile.type,
})

Store the returned media://... ref in source rows:

posts.update(postId, (draft) => {
  draft.set({ coverImage })
})

Resolve a media ref to a local file URI:

const { data: uri } = useQuery(media.queryOptions(post.coverImage))

media.queryOptions() returns string | null. It returns null when the ref is empty, invalid, unknown, or missing on disk.

Delete a media ref when your app no longer stores it:

const deleteMedia = useMutation(media.deleteMutationOptions({ queryClient }))

await deleteMedia.mutateAsync(coverImage)

Deletion removes Silo's copied file and media mapping only. Remove the ref from your own source rows or settings separately. Invalid or unknown refs are safe and return false.

API Shape

Silo exposes definition objects and option factories:

createCollection(store.collectionOptions('posts'))
createCollection(store.linkCollectionOptions())
useQuery(theme.queryOptions())
useMutation(theme.mutationOptions({ queryClient }))
useQuery(media.queryOptions(ref))
useMutation(media.mutationOptions({ queryClient }))
useMutation(media.deleteMutationOptions({ queryClient }))

There is no Silo provider and no Silo hook wrapper API.