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

ecsdk-ios-expo

v0.3.1

Published

Expo module for ECSDK-iOS (ELERTS See Say Now SDK)

Readme

ecsdk-ios-expo

Expo module for ECSDK-iOS (ELERTS "See Say Now" SDK) - Complete security and incident reporting solution for React Native apps.

npm version

License: MIT

📋 Table of Contents


✨ Features

  • Client Registration - Register users with the ECSDK system
  • User Login/Logout - Manage user sessions with saved tokens
  • Profile Management - Update user information
  • Organization Management - Join and manage organizations
  • Report Submission - Submit incident reports with photos and location
  • Message Center - View alerts and notifications
  • Background Fetch - Automatic data synchronization
  • TypeScript Support - Full type definitions
  • Config Plugin - Automated native configuration

Platform Support: iOS 15.1+ and tvOS 15.1+


📦 Installation

npm install ecsdk-ios-expo

# or

yarn add ecsdk-ios-expo

Note: The ECSDK-iOS library (ELERTSKit) is automatically included via Swift Package Manager. You don't need to add it manually.


⚡ Setup

The config plugin automatically configures all native iOS files including SPM framework integration. No manual native code editing required!

Step 1: Add Plugin to Config

app.config.js or app.config.ts:

export default {
  expo: {
    name: "My App",
    plugins: [
      [
        "ecsdk-ios-expo",
        {
          // Required: ELERTSKit API key
          apiKey: process.env.EXPO_PUBLIC_ECSDK_API_KEY,
          // Optional: Product key (short name for your app without spaces)
          // If not provided, can be set via EXPO_PUBLIC_ECSDK_PRODUCT_KEY or Info.plist
          productKey: "MyApp",
        },
      ],
    ],
    ios: {
      bundleIdentifier: "com.yourcompany.yourapp",
    },
  },
};

The config plugin automatically:

  • ✅ Adds ELERTSKitCore and ELERTSKitUI frameworks via SPM
  • ✅ Configures framework search paths
  • ✅ Sets up framework embedding
  • ✅ Injects initialization code into AppDelegate's willFinishLaunchingWithOptions
  • ✅ Sets up background fetch manager
  • ✅ Injects background fetch handler for store and forward functionality
  • ✅ Configures API key and product key

Step 2: Set Up GitHub Authentication

The ELERTSKit-iOS library is hosted on GitHub. Set environment variables for GitHub authentication.

For local development:

export GPR_USER=your-github-username
export GPR_API_KEY=your-personal-access-token

For EAS Build, add to eas.json:

{
  "build": {
    "production": {
      "env": {
        "GPR_USER": "your-github-username",
        "GPR_API_KEY": "your-token"
      }
    }
  }
}

Note: You need access to the ELERTS GitHub repository. Contact ELERTS support for access.

Step 3: Build and Run

npx expo prebuild --clean
npx expo run:ios

Done! The config plugin handles everything. Skip to API Reference to start using the SDK.


📱 Quick Start Summary

  1. Install package: npm install ecsdk-ios-expo
  2. Add config plugin to app.config.js with API key and product key
  3. Set GitHub credentials for ELERTSKit library access
  4. Run: npx expo prebuild --clean && npx expo run:ios
  5. Register client and join organization
  6. Start using ECSDK features!

Note: SDK initialization is handled automatically by the config plugin in AppDelegate. No manual initialization code needed!


📖 API Reference

Import

import EcsdkIosExpo, { Organization, UserProfile } from "ecsdk-ios-expo";

Initialization

Note: SDK initialization is handled automatically by the config plugin. The plugin injects initialization code into AppDelegate's willFinishLaunchingWithOptions, which:

  • Initializes ELERTSKit with your API key
  • Sets up background fetch manager
  • Configures product key

No manual initialization code is required in your app!

Background Fetch: The config plugin also automatically injects the background fetch handler into AppDelegate to enable store and forward functionality when there is poor connectivity. This is handled automatically - no additional code needed!


Client Management

createClient(profile)

Register a new client with the ECSDK system. Must be called before using other features.

Parameters:

{
  firstName: string;
  lastName: string;
  email: string;
  phone: string;
  otherFields?: Record<string, any>; // Optional additional fields
}

Returns: Promise<string> - The client token (save this to your backend!)

Example:

const clientToken = await EcsdkIosExpo.createClient({
  firstName: "John",
  lastName: "Doe",
  email: "[email protected]",
  phone: "+1234567890",
});

// IMPORTANT: Save this token!
console.log("Token:", clientToken);

updateClientInfo(profile)

Update the client's profile information.

Parameters:

{
  firstName: string;
  lastName: string;
  email: string;
  phone: string;
  otherFields?: Record<string, any>;
}

Returns: Promise<boolean>

Example:

await EcsdkIosExpo.updateClientInfo({
  firstName: "Jane",
  lastName: "Smith",
  email: "[email protected]",
  phone: "+1987654321",
});

User Login/Logout Management

Important for apps with user login systems: If your app has user authentication, you must save the ELERTS client token on your server with each user's data. When a user logs back in, retrieve their token and restore their ELERTS session.

login(clientToken)

Login a user with their saved ELERTS client token. Call this when a user logs into your app to restore their ELERTS session.

Parameters:

  • clientToken: string - The ELERTS client token retrieved from your server

Returns: void

Example:

// Typical login flow:
async function handleUserLogin(username, password) {
  // 1. Authenticate user with your backend
  const user = await yourAuthAPI.login(username, password);
  
  // 2. Retrieve the ELERTS token saved for this user
  const elertsToken = user.elertsClientToken;
  
  // 3. Login to ELERTS
  EcsdkIosExpo.login(elertsToken);
  
  // User can now submit reports and receive messages
}

Important Notes:

  • The ELERTS token should be saved to your server when the user first registers with createClient()
  • Upon login, retrieve this token from your server and pass it to login()
  • If you want to allow non-logged-in users to send reports, use an ELERTS webform instead

logout()

Logout the current user and clear their ELERTS session. Call this when a user logs out of your app.

Returns: void

Example:

async function handleUserLogout() {
  // Clear ELERTS session
  EcsdkIosExpo.logout();
  
  // Then clear your app's session
  await yourAuthAPI.logout();
}

Note: After logout, the user will not be able to submit reports or receive ELERTS messages until they log back in.


getClientToken()

Get the current ELERTS client token. Returns null if no user is logged in.

Returns: string | null

Example:

const token = EcsdkIosExpo.getClientToken();

if (token) {
  console.log("User is logged in to ELERTS");
  // Optionally save token to your server if not already saved
  await saveTokenToServer(currentUserId, token);
} else {
  console.log("No user logged in to ELERTS");
}

Use Cases:

  • Check if a user is currently logged in
  • Retrieve the token to save to your server
  • Verify login/logout operations

Complete Login Flow Example

import EcsdkIosExpo from "ecsdk-ios-expo";

// First-time registration
async function registerNewUser(userData) {
  // 1. Register with ECSDK
  const clientToken = await EcsdkIosExpo.createClient({
    firstName: userData.firstName,
    lastName: userData.lastName,
    email: userData.email,
    phone: userData.phone,
  });
  
  // 2. Save the ELERTS token to your server
  await yourAPI.saveUserData({
    userId: userData.userId,
    elertsClientToken: clientToken, // IMPORTANT!
    ...userData
  });
  
  // User is now registered and logged in
}

// Returning user login
async function loginExistingUser(username, password) {
  // 1. Authenticate with your backend
  const user = await yourAPI.login(username, password);
  
  // 2. Retrieve the saved ELERTS token
  const elertsToken = user.elertsClientToken;
  
  // 3. Login to ELERTS
  if (elertsToken) {
    EcsdkIosExpo.login(elertsToken);
    console.log("Logged in to ELERTS");
  } else {
    console.warn("No ELERTS token found for user");
  }
}

// User logout
async function logoutUser() {
  // 1. Logout from ELERTS
  EcsdkIosExpo.logout();
  
  // 2. Clear your app's session
  await yourAPI.logout();
  
  console.log("User logged out");
}

Organization Management

listOrganizations(joined)

Get list of organizations. Returns joined organizations or available organizations based on the parameter.

Parameters:

  • joined: boolean - If true, returns joined organizations; if false, returns available organizations

Returns: Promise<Organization[]>

Example:

// Get available organizations
const availableOrgs = await EcsdkIosExpo.listOrganizations(false);
availableOrgs.forEach((org) => {
  console.log(`${org.name} (ID: ${org.organizationId})`);
  console.log(`  Description: ${org.description}`);
});

// Get joined organizations
const joinedOrgs = await EcsdkIosExpo.listOrganizations(true);
console.log(`User has joined ${joinedOrgs.length} organizations`);

joinOrganization(organizationId)

Join an organization. The first organization joined will be set as active.

Parameters:

  • organizationId: number - The organization ID to join

Returns: Promise<boolean>

Example:

const orgs = await EcsdkIosExpo.listOrganizations(false);

if (orgs.length > 0) {
  await EcsdkIosExpo.joinOrganization(orgs[0].organizationId);
  console.log(`Joined ${orgs[0].name}`);
}

setActiveOrganization(organizationId)

Set which organization is currently active.

Parameters:

  • organizationId: number - The organization ID

Returns: void

Example:

await EcsdkIosExpo.setActiveOrganization(12345);

getActiveOrganization()

Get the currently active organization.

Returns: Organization | { organizationId: 0, name: "", description: "" }

Returns an object with organizationId: 0 if no active organization is set.

Example:

const activeOrg = EcsdkIosExpo.getActiveOrganization();

if (activeOrg.organizationId !== 0) {
  console.log("Active:", activeOrg.name);
  console.log("Description:", activeOrg.description);
} else {
  console.log("No active organization");
}

getAvailableOrganizations()

Get list of available organizations (synchronous, returns cached data).

Returns: Organization[]

Example:

const orgs = EcsdkIosExpo.getAvailableOrganizations();
console.log(`Found ${orgs.length} available organizations`);

getSelectedOrganizations()

Get selected organizations from user profile (synchronous, returns cached data).

Returns: Organization[]

Example:

const selectedOrgs = EcsdkIosExpo.getSelectedOrganizations();
console.log(`User has selected ${selectedOrgs.length} organizations`);

TypeScript Types

interface UserProfile {
  firstName: string;
  lastName: string;
  email: string;
  phone: string;
  otherFields?: Record<string, any>;
}

interface Organization {
  organizationId: number;
  name: string;
  description: string;
}

💡 Complete Example

import React, { useEffect, useState } from "react";
import { View, Button, Alert, Text } from "react-native";
import EcsdkIosExpo, { Organization, UserProfile } from "ecsdk-ios-expo";

export default function App() {
  const [isRegistered, setIsRegistered] = useState(false);
  const [activeOrg, setActiveOrg] = useState<Organization | null>(null);
  const [initialized, setInitialized] = useState(false);

  useEffect(() => {
    initializeECSDK();
  }, []);

  async function initializeECSDK() {
    try {
      // SDK is automatically initialized by the config plugin in AppDelegate
      // Try to access the SDK to verify it's ready
      const token = EcsdkIosExpo.getClientToken();
      setInitialized(true); // SDK is ready (initialized in AppDelegate)

      // Check if user is already registered
      if (token) {
        setIsRegistered(true);
        // Refresh organization data
        await refreshOrganizationData();
      }
    } catch (error: any) {
      // Even if there's an error, SDK should be initialized in AppDelegate
      setInitialized(true);
      Alert.alert("Initialization Error", error.message);
      console.error("Init error:", error);
    }
  }

  async function refreshOrganizationData() {
    const activeOrg = EcsdkIosExpo.getActiveOrganization();
    if (activeOrg.organizationId !== 0) {
      setActiveOrg(activeOrg);
    }
  }

  async function handleRegister() {
    if (!initialized) {
      Alert.alert("Error", "Please wait for SDK initialization");
      return;
    }

    try {
      // Register client
      const clientToken = await EcsdkIosExpo.createClient({
        firstName: "John",
        lastName: "Doe",
        email: "[email protected]",
        phone: "+1234567890",
      });

      // Save the token to your backend!
      console.log("Client Token:", clientToken);
      setIsRegistered(true);

      // Update profile
      await EcsdkIosExpo.updateClientInfo({
        firstName: "John",
        lastName: "Doe",
        email: "[email protected]",
        phone: "+1234567890",
      });

      // Get and join organization
      const organizations = await EcsdkIosExpo.listOrganizations(false);

      if (organizations.length > 0) {
        // Join first organization
        await EcsdkIosExpo.joinOrganization(organizations[0].organizationId);
        EcsdkIosExpo.setActiveOrganization(organizations[0].organizationId);

        // Get active organization
        const org = EcsdkIosExpo.getActiveOrganization();
        setActiveOrg(org);

        Alert.alert("Success", `Ready to use ECSDK with ${org.name}`);
      } else {
        Alert.alert("Error", "No organizations available. Check your API key.");
      }
    } catch (error: any) {
      Alert.alert("Registration Error", error.message);
      console.error("Registration error:", error);
    }
  }

  return (
    <View style={{ flex: 1, justifyContent: "center", padding: 20 }}>
      <Text style={{ marginBottom: 20, textAlign: "center" }}>
        ECSDK iOS Example
      </Text>

      {!isRegistered && (
        <Button
          title="Register Client"
          onPress={handleRegister}
          disabled={!initialized}
        />
      )}

      {isRegistered && (
        <>
          <Text style={{ marginBottom: 10 }}>
            Status: Registered
          </Text>
          {activeOrg && activeOrg.organizationId !== 0 && (
            <Text style={{ marginBottom: 10 }}>
              Active Org: {activeOrg.name}
            </Text>
          )}
        </>
      )}
    </View>
  );
}

🐛 Troubleshooting

Build fails with "Could not resolve ELERTSKit"

Solution: Check GitHub authentication. The ELERTSKit-iOS library requires GitHub authentication to access the private repository.

  1. Verify environment variables:

    echo $GPR_USER
    echo $GPR_API_KEY
  2. For EAS Build, add to eas.json:

    {
      "build": {
        "production": {
          "env": {
            "GPR_USER": "your-github-username",
            "GPR_API_KEY": "your-token"
          }
        }
      }
    }
  3. Contact ELERTS support if you don't have access to the repository


"Unable to resolve host" or Network errors

Solution:

  1. Clean and rebuild:

    cd ios
    pod deintegrate
    pod install
    cd ..
    npx expo run:ios
  2. Check internet connection: SPM requires internet access to download packages

  3. Test on physical device: Network issues are sometimes simulator-specific


"No active organization" error

Solution: Join an organization first

const orgs = await EcsdkIosExpo.listOrganizations(false);
if (orgs.length > 0) {
  await EcsdkIosExpo.joinOrganization(orgs[0].organizationId);
  EcsdkIosExpo.setActiveOrganization(orgs[0].organizationId);
}

App crashes on startup

Solution: Verify SDK is configured correctly in plugin options

// In app.config.ts, make sure you have:
plugins: [
  [
    "ecsdk-ios-expo",
    {
      apiKey: process.env.EXPO_PUBLIC_ECSDK_API_KEY, // Required
      productKey: "YourProductKey", // Optional
    },
  ],
],

The SDK is automatically initialized in AppDelegate by the config plugin. No manual initialization code needed!


Config plugin not applying changes

Solution:

npx expo prebuild --clean
cd ios
pod install
cd ..
npx expo run:ios

SPM framework not found errors

Solution: The config plugin should handle this automatically, but if you see framework errors:

  1. Clean build folder:

    cd ios
    xcodebuild clean -workspace YourApp.xcworkspace -scheme YourApp
  2. Re-run prebuild:

    npx expo prebuild --clean
  3. Verify Podfile has post_install block with SPM framework code (added by config plugin)


TypeScript errors

Solution: Make sure you're importing types correctly

import EcsdkIosExpo, { Organization, UserProfile } from "ecsdk-ios-expo";

"No client token available" error

Solution: Make sure you've registered a client or logged in with a saved token

// Register new client
const token = await EcsdkIosExpo.createClient({...});

// Or login with saved token
EcsdkIosExpo.login(savedToken);

📄 License

MIT

🤝 Support

  • SDK Issues: Contact ELERTS support
  • Module Issues: GitHub Issues
  • API Key: Contact ELERTS to get your API key

🙏 Credits

  • ECSDK-iOS SDK (ELERTSKit) by ELERTS
  • Built with Expo Modules
  • Created for the React Native community

Version: 0.1.0
Made for the React Native community 🚀