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

@zally-sdk/sdk-react-native

v1.7.0

Published

React Native SDK for zally – one npm package that wraps the native iOS and Android zally SDKs

Readme

@zally-sdk/sdk-react-native

React Native SDK for zally — wraps the native iOS and Android SDKs behind a single JavaScript API.

Requirements

  • React Native >= 0.80
  • iOS 17.0+
  • Android: minSdk 23, compileSdk 36, Java 17, AndroidX, Kotlin 2.2 or later

The React Native floor is set by Android, not by this package's JavaScript. com.zally:zally-sdk depends on androidx.core:core-ktx:1.18.0, which requires the consuming app to compile against API 36 with Android Gradle plugin 8.9.1 or newer. React Native 0.80 is the first release whose template ships an AGP that new: 0.79 ships 8.8.2, 0.78 ships 8.8.0, 0.77 ships 8.7.2, 0.76 ships 8.6.0.

Raising AGP yourself on an older React Native does not work either. AGP 8.9.1 needs Gradle 8.11 or newer, and React Native's own Gradle plugin compiles with -Werror on those releases, so it fails on Gradle's deprecation warnings before your app is reached.

Installation

npm install @zally-sdk/sdk-react-native
# or
yarn add @zally-sdk/sdk-react-native

iOS

Expo managed projects — add the plugin in app.json:

{
  "expo": {
    "plugins": ["@zally-sdk/sdk-react-native"]
  }
}

Then run npx expo prebuild or npx expo run:ios.

Bare React Native — set your deployment target to iOS 17.0, add the zally pod to your Podfile:

pod 'zally-sdk', :podspec => 'https://raw.githubusercontent.com/zally-ltd/zally-ios-sdk-package/3.1.0/zally-sdk.podspec'

Then cd ios && pod install && cd ...

Native iOS version resolution

The native iOS version is pinned, and ZallySdk.podspec holds the pin. The Expo config plugin reads that pin at prebuild time and writes the Podfile line above, so Expo and bare React Native resolve the same native version from the same wrapper version. Upgrading the native SDK therefore takes a release of this package, the same as on Android.

The plugin previously pointed at the public podspec on its default branch, which carried whatever version was current at pod install time. That let one wrapper version resolve two different native versions, put an iOS SDK publish into Expo apps without a React Native release, and made the public podspec a shared recovery surface for anyone rolling back.

The Podfile line carries a tag ref, and that ref is the pin: it fixes what the URL resolves to. No version requirement sits alongside it, because CocoaPods rejects a dependency that has both an external :podspec source and a version requirement, failing pod install before resolution starts.

Moving the pin means editing s.dependency 'zally-sdk' in ZallySdk.podspec and the Podfile line above, then releasing this package. A unit test fails if the two disagree, and the version check in main-build.yml fails if the pin trails the latest published iOS SDK tag.

Upgrading from 1.6.6 or earlier (Expo): no manual action. Run npx expo prebuild (or npx expo run:ios) and pod install as usual. The plugin replaces its own generated block in ios/Podfile, so a Podfile carried over from an earlier prebuild picks up the pinned line, and the changed podspec URL makes CocoaPods re-resolve Podfile.lock. Bare React Native apps should replace the pod line in their Podfile with the one above. If the version you were resolving from the default branch had moved ahead of the pin, this moves you back to the pinned version.

The plugin can only replace a generated block whose two @generated marker comments are both intact. If the markers were edited or partly deleted, it appends a fresh block and leaves the old pod line in place, and pod install then fails reporting a conflicting external source for zally-sdk. Delete the old zally block from ios/Podfile and run pod install again.

Android

No extra setup — the native dependency is resolved automatically.

Usage

import zally from '@zally-sdk/sdk-react-native';

// 1. Initialize (call once after user login)
await zally.initialize({
  appUUID: 'your-app-uuid',
  // Called by the SDK, not once by this library: immediately during initialize,
  // and again whenever the SDK needs to recover its own tokens. Fetch a current
  // JWT on every call. Returning a captured or cached one leaves the SDK unable
  // to recover after it expires.
  getClientToken: async () => {
    return await yourBackend.getZallyToken();
  },
});

// 2. Start
await zally.start();

// 3. Check state
const state = await zally.getUserState();
console.log(state?.trainingState, state?.zIdStatus, state?.isUser);

// 4. Stop (e.g. on logout)
await zally.stop();

API

| Method | Returns | Description | | --------------------------------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | initialize({ appUUID, getClientToken, baseUrl? }) | Promise<void> | Initialize and authorize the SDK. Call once after user login. getClientToken is called by the SDK repeatedly, not once: see below. baseUrl requires the internal edition: see below. | | start() | Promise<void> | Start sensor data collection and streaming. Call after initialize(). | | stop() | Promise<void> | Stop the SDK (e.g. on user logout). | | isInitialized() | Promise<boolean> | Whether the SDK reports itself initialized. Platform-dependent: see below. | | isRunning() | Promise<boolean> | Whether the SDK is actively collecting data. Authoritative on iOS only: see below. | | getUserState() | Promise<UserState \| null> | Current user state (training progress, identity verification). Maps to Android userState / iOS BiometricState. |

getClientToken is called more than once

The native SDKs take a token-supplying function and re-invoke it: once when authorizing, and again whenever they need to recover their own tokens, for example after a refresh token expires. This library passes your function through to them rather than resolving it to a string.

So getClientToken must return a currently valid JWT every time it is called. A common mistake is to close over a token fetched at login:

// Wrong: the SDK can never obtain a fresh token, so it cannot recover.
const token = await yourBackend.getZallyToken();
await zally.initialize({ appUUID, getClientToken: async () => token });

// Right: fetch on demand.
await zally.initialize({ appUUID, getClientToken: () => yourBackend.getZallyToken() });

Each request is bounded by a 30 second timeout. If your function has not returned by then, the SDK is told no token is available and authorization fails rather than hanging. Returning null, returning an empty string, or throwing all report "no token" to the SDK, and each logs a warning to the console: the SDK's own error says only "Invalid token", which does not point at a failing endpoint.

The wrapper version is reported at authorization

initialize() puts this package's version on the native bridge as wrapperVersion, a string | null field on the options object the JavaScript layer passes to the native module. Without it, token exchange sees only the native iOS or Android SDK underneath this wrapper, so the SDK version support table cannot tell a React Native consumer from a direct native integrator.

The version is read from this package's package.json and held nowhere else, so the version reported and the version published cannot drift.

The wire contract this establishes:

  • wrapperVersion is a semantic version string, prereleases included, or null
  • the native bridges forward it to the native SDK, which reports it to token exchange alongside the platform and native SDK version it already sends
  • where both a native range and a React Native range match the same session, the React Native range is applied. A session reporting a wrapper version is a React Native consumer, so a native version marked unsupported for a reason unrelated to React Native does not halt it

Both bridges read wrapperVersion and log it, but cannot yet forward it: ZallySDK.initialize takes (context, appId) on Android and appUUID on iOS, and neither native SDK exposes a wrapper-version API. The forwarding, and the support table changes behind it, land with the native SDK work. Sending the field first fixes the contract both sides build against, and logging it at the bridge means a support request can identify a React Native consumer today rather than waiting for that work.

src/__tests__/nativeContract.test.ts asserts that every key in InitializeOptions is at least named by both native bridges. Nothing else can: there is no codegen here, keys are matched by string at runtime, and both sides compile perfectly while a value nobody reads is dropped on the floor.

Reporting is fail open at every step. A version that cannot be read or does not parse is sent as null and logs a warning to the console. Authorization proceeds exactly as it would have without one, and an unrecognised or absent version is never a reason to refuse a session.

isInitialized and isRunning differ by platform

Both reflect what each native SDK exposes, which is not the same thing.

isInitialized() is true on iOS only once authorization has succeeded. On Android it is true once initialize() completes, which happens before authorization. Do not treat it as "ready to authenticate" on Android.

isRunning() is authoritative on iOS, where the SDK reports sensors and authorization together. The Android SDK exposes no running state, so this reflects whether start() last succeeded and will not notice the SDK stopping on its own. Never treat it as proof that data is flowing.

UserState

{
  trainingState: string; // "UNTRAINED" | "TRAINING" | "TRAINED"
  zIdStatus: string; // "UNKNOWN" | "USER" | "IMPOSTER" | "INACTIVE"
  isUser: boolean; // true if verified as the legitimate user
  isImposter: boolean; // true if potential imposter detected (Android: zIdStatus.IMPOSTER; iOS: derived from server response)
}

Internal edition

This package talks to production and nothing else. zally's own apps that need the dev stack use the internal edition, which adds an optional baseUrl to initialize:

await zally.initialize({
  appUUID,
  getClientToken,
  baseUrl: 'https://coreapi-dev.zally-services.com/',
});

On the public package that rejects with E_UNSUPPORTED_EDITION. The base URL is stripped from the public native builds on both platforms deliberately, so this is a build-time edition rather than a runtime switch. Turning it on means zallySdkEdition=internal on Android and ZALLY_INTERNAL_EDITION=1 on iOS, and both platforms must be switched. See docs/internal-edition.md.

Releasing

Releasing is two dispatches with a hold point between them. See docs/release-process.md.

License

Apache-2.0