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

@geekapps/silo-react-native

v0.3.0

Published

Silo SDK for React Native / Expo — typed client + React hooks

Readme

@geekapps/silo-react-native

Silo SDK for React Native and Expo apps — typed client + React hooks. Works in both Expo (managed) and bare React Native projects; it has no dependency on either.

Install

bun add @geekapps/silo-react-native

Auth: token is always required, fetched from your backend

A mobile app's bundle can always be extracted from a public build. Because of that, this SDK never generates or stores a Silo service account credential itself — there is no serviceAccount option, and SiloClient holds no token internally. Every authenticated call takes an explicit, required token argument.

Your own backend — the one place a service account secret is safe to live — should hold the Silo service account credentials and expose an endpoint that mints a short-lived token for your app to fetch:

async function getSiloToken(): Promise<string> {
  const res = await fetch("https://your-backend.com/silo-token", {
    headers: { Authorization: `Bearer ${yourAppSessionToken}` }, // however your backend authenticates the app
  });
  const { token } = await res.json();
  return token;
}

That backend endpoint, in turn, calls Silo's own service-account token endpoint server-side (see @geekapps/silo-nextjs's ServiceAccountTokenProvider for a reference implementation) and returns just the short-lived token to the app — the secret itself never leaves your server.

Setup

<SiloProvider> only configures where to reach Silo — no credentials:

import { SiloProvider } from "@geekapps/silo-react-native";

export default function App() {
  return (
    <SiloProvider baseUrl="https://api.silo.geekapps.com.br">
      {/* ... */}
    </SiloProvider>
  );
}

Usage

import { useUpload } from "@geekapps/silo-react-native";
import * as ImagePicker from "expo-image-picker";

function UploadButton() {
  const { state, upload } = useUpload({ bucket: "avatars" });

  async function pickAndUpload() {
    const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: "images" });
    if (result.canceled) return;
    const asset = result.assets[0];

    const token = await getSiloToken();
    await upload(
      {
        uri: asset.uri,
        name: asset.fileName ?? "photo.jpg",
        type: asset.mimeType ?? "image/jpeg",
        size: asset.fileSize,
      },
      token
    );
  }

  return (
    <Button onPress={pickAndUpload} title={state.status === "uploading" ? `${state.progress}%` : "Upload"} />
  );
}

Or without hooks, using the client directly:

import { SiloClient } from "@geekapps/silo-react-native";

const silo = new SiloClient({ baseUrl: "https://api.silo.geekapps.com.br" });

const token = await getSiloToken();
const result = await silo.upload({ uri, name: "video.mp4", type: "video/mp4", size }, token);
const playbackUrl = await silo.getHlsStreamUrl(result.id, token);

Hooks

Every hook that touches an authenticated endpoint takes token as an explicit argument (usually right after the resource id) — there's no implicit/ambient auth.

  • useUpload() → upload(file, token, opts?) — single-file upload with progress
  • useBatchUpload() → upload(files, token, opts?) — upload multiple files at once
  • useSignedUrl(fileId, token, opts?) — presigned download URL for a file
  • useFileStatus(fileId, token, opts?) — poll a file's processing status until it's ready/failed
  • useDeleteFile() → deleteFile(fileId, token) — delete a file
  • useThumbnailUrl(fileId, token, screenW?) / useStoryboardUrl(...) / useHlsStreamUrl(fileId, token) — media URLs for a file
  • useSiloClient() — the raw SiloClient instance from context, for anything not covered by a hook

Large file / true multipart uploads

React Native has no File.slice() equivalent, so this SDK's upload() and useUpload/useBatchUpload send each file as a single part — that's fine for images and most videos recorded on-device. For very large files where you want real chunked/resumable multipart upload, read and slice the file yourself (e.g. with expo-file-system's base64 reading, or react-native-blob-util) and drive the primitives directly:

const { fileId, uploadId } = await silo.startMultipartUpload({ fileName, mimeType, size, bucket }, token);
for (const chunk of yourChunks) {
  const { url } = await silo.getUploadPartUrl(fileId, uploadId, partNumber, token);
  await silo.uploadPart(url, chunk, mimeType); // part URLs are presigned — no token needed here
}
await silo.completeMultipartUpload(fileId, uploadId, parts, token);