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 🙏

© 2025 – Pkg Stats / Ryan Hefner

intervengine-rn-sdk

v0.4.0

Published

Intervengine Mobile SDK for React Native - provides integration with Intervengine services using Kotlin Multiplatform shared library

Downloads

831

Readme

Intervengine React Native SDK

React Native wrapper for the Intervengine Mobile SDK, built with Expo Modules and Kotlin Multiplatform (KMP).

Overview

This SDK provides a React Native interface to the Intervengine platform, enabling mobile apps to:

  • Authenticate users and manage sessions
  • Listen to real-time updates via Server-Sent Events (SSE)
  • Manage user context and state
  • Fetch and display embeddable cards
  • Fetch contents

Architecture

The SDK consists of three main layers:

SDK Architecture Diagram

How It Works

  1. TypeScript SDK (IntervengineSdk.ts): High-level API that React Native apps use
  2. Native Modules: Platform-specific bridge code (Swift for iOS, Kotlin for Android)
  3. KMP Shared Library: Cross-platform business logic written in Kotlin

The native modules use Expo Modules API, which provides:

  • Automatic type conversion between native and JavaScript
  • Promise-based async functions
  • Event emitters for native to JavaScript communication
  • No need to write JSI/JNI code manually

Installation

NPM Install:

npm install intervengine-rn-sdk

Usage

Basic Setup

// SDK Config
export type SDKConfig = {
  apiUrl: string; // Intervengine API URL
  apiKey: string; // Intervegine API key
  appId: string; // Intervengine application connector ID
  appSecret: string; // Intervengine application connector secret
  userType: UserType; // 'external' or 'participant'
  userId: string; // user identifier
  enableLogging?: boolean;
};
import { IntervengineSdk } from 'intervengine-rn-sdk';

// Initialize the SDK with a sdkConfig object
const sdk = await IntervengineSdk.initialize({
  apiUrl: 'https://your-api-url.com',
  apiKey: 'your-api-key',
  appId: 'your-app-id',
  appSecret: 'your-app-secret',
  userType: 'external|participant',
  enableLogging: true,
});

// Start listening for server events
await sdk.start();

Listening to Auth State Changes

import { useEffect, useState } from 'react';

function MyComponent() {
  const [authState, setAuthState] = useState('loading');

  useEffect(() => {
    if (!sdk) return;

    // Get current auth state
    sdk.getCurrentAuthState().then((state) => {
      setAuthState(state.state);
    });

    // Listen for auth state changes
    const subscription = sdk.addAuthStateListener((state) => {
      console.log('Auth state:', state.state);
      console.log('Access token:', state.accessToken);
      setAuthState(state.state);
    });

    return () => subscription.remove();
  }, [sdk]);

  return <Text>Auth State: {authState}</Text>;
}

Fetching Cards

// Card search parameters
type CardSearchParam = {
  healthAreaId?: string; // Filter by health area ID
  fromDate?: string;  // ISO 8601 date string, default value: today
  toDate?: string;  // ISO 8601 date string, default value: today
  page?: number; // default value: 1
  perPage?: number; // default value: 10
  isActive?: boolean; // default value: true
  isOneOff?: boolean; // default value: null
  isReported?: boolean; // default value: null
};
// Fetch embeddable cards with search param
const cards = await sdk.getEmbeddableCards({
    healthAreaId: 'health-area-123', // Optional: filter by health area
    fromDate: '2025-11-11',
    toDate: '2025-11-11',
    page: 1,
    perPage: 20,
    isActive: true,
});

cards.forEach(card => {
  console.log('Card:', card.title, card.url);
  if (card.healthArea) {
    console.log('Health Area:', card.healthArea.healthAreaName);
  }
});

Listening to Card Updates

useEffect(() => {
  if (!sdk) return;

  const subscription = sdk.addCardsUpdateListener((update) => {
    console.log('New cards received:', update.newCards);
    // Refresh your cards list
  });

  return () => subscription.remove();
}, [sdk]);

Getting User Context

const context = await sdk.getUserContext();
console.log('User ID:', context.userId);
console.log('Access Token:', context.accessToken);

Complete Example

import React, { useEffect, useState } from 'react';
import { View, Text, FlatList } from 'react-native';
import { IntervengineSdk } from 'intervengine-rn-sdk';

function App() {
  const [sdk, setSdk] = useState(null);
  const [authState, setAuthState] = useState('loading');
  const [cards, setCards] = useState([]);

  useEffect(() => {
    // Initialize SDK
    IntervengineSdk.initialize({
      apiUrl: 'https://api.example.com',
      apiKey: 'your-key',
      appId: 'your-app-id',
      appSecret: 'your-secret',
    }).then(async (sdkInstance) => {
      setSdk(sdkInstance);

      // Start listening for events
      await sdkInstance.start();

      // Fetch initial cards
      const initialCards = await sdkInstance.getEmbeddableCards({
        page: 1,
        perPage: 20,
        isActive: true
      });
      setCards(initialCards);
    });
  }, []);

  useEffect(() => {
    if (!sdk) return;

    // Listen for auth state changes
    const authSub = sdk.addAuthStateListener((state) => {
      setAuthState(state.state);
    });

    // Listen for new cards
    const cardsSub = sdk.addCardsUpdateListener(async () => {
      const updatedCards = await sdk.getEmbeddableCards({
        page: 1,
        perPage: 20,
        isActive: true
      });
      setCards(updatedCards);
    });

    return () => {
      authSub.remove();
      cardsSub.remove();
    };
  }, [sdk]);

  return (
    <View>
      <Text>Status: {authState}</Text>
      <FlatList
        data={cards}
        renderItem={({ item }) => (
          <View>
            <Text>{item.title}</Text>
            <Text>{item.descriptionText}</Text>
          </View>
        )}
        keyExtractor={(item) => item.id}
      />
    </View>
  );
}

API Reference

IntervengineSdk.initialize(config)

Initialize the SDK with configuration.

Parameters:

  • config.apiUrl: API endpoint URL
  • config.apiKey: API key
  • config.appId: Application ID
  • config.appSecret: Application secret
  • config.initialPageSize: Initial page size for cards (default: 10)
  • config.enableLogging: Enable debug logging (default: false)

Returns: Promise<IntervengineSdk>

sdk.start()

Start listening for Server-Sent Events (SSE). The userType and userId are provided during SDK initialization.

Returns: Promise<void>

sdk.stop()

Stop listening for SSE events.

Returns: Promise<void>

sdk.signOut()

Sign out and clear SDK state.

Returns: Promise<void>

sdk.getEmbeddableCards(cardSearchParam?)

Fetch embeddable cards with optional search parameters.

Parameters:

  • cardSearchParam: Optional CardSearchParam object with filters:
    • healthAreaId: Filter by health area ID
    • fromDate: Start date (ISO 8601 format, default: today)
    • toDate: End date (ISO 8601 format, default: today)
    • page: Page number (default: 1)
    • perPage: Items per page (default: 10)
    • isActive: Filter by active status (default: true)
    • isOneOff: Filter by one-off cards
    • isReported: Filter by reported status

Returns: Promise<EmbeddableCard[]>

sdk.getUserContext()

Get current user context.

Returns: Promise<{ userId: string, accessToken: string }>

sdk.getCurrentAuthState()

Get current authentication state.

Returns: Promise<AuthStatePayload>

sdk.addAuthStateListener(callback)

Listen for authentication state changes.

Parameters:

  • callback: (state: AuthStatePayload) => void

Returns: { remove: () => void }

sdk.addCardsUpdateListener(callback)

Listen for card updates.

Parameters:

  • callback: (update: CardsUpdatePayload) => void

Returns: { remove: () => void }

sdk.searchContents(params)

Search for contents with various filters.

Parameters:

  • params: ContentSearchParam object with filters:
    • keyword: Search keyword
    • contentTypeId: Filter by content type ID
    • title: Filter by title
    • tagIds: Filter by tag IDs (array)
    • groupIds: Filter by group IDs (array)
    • isExternal: Filter by external content
    • isActive: Filter by active status

Returns: Promise<SearchResult<Content>>

sdk.getContent(contentId)

Get a specific content by ID.

Parameters:

  • contentId: Content ID (string)

Returns: Promise<Content>

Types

AuthStatePayload

type AuthStatePayload = {
  state: 'authenticated' | 'unauthenticated' | 'loading' | 'error';
  accessToken?: string;  // Present when state is 'authenticated'
  error?: string;        // Present when state is 'error'
}

EmbeddableCard

type EmbeddableCard = {
  id: string;
  url: string;
  activityPlanType: string;
  title: string;
  descriptionText?: string;
  imageUrl?: string;
  isOneOff: boolean;
  scheduledAt: string;
  reportedAt?: string;
  data: CardData | null;
  associatedJourney: AssociatedJourney | null;
  healthArea: HealthArea | null;
}

CardsUpdatePayload

type CardsUpdatePayload = {
  newCards: EmbeddableCard[];
}

HealthArea

type HealthArea = {
  id: string;
  healthAreaCode: string;
  healthAreaName: string;
  descriptionText?: string;
}

AssociatedJourney

type AssociatedJourney = {
  id: string;
  name: string;
}

CardData

type CardData = {
  id: string;
  activityPlanType: string;
  activityValues: ActivityValue[];
}

ActivityValue

type ActivityValue = {
  id: string;
  measureTypeId: string;
  measureTypeName: string;
  measureDataType: string;
  measureTypeOptions: MeasureTypeOption[];
  reportedValue: string;
}

MeasureTypeOption

type MeasureTypeOption = {
  id: string;
  label: string;
  descriptionText?: string;
  score?: number;
}

ContentSearchParam

type ContentSearchParam = {
  keyword?: string;
  contentTypeId?: string;
  title?: string;
  tagIds?: string[];
  groupIds?: string[];
  isExternal?: boolean;
  isActive?: boolean;
}

SearchResult<T>

type SearchResult<T> = {
  results: T[];
  total: number;
}

Content

type Content = {
  id: string;
  uuid?: string;
  publishedVersionId?: string;
  currentVersionId?: string;
  contentTypeId: string;
  contentType?: ContentType;
  externalReference?: string;
  title: string;
  body?: ContentPage[] | null;
  descriptionText?: string;
  tagIds: string[];
  tags: ContentTag[];
  groupIds: string[];
  groups: ContentGroup[];
  uiConfigs?: Record<string, any> | null;
  isActive: boolean;
  createdAt: string;
  createdBy: string;
  updatedAt: string;
  updatedBy: string;
}

ContentType

type ContentType = {
  id: string;
  contentTypeCode: string;
  contentTypeName: string;
  contentTypeDescription?: string;
  isActive: boolean;
  createdAt: string;
  createdBy: string;
  updatedAt: string;
  updatedBy: string;
}

ContentPage

type ContentPage = {
  id: string;
  contentId: string;
  title: string;
  descriptionText?: string;
  contentElements: ContentElement[];
  uiConfigs?: Record<string, any> | null;
  displayOrder: number;
}

ContentElement

type ContentElement = {
  id: string;
  assetId?: string;
  asset?: Asset;
  text?: string;
  displayOrder: number;
}

ContentTag

type ContentTag = {
  id: string;
  tagCode: string;
  tagName: string;
  tagTypeId?: string;
  tagType?: TagType;
}

ContentGroup

type ContentGroup = {
  id: string;
  groupType: string;
  groupCode: string;
  groupName: string;
}

TagType

type TagType = {
  id: string;
  tagTypeCode: string;
  tagTypeName: string;
  description?: string;
}

Asset

type Asset = {
  id: string;
  uuid?: string;
  assetMimeType: string;
  assetName: string;
  resourceName: string;
  resourceType: string;
  resourceURL: string;
  resourceThumbnailURL?: string;
  resourceSize: number;
  tagIds: string[];
  isActive: boolean;
  createdAt: string;
  createdBy: string;
  updatedAt: string;
  updatedBy: string;
}

TODO

  • Add more functions that wraps Intervengine Application API API Reference
  • Support for Content Library, Message Inbox, Enrolled Journeys
  • Support Basic UI components

Running the Example

cd example
npm install
npm run ios     # Run on iOS
npm run android # Run on Android

License

MIT