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

@rehers/rehers-roleplay-sdk

v2.5.1

Published

Seamless Roleplay SDK — embed roleplay call sessions via a modal + iframe

Readme

Roleplay SDK for Seamless.AI

Install

npm install @rehers/rehers-roleplay-sdk

1. Wrap your app with the Provider

Add this once, above all your routes. It initializes the SDK for the logged-in Seamless user.

import { SeamlessRoleplayProvider } from "@rehers/rehers-roleplay-sdk/react";

function App() {
  // You already have the logged-in user from your auth/session.
  // The SDK needs their id and email.
  const me = useCurrentUser(); // however you get the logged-in user

  return (
    <SeamlessRoleplayProvider
      publishableKey="pk_live_..."
      userId={String(me.id)}
      userEmail={me.username}
      userRole={me.orgRole}
      onReady={() => console.log("Roleplay SDK ready")}
      onError={(err) => console.error("Roleplay SDK error", err)}
    >
      <Routes>
        <Route path="/roleplay" element={<RoleplayPage />} />
        <Route path="/contacts" element={<ContactSearch />} />
        {/* ...your other routes */}
      </Routes>
    </SeamlessRoleplayProvider>
  );
}

If you fetch the user via API:

const res = await fetch("https://api.seamless.ai/api/users/me", {
  credentials: "include",
}).then((r) => r.json());

const me = res.data ?? res;
// me.id       → pass as userId (convert to string)
// me.username → pass as userEmail
// me.orgRole  → pass as userRole directly

That's the only setup. Everything below just works.


2. Full Roleplay page

For the dedicated Roleplay tab/page, drop in RoleplayEmbed. It fills its container.

import { RoleplayEmbed } from "@rehers/rehers-roleplay-sdk/react";

function RoleplayPage() {
  return (
    <RoleplayEmbed style={{ width: "100%", height: "100%" }} />
  );
}

Make sure the parent has a height (height: 100%, height: 100vh, flex: 1, etc).

Mounts automatically. Cleans up automatically when the user navigates away.


3. Roleplay dialog on Contact Search

When a user clicks "Roleplay" on a contact row, a dialog opens over the page.

import { useState } from "react";
import { RoleplayDialog } from "@rehers/rehers-roleplay-sdk/react";

function ContactSearch() {
  const [activeContact, setActiveContact] = useState(null);

  return (
    <>
      {/* Your existing contact table — just add an onClick to each row's button */}
      <table>
        {contacts.map((contact) => (
          <tr key={contact.id}>
            <td>{contact.name}</td>
            <td>{contact.company}</td>
            <td>{contact.title}</td>
            <td>
              <button onClick={() => setActiveContact(contact)}>
                Roleplay
              </button>
            </td>
          </tr>
        ))}
      </table>

      {/* This renders nothing visible — the SDK creates the overlay */}
      <RoleplayDialog
        open={activeContact !== null}
        name={activeContact?.name ?? ""}
        domain={activeContact?.domain ?? ""}
        company={activeContact?.company ?? ""}
        title={activeContact?.title ?? ""}
        liUrl={activeContact?.linkedinUrl}
        companyDescription={activeContact?.companyDescription}
        onClose={() => setActiveContact(null)}
        onError={(err) => console.error("Error", err)}
      />
    </>
  );
}

How it works: Set activeContact to a contact object to open the dialog. Set it back to null to close. The onClose callback fires when the user closes it themselves.


4. Add to Scenario (bulk)

When users select multiple contacts and click "Add to Scenario", a scenario picker dialog opens.

import { useState } from "react";
import { AddToScenarioDialog } from "@rehers/rehers-roleplay-sdk/react";

function ContactSearch() {
  const [selectedContacts, setSelectedContacts] = useState([]);
  const [showScenario, setShowScenario] = useState(false);

  return (
    <>
      {/* Your existing table with checkboxes that populate selectedContacts */}

      <button
        disabled={selectedContacts.length === 0}
        onClick={() => setShowScenario(true)}
      >
        Add {selectedContacts.length} to Scenario
      </button>

      <AddToScenarioDialog
        open={showScenario}
        contacts={selectedContacts.map((c) => ({
          name: c.name,
          company: c.company,
          title: c.title,
          domain: c.domain,
          liUrl: c.linkedinUrl,
        }))}
        onComplete={(data) => {
          console.log(`Added ${data.addedCount} to ${data.scenarioName}`);
          setShowScenario(false);
          setSelectedContacts([]);
        }}
        onClose={() => setShowScenario(false)}
        onError={(err) => console.error("Error", err)}
      />
    </>
  );
}

Accepts 1 to 25 contacts. Each contact needs name, company, title, and domain.


Contact field mapping

When passing contact data to RoleplayDialog or AddToScenarioDialog:

| SDK prop | Your contact field | |---|---| | name | Full name | | domain | Company domain (e.g. "stripe.com") | | company | Company name | | title | Job title | | liUrl | LinkedIn URL (optional) | | companyDescription | Company description (optional) |


That's it

  • Provider wraps your app once — handles auth, sessions, cleanup
  • RoleplayEmbed is your full Roleplay page — one component
  • RoleplayDialog opens per-contact from Contact Search — controlled by a boolean
  • AddToScenarioDialog opens for bulk import — controlled by a boolean

All three clean up after themselves. No manual destroy(), no useEffect, no refs.

TypeScript types are included — your editor will autocomplete all props.


Trial and upgrade handling

If a user doesn't have a Roleplay subscription, the SDK shows the upgrade/trial UI automatically inside the iframe. No client-side logic needed.


Advanced: Vanilla JavaScript

If you need the vanilla SDK without React:

import "@rehers/rehers-roleplay-sdk";

// Initialize once
SeamlessRoleplay.init({
  publishableKey: "pk_live_...",
  userId: "...",
  userEmail: "...",
  onReady() { console.log("ready"); },
});

// Full page embed
SeamlessRoleplay.mount(document.getElementById("container"));

// Contact dialog
SeamlessRoleplay.open({ name: "...", domain: "...", company: "...", title: "..." });

// Bulk import
SeamlessRoleplay.addToScenario({ contacts: [...], onComplete(data) { } });

// Cleanup
SeamlessRoleplay.close();     // close dialog
SeamlessRoleplay.unmount();   // remove embed
SeamlessRoleplay.destroy();   // full cleanup