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

@myo-devs/react

v0.1.1

Published

Official React SDK for the Myo Platform

Readme

Myo React SDK

Official React SDK for the Myo Platform - Connect your users' personal data through a seamless widget experience.

Installation

npm install @myo-devs/react

Quick Start

The simplest way to add Myo to your app:

import { MyoConnectButton, useMyoConnection } from '@myo-devs/react';

function App() {
  const { connection, setConnection, clearConnection } = useMyoConnection({
    storage: 'session',
  });

  if (connection) {
    return (
      <div>
        <p>Connected as {connection.userId}</p>
        <button onClick={clearConnection}>Disconnect</button>
      </div>
    );
  }

  return (
    <MyoConnectButton
      fetchToken={async () => {
        const res = await fetch('/api/link-token', { method: 'POST' });
        return (await res.json()).linkToken;
      }}
      onSuccess={(metadata) => setConnection(metadata.userId, metadata.provider)}
    >
      Connect Your Data
    </MyoConnectButton>
  );
}

Features

  • One-click connection - MyoConnectButton handles token fetching and widget opening
  • Custom button support - useMyoConnect hook for using your own button UI
  • Connection persistence - useMyoConnection hook for storing connection state
  • Low-level control - useMyoLink hook for full customization
  • Modal & redirect modes - Modal overlay (default) or popup window
  • Full TypeScript support - Excellent IDE autocompletion
  • Secure PostMessage - Origin-validated communication with widget

Components & Hooks

MyoConnectButton

The easiest way to add Myo connection to your app. Handles fetching the link token and opening the widget automatically.

import { MyoConnectButton, useMyoConnection } from '@myo-devs/react';

function ConnectPage() {
  const { connection, setConnection, clearConnection } = useMyoConnection({
    storage: 'session',
  });

  if (connection) {
    return (
      <div>
        <p>Connected: {connection.userId} via {connection.provider}</p>
        <button onClick={clearConnection}>Disconnect</button>
      </div>
    );
  }

  return (
    <MyoConnectButton
      fetchToken={async () => {
        const res = await fetch('/api/link-token', { method: 'POST' });
        const data = await res.json();
        if (!res.ok) throw new Error(data.error);
        return data.linkToken;
      }}
      widgetUrl={process.env.NEXT_PUBLIC_MYO_WIDGET_URL}
      onSuccess={(metadata) => {
        setConnection(metadata.userId, metadata.provider);
      }}
      onError={(error) => {
        console.error('Connection failed:', error.error);
      }}
      className="connect-button"
    >
      Connect Your Data
    </MyoConnectButton>
  );
}

MyoConnectButton Props

| Prop | Type | Required | Description | |------|------|----------|-------------| | fetchToken | () => Promise<string> | Yes | Async function to fetch link token from your backend | | children | ReactNode | Yes | Button content | | widgetUrl | string | No | Custom widget URL (default: https://link.myo-app.co) | | onSuccess | (metadata) => void | No | Called on successful connection | | onError | (error) => void | No | Called when an error occurs | | onExit | (error, metadata) => void | No | Called when user exits | | connectingText | string | No | Text while connecting (default: "Connecting...") | | className | string | No | CSS classes for the button | | style | CSSProperties | No | Inline styles for the button | | disabled | boolean | No | Disable the button |

useMyoConnect

Use this hook when you want to trigger the Myo modal from your own custom button or UI element. It handles token fetching and widget opening, giving you full control over the trigger UI.

import { useMyoConnect, useMyoConnection } from '@myo-devs/react';

function CustomConnectButton() {
  const { setConnection } = useMyoConnection({ storage: 'session' });

  const { connect, isConnecting, isOpen, error } = useMyoConnect({
    fetchToken: async () => {
      const res = await fetch('/api/link-token', { method: 'POST' });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error);
      return data.linkToken;
    },
    widgetUrl: process.env.NEXT_PUBLIC_MYO_WIDGET_URL,
    onSuccess: (metadata) => {
      setConnection(metadata.userId, metadata.provider);
    },
    onError: (error) => {
      console.error('Connection failed:', error.error);
    },
  });

  return (
    <div>
      <MyFancyButton onClick={connect} disabled={isConnecting || isOpen}>
        {isConnecting ? 'Connecting...' : 'Link Your Data'}
      </MyFancyButton>
      {error && <p className="error">{error}</p>}
    </div>
  );
}

useMyoConnect Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | fetchToken | () => Promise<string> | Yes | Async function to fetch link token from your backend | | widgetUrl | string | No | Custom widget URL (default: https://link.myo-app.co) | | displayMode | 'modal' \| 'redirect' | No | Widget display mode (default: 'modal') | | onSuccess | (metadata) => void | No | Called on successful connection | | onError | (error) => void | No | Called when an error occurs | | onExit | (error, metadata) => void | No | Called when user exits | | modalStyle | CSSProperties | No | Override modal container styles | | iframeStyle | CSSProperties | No | Override iframe styles | | backdropStyle | CSSProperties | No | Override backdrop styles |

useMyoConnect Return Value

| Property | Type | Description | |----------|------|-------------| | connect | () => Promise<void> | Trigger the connection flow (fetch token + open widget) | | isConnecting | boolean | Whether a token is being fetched | | isOpen | boolean | Whether the widget is currently open | | ready | boolean | Whether the widget is ready (token has been fetched) | | error | string \| null | Latest error message (if any) |

useMyoConnection

Hook for managing persisted connection state. Handles storing/retrieving connection from browser storage.

import { useMyoConnection } from '@myo-devs/react';

function MyComponent() {
  const { connection, isLoaded, setConnection, clearConnection } = useMyoConnection({
    storage: 'session', // or 'local'
    storageKey: 'myo_connection', // optional custom key
  });

  if (!isLoaded) return <div>Loading...</div>;

  if (connection) {
    return (
      <div>
        <p>User: {connection.userId}</p>
        <p>Provider: {connection.provider}</p>
        <p>Connected at: {new Date(connection.connectedAt).toLocaleString()}</p>
        <button onClick={clearConnection}>Disconnect</button>
      </div>
    );
  }

  return <div>Not connected</div>;
}

useMyoConnection Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | storage | 'session' \| 'local' | 'session' | Storage type | | storageKey | string | 'myo_connection' | Custom storage key |

useMyoConnection Return Value

| Property | Type | Description | |----------|------|-------------| | connection | MyoConnection \| null | Current connection or null | | isLoaded | boolean | Whether storage has been checked (SSR-safe) | | setConnection | (userId, provider) => void | Save a connection | | clearConnection | () => void | Clear the connection |

useMyoLink (Low-Level)

For advanced use cases where you already have a link token and need direct control over the widget. Most developers should use useMyoConnect instead.

import { useMyoLink } from '@myo-devs/react';

function CustomConnect({ linkToken }) {
  const { open, close, ready, isOpen, error } = useMyoLink({
    token: linkToken,
    onSuccess: (metadata) => {
      console.log('User ID:', metadata.userId);
      console.log('Provider:', metadata.provider); // 'google' | 'meta' | 'upload'
    },
    onError: (error) => {
      console.error('Error:', error.error);
    },
    onExit: (error, metadata) => {
      if (metadata.cancelled) console.log('User cancelled');
    },
    displayMode: 'modal', // or 'redirect'
  });

  return (
    <button onClick={open} disabled={!ready || isOpen}>
      {isOpen ? 'Connecting...' : 'Connect Your Data'}
    </button>
  );
}

useMyoLink Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | token | string | Yes | Link token from your backend | | onSuccess | (metadata) => void | No | Called on successful connection | | onError | (error) => void | No | Called when an error occurs | | onExit | (error, metadata) => void | No | Called when user exits | | displayMode | 'modal' \| 'redirect' | No | Widget display mode (default: 'modal') | | widgetUrl | string | No | Custom widget URL | | modalStyle | CSSProperties | No | Override modal container styles | | iframeStyle | CSSProperties | No | Override iframe styles | | backdropStyle | CSSProperties | No | Override backdrop styles |

useMyoLink Return Value

| Property | Type | Description | |----------|------|-------------| | open | () => void | Open the link widget | | close | () => void | Close the link widget programmatically | | ready | boolean | Whether the widget is ready to open | | isOpen | boolean | Whether the widget is currently open | | error | LinkErrorMetadata \| null | Latest error (if any) |

Backend Setup

Link tokens must be created on your backend. Example using Next.js API routes:

// app/api/link-token/route.ts
import { NextResponse } from 'next/server';
import { MyoClient } from '@myo-devs/node';

const client = new MyoClient({ apiKey: process.env.MYO_API_KEY });

export async function POST() {
  const token = await client.link.tokens.create({
    redirectUri: process.env.NEXT_PUBLIC_APP_URL,
  });

  return NextResponse.json({
    linkToken: token.linkToken,
  });
}

Callback Metadata Types

LinkSuccessMetadata:

{
  userId: string;
  provider: 'google' | 'meta' | 'upload';
  timestamp: number;
}

LinkErrorMetadata:

{
  error: string;
  provider?: 'google' | 'meta' | 'upload';
  timestamp: number;
}

LinkExitMetadata:

{
  cancelled: boolean;
  error?: LinkErrorMetadata;
  timestamp: number;
}

MyoConnection:

{
  userId: string;
  provider: 'google' | 'meta' | 'upload';
  connectedAt: number;
}

Security Note

The onSuccess callback is useful for updating your UI immediately, but you should always rely on backend webhooks to confirm the connection was successful. The frontend callback could potentially be spoofed.

Requirements

  • React 18+
  • React DOM 18+

License

MIT