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

@sira-screen-share/support-react-native

v0.0.8

Published

Sira screen-share-with-annotation support SDK for React Native and Expo apps.

Downloads

935

Readme

@sira-screen-share/support-react-native

Sira-style screen-share-with-annotation support for React Native and Expo apps.

Same 6-digit code handoff as the web SDK, same agent dashboard, same annotation protocol — built for native apps.

  • One npm package, one config plugin, one provider component.
  • Android: full-screen MediaProjection capture — agent follows the customer across apps. One system consent dialog at session start.
  • iOS: ReplayKit, app-only (no system dialog).
  • Sessions only end on explicit End from the customer or the agent (no auto-end on backgrounding).
  • iOS 14+, Android 8+ (API 26+).

Install

npm install @sira-screen-share/support-react-native react-native-webrtc

Add the config plugin to app.json:

{
  "expo": {
    "plugins": [
      "@sira-screen-share/support-react-native"
    ]
  }
}

Mount the provider at the app root. publicKey is required — the SDK has no production default because mobile apps send their bundle ID as the origin, and a production key has to be allowlisted server-side against your specific bundle ID:

import { SiraSupport } from "@sira-screen-share/support-react-native";

export default function App() {
  return (
    <SiraSupport publicKey="pk_live_acme">
      <RootNavigator />
    </SiraSupport>
  );
}

Three keys you can use:

| Key | Use for | | --------------------- | ------------------------------------------------------------------------------ | | pk_test | localhost-port allowlisted; for the harness, sim/emulator dev, unit tests | | pk_demo | localhost + the public Sira demo origin; for staging / preview builds | | pk_live_<slug> | provisioned per integrator, allowlisted to your iOS+Android bundle IDs |

To get a pk_live_<slug> for production, contact Sira with your bundle ID (e.g., com.acme.payroll on both platforms) and we'll provision it.

Full prop surface:

<SiraSupport
  publicKey="pk_live_acme"                 // required
  appName="MyApp"                          // optional; for the Android priming dialog
>
  <RootNavigator />
</SiraSupport>

Trigger code entry from anywhere:

import { useSiraSupport } from "@sira-screen-share/support-react-native";

function HelpButton() {
  const { openCodeEntry } = useSiraSupport();
  return <Button title="Enter support code" onPress={openCodeEntry} />;
}

Drop-in integration prompt

Paste this into Cursor / Claude Code / Copilot Chat / Cline / Windsurf or any coding agent. It has everything the agent needs to wire the SDK into an existing React Native or Expo codebase cleanly.

I want to integrate the npm package `@sira-screen-share/support-react-native`
into this codebase. It's a drop-in SDK that lets our support team view and
annotate a customer's screen via a 6-digit code the customer enters from a
Help menu.

Reference docs + source (fetch these if anything below is ambiguous):
- npm:    https://www.npmjs.com/package/@sira-screen-share/support-react-native
- GitHub: https://github.com/Yebe-Abe/sira-app-sdk

Please do the full integration. Follow these rules carefully:

1. INSTALL the package and its WebRTC peer dep with the right package
   manager for this repo (npm / pnpm / yarn / bun — infer from lockfiles):
     @sira-screen-share/support-react-native
     react-native-webrtc

2. ADD the Expo config plugin to app.json (or app.config.js / .ts). If the
   project is bare React Native (no Expo config plugin support), skip this
   step — the SDK still works, but the integrator must edit
   AndroidManifest.xml and Info.plist by hand. Surface that to me if it
   applies.

   {
     "expo": {
       "plugins": [
         "@sira-screen-share/support-react-native"
       ]
     }
   }

3. MOUNT the provider once at the very top of the app tree, wrapping the
   rest of the app. Most RN apps have a single root component (App.tsx)
   that returns a navigator or layout — wrap that. publicKey is required.

   import { SiraSupport } from "@sira-screen-share/support-react-native";

   // dev / sim / emulator (localhost-allowlisted)
   <SiraSupport publicKey="pk_test">
     <RootNavigator />
   </SiraSupport>

   // production: ask Sira for a pk_live_<slug> tied to YOUR bundle ID
   <SiraSupport publicKey="pk_live_<slug>">
     <RootNavigator />
   </SiraSupport>

   Public keys at a glance (pass via the `publicKey` prop):
   - `pk_test`       → allowlists localhost ports. Use for sim/emulator dev.
   - `pk_demo`       → allowlists localhost + the public Sira demo origin.
   - `pk_live_<slug>` → provisioned per integrator, allowlisted to a specific
                       iOS+Android bundle ID. Required for shipping to the
                       App Store / Play Store. Ask Sira for one.

   IF YOU DON'T KNOW the right key for this project, default to "pk_test"
   and surface a TODO in your response asking the human to swap it for a
   pk_live_<slug> before publishing.

4. FIND the existing Help affordance in this codebase — it's usually one
   of: a "Help" / "Support" item in a settings screen, a "?" icon in a
   header, a menu item inside a drawer or profile sheet, a chat-with-us
   row in account settings. Search for "help", "support", "contact",
   "faq", "assistance".

5. ADD a new item/button called "Enter support code" next to whatever you
   found. The click handler opens the SDK's modal via the
   `useSiraSupport()` hook:

   import { useSiraSupport } from "@sira-screen-share/support-react-native";

   function SupportCodeRow() {
     const { openCodeEntry } = useSiraSupport();
     return (
       <Pressable onPress={openCodeEntry}>
         <Text>Enter support code</Text>
       </Pressable>
     );
   }

   Match the existing component / styling patterns exactly — if the
   project uses NativeBase / Tamagui / styled-components / a custom design
   system, use that. If it uses StyleSheet.create, use that. DO NOT
   introduce a new styling approach.

6. DON'T DO THESE THINGS:
   • Don't manually request screen-recording permissions — the SDK handles
     ReplayKit (iOS) and MediaProjection (Android) itself
   • Don't add any styling to the SDK's modal or banner from outside —
     they're isolated overlays, customize via the `banner` prop only
   • Don't add env vars, API routes, or backend wiring — the SDK talks to
     Sira's hosted server
   • Don't pass a custom `serverUrl` unless I tell you to
   • Don't refactor the existing Help UI — only add one new entry point

7. After the edits, tell me:
   • Which file you added <SiraSupport> to
   • Which file you added the trigger to and how it looks in context
   • Whether you used the default production key or passed publicKey="pk_test"
   • Whether the project required any AndroidManifest.xml / Info.plist edits
     (only matters for bare RN, not Expo)

That's it.

Capture

  • Android: MediaProjection. The customer accepts a system consent dialog at session start; a mediaProjection-typed foreground service runs for the duration of the session and posts a notification. Captures the entire device — the agent follows the customer across apps.
  • iOS: ReplayKit. No system dialog (only the OS-level red recording bar). Captures the host app's surface only — system-wide capture would require a Broadcast Extension, which the SDK doesn't ship.

Android system dialog

The SDK shows a brief priming screen explaining what's about to happen, then Android's MediaProjection picker appears. The customer must:

  1. Choose Entire screen (not "A single app")
  2. Tap Start now

Once they agree, the foreground service starts and the agent sees the customer's screen — even when the customer leaves your app. A foreground service notification appears in the system tray for the duration of the session.

iOS

iOS uses ReplayKit and shows no system dialog — only the OS-level red recording bar at the top of the screen. iOS sessions capture only the host app's surface (no system-wide capture without a Broadcast Extension, which the SDK doesn't ship). When the customer backgrounds your app on iOS, the agent's view freezes at the last frame; capture resumes when the customer returns to your app.

What happens when the customer leaves your app

| Platform | While customer is in another app | When they return to your app | | ---------- | ----------------------------------------------------------------------------- | ----------------------------------------------------- | | Android | Agent sees the other app live (MediaProjection captures the whole device). | Agent's prior annotations are still on the host app. | | iOS | Agent's view freezes (ReplayKit suspends sample buffer delivery). | Capture resumes; annotations persist. |

Sessions do not auto-end when the customer backgrounds your app. They end only when:

  • The customer taps End in the consent banner
  • The agent taps End on the dashboard
  • The WebRTC connection has been confirmed dead for 30+ seconds (network-failure grace)

Public API

| Surface | What it does | | ------------------------- | ------------------------------------------------------------------------------------------------------- | | <SiraSupport> | Root provider. Owns the session state machine + in-session banner. | | useSiraSupport() | { openCodeEntry, end }. Safe to call before mount (no-ops). | | <SiraSupportTrigger> | Optional unstyled button that wraps openCodeEntry(). |

Provider props

<SiraSupport
  publicKey="pk_live_..."                              // required
  serverUrl="https://api.sira-screen-share.com"        // optional — for self-hosted

  android={{
    priming: true,                                     // default true; show the brief explainer screen before the MediaProjection picker
  }}

  banner={{                                            // defaults are loud and recommended
    background: "#b00020", foreground: "#fff",
    copy: "...", endLabel: "End",
  }}

  appName="MyApp"

  onSessionStart={(sid) => analytics.track("sira_start", { sid })}
  onSessionEnd={(reason, sid) => analytics.track("sira_end", { reason, sid })}
/>

Bandwidth

  • 8 fps steady state, bursting to 15 fps on detected motion.
  • WebP-encoded, ~30–60 KB per frame at 1280px on the longest edge.
  • Target steady-state: 200–400 kbps. Comfortable on mobile networks.

Versioning

This package follows the same beta cadence as the web SDK. Breaking changes possible in 0.0.x; first stable surface is 0.1.0.

Branding

The customer-facing modal (code entry) and Android priming screen ship pre-styled with Sira's brand tokens — the same orange (#f97316) primary and stone-* greyscale used in the agent dashboard and the rest of Sira's surface. Currently this isn't theme-prop-overridable; the package is @sira-screen-share and you're opting into Sira's visual identity for these screens. The in-session <ConsentBanner> is themable via the banner prop because that surface is recording-status UI where loud-red defaults are deliberate. A full theme prop covering all SDK UI is on the 0.1.0 roadmap.

0.0.8 — iOS annotation overlay: attach to host window so ReplayKit captures it

After 0.0.7 made drawings appear at correct positions on the customer's iPhone, live testing showed they still didn't appear on the dashboard — the customer saw the agent's strokes, but the captured JPEG frames coming back to the dashboard didn't include them.

Root cause: 0.0.1–0.0.7 attached the iOS annotation overlay as its own separate UIWindow at windowLevel = .alert + 1. ReplayKit's in-app startCapture doesn't include alert-level sibling windows in the captured composition — they render to screen for the customer but never make it into the captured frame buffer. (Android wasn't affected because its overlay is added to android.R.id.content, i.e. inside the captured view tree.)

The "captured frame is the single source of truth on the dashboard" design (introduced in the partial-render refactor) relies on overlay strokes being visible in the captured frames. Without that, the agent has no way to see what they drew once the local in-progress drag is released.

Fix: the overlay is now added as a subview of the host app's key UIWindow (using addSubview + bringSubviewToFront + autoresizing for orientation). It's still touch-transparent (isUserInteractionEnabled = false) so the host app's touches go through. Since it's in the same render tree the host app's main UIWindow uses, ReplayKit captures it.

Drops the no-longer-needed SiraPassthroughVC helper and the overlayWindow property.

No protocol or API change. Android unchanged.

0.0.7 — iOS annotation overlay: scale viewport-pixel coords to UIKit points

Now that frames flow on iOS (thanks to 0.0.6's JPEG switch), live testing surfaced that agent drawings appeared ~DPR-times larger and positioned wrong on the customer's iPhone — and consequently never made it back to the dashboard's view because they painted off-screen and the captured frame showed nothing where the agent expected.

Root cause: the SDK reports viewport as Dimensions.get("screen") × dpr (pixel space) and the dashboard sends annotation coords in that same pixel space, but the iOS overlay's UIView (bounds.size) is in UIKit points (1/DPR of pixels). Every iPhone since 2010 is Retina (DPR 2 or 3), so the overlay was effectively scaling coords up by 2-3× and ignoring the device pixel ratio. Android wasn't affected because its Canvas uses pixels natively.

Fix: translatePoint / translateRect in the iOS overlay now scale incoming coords by bounds / viewport before subtracting the screen-origin. One scale factor for x, one for y; works on iPhone full-screen, iPad split-view, multi-window — all the cases the existing screenOrigin() logic already handled.

No protocol change. Android consumers see zero behavioral difference.

0.0.6 — iOS frame encoder switched to JPEG; threading fix on stopCapture

Live test on a physical iPhone (the first time anyone ran iOS SDK code on real hardware) surfaced that iOS has no WebP encoder in ImageIO — Apple ships only decoders. Both 0.0.3's org.webmproject.webp UTI and 0.0.5's public.webp UTI fail at CGImageDestinationCreateWithData, silently dropping every iOS frame. 0.0.6 switches iOS to JPEG (public.jpeg, quality 0.6), the only lossy image format iOS ImageIO can both encode and that browsers decode universally. The dashboard's NativeFrameViewer was updated in lockstep to a format-agnostic Blob-based loader (browser sniffs from magic bytes), so the same code path renders WebP (Android) and JPEG (iOS) without a protocol change.

Also fixes a Main Thread Checker violation in stopCapture: ReplayKit's completion callback runs on its internal XPC queue, not main; the removeOverlay() call inside that callback was touching UIWindow.isHidden from a background thread. Wrapped in DispatchQueue.main.async.

JPEG frames are roughly 1.5–2× WebP at the same visual quality, so iOS sessions use ~500-800 kbps vs. Android's ~250-450 kbps at 8 fps. Within the 200-400 kbps target band; can drop quality to 0.5 in a follow-up if real-world bitrate runs hot. Long-term, linking libwebp.framework would let iOS match Android's output size.

The wire-format field is still named webp for backward compatibility — it's now opaque image bytes whose format is sniffed on decode.

0.0.5 — Sira-brand the modal + priming screen

Replaces the legacy React-Native blue (#1a73e8) CTA + arbitrary greys (#444, #333, #666) in CodeEntryModal and PrimingScreen with Sira's primary orange + stone palette. No API changes — purely visual. Drop-in compatible with 0.0.4.

0.0.4 — iOS bug fixes

iOS-only patch. Recommended for any iOS integration; Android consumers see no behavioral change.

  • WebP encoding is fixed. 0.0.3 (and earlier) used the wrong UTI string ("org.webmproject.webp") for CGImageDestinationCreateWithData, which made the destination init return nil and silently dropped every frame. Switched to "public.webp" — the identifier ImageIO actually registers on iOS 14+. Any iOS session before 0.0.4 produced no frames on the agent dashboard.
  • requestProjectionConsent Obj-C signature now matches the JS bridge (no captureMode parameter — that argument was dropped in 0.0.3 on the JS side but not here, so the call mismatched at runtime).
  • RPScreenRecorderDelegate is now wired. When iOS terminates capture mid-session (Control Center toggle, low memory, Siri, screen-recording restriction kicking in), the SDK emits a SiraCaptureState event so the JS provider can tear the session down cleanly instead of waiting for the WebRTC peer to time out.
  • Frame pipeline thread safety: seq / lastFrameTime / lastFrameHash are now mutated only on a dedicated serial queue; CIContext is cached on the module instead of recreated per frame.
  • SiraFrame event body now includes ts (epoch ms). Matches Android.

Migrating from 0.0.2

0.0.3 removed the "in-app" Android capture mode — full-screen MediaProjection is the only Android path now. If your earlier integration looked like:

// app.json
["@sira-screen-share/support-react-native", { "android": { "captureMode": "full-screen" } }]
<SiraSupport android={{ captureMode: "full-screen" }} ... />

…drop both { "android": { "captureMode": ... } } and the android={{ captureMode: ... }} prop. The plugin entry is now just "@sira-screen-share/support-react-native" (no options) and the provider's android prop carries only priming. The CaptureMode type export is gone.

The plugin always injects FOREGROUND_SERVICE + FOREGROUND_SERVICE_MEDIA_PROJECTION permissions and the SiraProjectionService declaration into the host manifest; that used to be conditional on captureMode === "full-screen".

License

MIT.