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

react-native-krds-game-sdk

v0.1.1

Published

React Native SDK for embedding KRDS web games inside client applications.

Readme

react-native-krds-game-sdk

React Native SDK for embedding KRDS web games inside client applications.

React Native Client
       ↓
react-native-krds-game-sdk
       ↓
KrdsGameView
       ↓
react-native-webview
       ↓
Web Content

1. Overview

KrdsGameView renders KRDS web content inside a React Native application and takes care of everything a host application would otherwise have to reimplement:

  • loads a URL in a WebView with JavaScript and DOM storage enabled,
  • shows a loading indicator until the content is ready,
  • turns native WebView failures into one typed GameWebViewError shape,
  • carries structured messages between the web game and React Native,
  • keeps callbacks referentially stable so parent re-renders do not restart the WebView.

The SDK deliberately contains no game logic. It is a transport and rendering layer, which is what allows game IDs, configuration, authentication and native modules to be added later without changing the public API. See Architecture in the development guide for the planned phases.

Licensing — this is commercial software. Use in production requires a valid KRDS subscription; see LICENSE.

2. Requirements

| Requirement | Version | | -------------------- | -------------------------------- | | React Native | >= 0.71 (New Architecture ready) | | React | >= 18 | | react-native-webview | >= 13 |

react, react-native and react-native-webview are peer dependencies. They are provided by the client application and are never bundled into this package — bundling them would create duplicate copies of React or of the native WebView module at runtime.

3. Installation

npm install react-native-krds-game-sdk react-native-webview
yarn add react-native-krds-game-sdk react-native-webview

For Expo projects, install the WebView version matched to your SDK release:

npx expo install react-native-webview

4. iOS setup

react-native-webview contains native code, so the pods have to be installed:

cd ios && pod install

No changes are required for https:// content. Two cases need extra configuration:

Loading plain http:// URLs (local development servers) — App Transport Security blocks them. Add an exception to ios/<App>/Info.plist, scoped as narrowly as possible:

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>localhost</key>
    <dict>
      <key>NSExceptionAllowsInsecureHTTPLoads</key>
      <true/>
    </dict>
  </dict>
</dict>

Games that use the camera or microphone — declare the usage descriptions the platform requires, otherwise the application is terminated when the permission is requested:

<key>NSCameraUsageDescription</key>
<string>Used by games that require the camera.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Used by games that require the microphone.</string>

5. Android setup

Autolinking wires up the WebView, so there is nothing to register manually.

Confirm the internet permission is present in android/app/src/main/AndroidManifest.xml (it is part of the default React Native template):

<uses-permission android:name="android.permission.INTERNET" />

To load plain http:// URLs during development, enable cleartext traffic on the <application> element — preferably only in the debug manifest:

<application android:usesCleartextTraffic="true" ... >

react-native-webview requires minSdkVersion 24 or higher, which is the React Native default.

Jest setup in the client application

This SDK resolves to its CommonJS build under Jest, so it needs no configuration. Its peer dependency react-native-webview does: it publishes untranspiled ES modules and reaches for its native module at import time. Any test that renders a screen containing KrdsGameView therefore needs both of these in the client application.

// jest.config.js
module.exports = {
  preset: '@react-native/jest-preset',
  setupFiles: ['<rootDir>/jest.setup.js'],
  transformIgnorePatterns: [
    'node_modules/(?!((jest-)?react-native|@react-native(-community)?|react-native-webview)/)',
  ],
};
// jest.setup.js
jest.mock('react-native-webview', () => {
  const React = require('react');
  const { View } = require('react-native');

  const WebView = React.forwardRef((props, ref) => {
    React.useImperativeHandle(ref, () => ({
      reload: jest.fn(),
      injectJavaScript: jest.fn(),
      postMessage: jest.fn(),
      stopLoading: jest.fn(),
    }));

    return React.createElement(View, { testID: 'mock-webview', ...props });
  });

  return { __esModule: true, WebView, default: WebView };
});

With the WebView mocked, the SDK's callbacks can be driven directly in tests:

const webView = renderer.root.findByProps({ testID: 'mock-webview' });

act(() => {
  webView.props.onMessage({
    nativeEvent: { data: JSON.stringify({ type: 'GAME_STARTED' }) },
  });
});

6. Basic usage

import { KrdsGameView } from 'react-native-krds-game-sdk';
import type { GameMessage, GameWebViewError } from 'react-native-krds-game-sdk';
import { StyleSheet, View } from 'react-native';

export function GameScreen() {
  return (
    <View style={styles.container}>
      <KrdsGameView
        url="https://example.com"
        onLoad={() => {
          console.log('Game loaded');
        }}
        onError={(error: GameWebViewError) => {
          console.log('Game error', error.code, error.message);
        }}
        onMessage={(message: GameMessage) => {
          console.log('Game message', message.type, message.data);
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1 },
});

KrdsGameView fills its parent (flex: 1). Give it a sized container, or pass style.

Imperative API

import { useRef } from 'react';
import { KrdsGameView } from 'react-native-krds-game-sdk';
import type { KrdsGameViewRef } from 'react-native-krds-game-sdk';

const gameRef = useRef<KrdsGameViewRef>(null);

gameRef.current?.reload();
gameRef.current?.postMessage({ type: 'PAUSE_GAME' });

<KrdsGameView ref={gameRef} url="https://example.com" />;

7. Props

| Prop | Type | Default | Description | | ----------------------- | ----------------------------------- | ---------- | -------------------------------------------------------------------- | | url | string | required | Absolute http(s) URL of the web content. | | onLoad | () => void | — | Content finished loading successfully. | | onLoadStart | () => void | — | A navigation started, including reloads. | | onLoadEnd | () => void | — | A navigation ended, successfully or not. | | onError | (error: GameWebViewError) => void | — | A normalized error occurred. | | onMessage | (message: GameMessage) => void | — | A well-formed message arrived from the web content. | | style | StyleProp<ViewStyle> | flex: 1 | Style of the container view. | | showsLoadingIndicator | boolean | true | Show the built-in loading indicator. | | loadingIndicatorColor | string | platform | Color of the built-in indicator. | | renderLoading | () => ReactElement \| null | — | Replaces the built-in indicator with a custom loading state. | | javaScriptEnabled | boolean | true | Enable JavaScript in the web content. | | domStorageEnabled | boolean | true | Enable localStorage / sessionStorage. | | webViewProps | KrdsGameWebViewProps | — | Escape hatch forwarded to react-native-webview (see caveat below). | | testID | string | — | Test identifier on the container view. |

Applied to the WebView by default, overridable through webViewProps: allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true.

webViewProps couples your code to react-native-webview's own API rather than to the SDK's contract. Props the SDK owns (source, the loading/error/message handlers, the injected bridge script) are removed from its type, because overriding them would break loading state, error reporting or messaging. Prefer the dedicated props above; treat webViewProps as temporary until the SDK exposes a first-class prop for what you need.

Ref

| Method | Description | | ---------------------- | ----------------------------------------- | | reload() | Reloads the current URL. | | postMessage(message) | Sends a GameMessage to the web content. |

8. Events and callbacks

Loading a URL produces this sequence:

onLoadStart  →  (loading indicator visible)  →  onLoad  →  onLoadEnd
onLoadStart  →  onError                                 →  onLoadEnd
  • onLoadEnd fires for both outcomes; use it to dismiss your own progress UI.
  • onError may fire without ending the load — an HTTP error on a sub-resource, or a malformed message, is reported while the view stays usable. Branch on error.isFatal.
  • All callbacks are optional. Passing inline arrow functions is fine: they are internally stabilized, so a parent re-render never rebuilds the WebView handlers.

Game lifecycle events (GAME_STARTED, GAME_COMPLETED, …) are not callbacks — they arrive as messages through onMessage. The vocabulary is published as GAME_EVENTS:

import { GAME_EVENTS } from 'react-native-krds-game-sdk';
import type { GameMessage, GameResult } from 'react-native-krds-game-sdk';

const handleMessage = (message: GameMessage) => {
  switch (message.type) {
    case GAME_EVENTS.GAME_STARTED:
      analytics.track('game_started');
      break;
    case GAME_EVENTS.GAME_COMPLETED: {
      const result = message.data as GameResult;
      grantReward(result.reward);
      break;
    }
    default:
      // Unknown types are forwarded as-is, so new web events do not require an app update.
      break;
  }
};

9. Web ↔ React Native messaging

The SDK injects window.KrdsGameBridge into the page before its own scripts run. Games use that object instead of window.ReactNativeWebView directly, so the transport can change later — to a native module, for example — without the games being rewritten.

Web → React Native

window.KrdsGameBridge.postMessage({
  type: 'GAME_COMPLETED',
  data: { score: 100, reward: 50 },
});

Every message must be a JSON object with a non-empty type string. data is optional and entirely defined by the game. Well-formed messages reach onMessage; anything else is reported through onError as a non-fatal MESSAGE_PARSE_FAILED.

A page that has not been updated for the bridge can still use the underlying transport directly:

window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'GAME_STARTED' }));

React Native → web

gameRef.current?.postMessage({ type: 'PAUSE_GAME', data: { reason: 'app_backgrounded' } });

The page receives it either through a listener:

const unsubscribe = window.KrdsGameBridge.addMessageListener((message) => {
  if (message.type === 'PAUSE_GAME') {
    pause();
  }
});

or as a DOM event:

window.addEventListener('krds:message', (event) => {
  console.log(event.detail.type, event.detail.data);
});

Typing payloads

GameMessage.data is unknown because the payload belongs to the game, not to the SDK. Narrow it in your own code:

const handleMessage = (message: GameMessage<GameResult>) => {
  console.log(message.data?.score);
};

10. Error handling

Every failure is normalized into GameWebViewError, so client applications never touch react-native-webview internals:

interface GameWebViewError {
  code: GameErrorCode;
  message: string; // for logs — do not parse
  url?: string;
  statusCode?: number;
  isFatal: boolean;
}

| Code | Cause | isFatal | | ---------------------- | ---------------------------------------------- | --------- | | INVALID_URL | url is not an absolute http(s) URL | true | | WEBVIEW_LOAD_FAILED | Offline, DNS, TLS or timeout failure | true | | WEBVIEW_HTTP_ERROR | Server responded 4xx/5xx (statusCode is set) | true | | WEBVIEW_TERMINATED | Web content process crashed or was reclaimed | true | | MESSAGE_PARSE_FAILED | Message was not JSON, or had no type string | false |

Branch on code, never on message. Messages are for logs and may be reworded in any release.

import { GAME_ERROR_CODES } from 'react-native-krds-game-sdk';

const handleError = (error: GameWebViewError) => {
  if (!error.isFatal) {
    logger.warn('KRDS game warning', error);
    return;
  }

  if (error.code === GAME_ERROR_CODES.WEBVIEW_TERMINATED) {
    gameRef.current?.reload();
    return;
  }

  showRetryScreen(error);
};

Development

Building, testing or publishing this SDK itself — not just using it — see DEVELOPMENT.md.

License

Commercial. See LICENSE.