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

expo-rollup

v0.3.2

Published

Rollup SDK for Expo and React Native: on-device camera roll index, search, query and profile (iOS).

Readme

expo-rollup

The Rollup SDK for Expo and React Native apps. Rollup indexes the person's camera roll on their iPhone, so your app can search it on the device and ask about their life (query, profile). Photos never leave the iPhone.

This module is a thin wrapper over the native Rollup SDK for iOS: the Swift SDK does the indexing and search, and the module passes calls and results across the bridge as JSON. Documentation: https://docs.tryrollup.com/platforms/expo

Requirements

  • iOS only. On Android and the web every call rejects with code unsupportedPlatform, so cross-platform apps still build and run.
  • An iPhone with iOS 26 or later for Rollup to run. Your app can support iOS 16.0 and later: below iOS 26, isAvailable is false and every call rejects with unsupportedPlatform. The Simulator is not supported: configure rejects with simulatorUnsupported. Development builds on a device work (they attest in Apple's development App Attest environment, which Rollup accepts).
  • A development build (npx expo run:ios --device, or EAS Build). Expo Go does not include this module.
  • An approved app in the Rollup developer dashboard (https://www.tryrollup.com/developers), with your Team ID and bundle ID, and its publishable key (rk_live_...).

Install

npx expo install expo-rollup

Add the config plugin to app.json (or app.config.js):

{
  "expo": {
    "ios": { "bundleIdentifier": "com.example.app" },
    "plugins": [
      ["expo-rollup", { "photosPermission": "Your photos help personalize the app. They stay on your iPhone." }]
    ]
  }
}

Then generate the native project and build: npx expo prebuild --platform ios and npx expo run:ios --device.

The plugin sets everything the SDK needs:

  • NSPhotoLibraryUsageDescription (the photosPermission option).
  • BGTaskSchedulerPermittedIdentifiers with <bundle ID>.rollup.indexing.* and <bundle ID>.rollup.update, and UIBackgroundModes with processing.
  • The App Attest entitlement (com.apple.developer.devicecheck.appattest-environment).
  • An iOS deployment target of at least 16.0 (a higher one is kept).
  • pod 'Rollup', :podspec => '...' in the Podfile: the Rollup binary is not on CocoaPods trunk, so the app's Podfile names its podspec. The version and URL come from this package's rollup-sdk.json.

The module registers Rollup's background task at launch on its own.

| Option | Default | Meaning | | --- | --- | --- | | photosPermission | A short default text | The Photos permission text. Say why your app reads the person's photos. | | appAttestEnvironment | "production" | "development" or "production". Rollup accepts both. | | rollupPodspec | From rollup-sdk.json | Where CocoaPods gets the Rollup pod. |

Bare React Native

Set up Expo Modules (npx install-expo-modules@latest), install the package (npm install expo-rollup), then make the changes above by hand: the Info.plist entries, the App Attest capability, an iOS deployment target of 16.0 or later, and this line in your Podfile's app target, after use_expo_modules!:

pod 'Rollup', :podspec => 'https://raw.githubusercontent.com/tryrollup/rollup-ios-sdk/0.2.0/Rollup.podspec'

Use

import * as Rollup from 'expo-rollup';

// Once, when your app starts. Every option left out keeps the SDK's default (the last three months, growing).
await Rollup.configure('rk_live_...', {
  window: Rollup.indexWindow.growing(Rollup.span.months(3)),
});

// From a screen where the person has just chosen to turn the feature on: a grant starts the first index.
const access = await Rollup.requestPhotoAccess();

// The indexing state, kept current (downloadingAssets, preparing, indexing, ready, unfinished, paused, failed, ...).
const state = Rollup.useIndexingState();

if (Rollup.isSearchable(state)) {
  const results = await Rollup.search('ramen in Tokyo last spring');
  const answer = await Rollup.query('Where do I eat most?');
  const profile = await Rollup.profile({
    type: 'object',
    properties: { favorite_cuisine: { type: 'string', description: 'The cuisine they eat most often' } },
  });
}

// The index's largest groups (labels, kinds of place, cuisines, food) with counts and sample photos, in one call.
const groups = await Rollup.facets({ limit: 16, samples: 4 });

// Each batch of photos a run makes searchable, as it does: add them to the screen instead of searching again.
const subscription = Rollup.addIndexedBatchListener((batch) => console.log(batch.items.length, batch.indexed, batch.total));

// Start over without downloading the models again (reset() deletes them too). Then startIndexing() builds a new index.
await Rollup.deleteIndex();

Calls reject with a RollupError: a stable code (the Swift SDK's codes, plus unsupportedPlatform and invalidOptions), a message for developers, and for errors from Rollup's server the serverCode, retryable and retryAfter.

try {
  await Rollup.query('Where do I eat most?');
} catch (error) {
  if (Rollup.isRollupError(error, 'quotaExceeded')) {
    // The app's monthly budget is used up until the date in error.message.
  }
}

Search results identify photos by their PhotoKit local identifier (result.id). Show them with expo-media-library, or a ph:// URI in React Native's Image.

Privacy and App Review

search runs on the iPhone. query and profile send text the index derived from the person's photos (dates, places, labels, text read in photos) to Rollup's server and its model provider. Before your app calls them, tell the person and get their permission: App Store Review Guideline 5.1.2(i) requires it for personal data shared with third-party AI. See https://docs.tryrollup.com/guides/privacy