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

@pythiasport/betting-widget

v1.1.2

Published

TypeScript SDK for embedding Pythia betting widget

Downloads

272

Readme

@pythiasport/betting-widget

A modern, framework-agnostic TypeScript SDK for embedding the Pythia betting widget into any web application.

Features

  • TypeScript-first with full type safety
  • 🎯 Framework-agnostic - works with React, Vue, Angular, or vanilla JS
  • 🎨 Theme support with dark/light modes
  • 📡 Event-driven architecture using EventEmitter pattern
  • 🔒 Type-safe APIs with comprehensive JSDoc documentation
  • 📦 Multiple build formats - ESM, CommonJS, and UMD/IIFE
  • 🎪 Zero dependencies in runtime

Installation

npm install @pythiasport/betting-widget
yarn add @pythiasport/betting-widget
pnpm add @pythiasport/betting-widget

Quick Start

1. Add container to your HTML

<div id="betting-widget-container"></div>

2. Initialize the SDK

import { PythiaSDK } from '@pythiasport/betting-widget';

const sdk = new PythiaSDK();

// Listen to events
sdk.on('betslip:open', () => {
  console.log('Betslip opened!');
});

sdk.on('ready', () => {
  console.log('Widget is ready!');
});

// Initialize with configuration
sdk.init({
  tenantId: 'your-tenant-id',
  jwtToken: 'user-jwt-token',
  userId: 'user-123',
  currencyCode: 'USD',
  currencySymbol: '',
  theme: 'dark',
  style: 'width: 100%; height: 100%; border: none;',
  onLoginRequest: () => {
    // Handle login request
    console.log('User needs to login');
  }
});

Framework Integration

React

import { useEffect, useRef } from 'react';
import { PythiaSDK } from '@pythiasport/betting-widget';

function BettingWidget() {
  const sdkRef = useRef<PythiaSDK | null>(null);

  useEffect(() => {
    const sdk = new PythiaSDK();
    sdkRef.current = sdk;

    sdk.on('betslip:open', () => {
      console.log('Betslip opened');
    });

    sdk.init({
      tenantId: 'your-tenant-id',
      jwtToken: 'user-token',
      userId: 'user-123',
      currencyCode: 'USD',
      currencySymbol: '',
      theme: 'dark',
    });

    return () => {
      sdk.destroy();
    };
  }, []);

  const handleThemeToggle = () => {
    sdkRef.current?.setTheme('light');
  };

  return (
    <div>
      <button onClick={handleThemeToggle}>Toggle Theme</button>
      <div id="betting-widget-container" />
    </div>
  );
}

Vue 3

<template>
  <div>
    <button @click="toggleTheme">Toggle Theme</button>
    <div id="betting-widget-container"></div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import { PythiaSDK } from '@pythiasport/betting-widget';

const sdk = ref<PythiaSDK | null>(null);

onMounted(() => {
  const instance = new PythiaSDK();
  sdk.value = instance;

  instance.on('betslip:open', () => {
    console.log('Betslip opened');
  });

  instance.init({
    tenantId: 'your-tenant-id',
    jwtToken: 'user-token',
    userId: 'user-123',
    currencyCode: 'USD',
    currencySymbol: '',
    theme: 'dark',
  });
});

onUnmounted(() => {
  sdk.value?.destroy();
});

const toggleTheme = () => {
  sdk.value?.setTheme('light');
};
</script>

Angular

import { Component, OnInit, OnDestroy } from '@angular/core';
import { PythiaSDK } from '@pythiasport/betting-widget';

@Component({
  selector: 'app-betting-widget',
  template: `
    <div>
      <button (click)="toggleTheme()">Toggle Theme</button>
      <div id="betting-widget-container"></div>
    </div>
  `
})
export class BettingWidgetComponent implements OnInit, OnDestroy {
  private sdk: PythiaSDK | null = null;

  ngOnInit() {
    this.sdk = new PythiaSDK();

    this.sdk.on('betslip:open', () => {
      console.log('Betslip opened');
    });

    this.sdk.init({
      tenantId: 'your-tenant-id',
      jwtToken: 'user-token',
      userId: 'user-123',
      currencyCode: 'USD',
      currencySymbol: '',
      theme: 'dark',
    });
  }

  ngOnDestroy() {
    this.sdk?.destroy();
  }

  toggleTheme() {
    this.sdk?.setTheme('light');
  }
}

Vanilla JavaScript (UMD)

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/@pythiasport/betting-widget@latest/dist/index.global.js"></script>
</head>
<body>
  <div id="betting-widget-container"></div>

  <script>
    const sdk = new PythiaSDK.PythiaSDK();

    sdk.on('betslip:open', function() {
      console.log('Betslip opened');
    });

    sdk.init({
      tenantId: 'your-tenant-id',
      jwtToken: 'user-token',
      userId: 'user-123',
      currencyCode: 'USD',
      currencySymbol: ',
      theme: 'dark'
    });
  </script>
</body>
</html>

API Reference

Constructor

const sdk = new PythiaSDK();

Methods

init(options: PythiaSDKOptions): void

Initializes the SDK with configuration options.

Parameters:

  • tenantId (string, required) - Unique identifier for the tenant
  • jwtToken (string, required) - JWT token for authentication
  • userId (string, required) - User identifier
  • currencyCode (string, required) - ISO currency code (e.g., 'USD', 'EUR')
  • currencySymbol (string, required) - Currency symbol (e.g., ', '€')
  • style (string, optional) - CSS styles for the iframe
  • theme ('light' | 'dark', optional) - Initial theme (default is 'dark')
  • bettingAppUrl (string, optional) - URL of the betting application
  • oddsFormat ('decimal' | 'fractional' | 'moneyline', optional) - a parameter that defines which price format should be used (default is 'decimal').
  • language (optional) - the interface language, specified as a country/language code (e.g. 'en', 'de'; default is 'en').
  • timeFormat ('24h' | '12h', optional) - the time display format (default is '24h').
  • userLocation ('string', optional) - The user’s location in country code format is used to display only the streams available for that specific location. If this parameter is not provided, all streams will be displayed, but not all of them will be playable. (e.g. 'US', 'DE').
  • onLoginRequest (function, optional) - Callback when login is requested

updateUserInfo(userInfo: UserInfo): void

Updates user authentication information after login/logout.

sdk.updateUserInfo({
  jwtToken: 'new-jwt-token',
  userId: 'user-123',
  currencyCode: 'EUR',
  currencySymbol: '€'
});

It can be used to change the price type and the time format.

sdk.updateUserInfo({
  timeFormat: '12h',
  oddsFormat: 'moneyline'
});

setTheme(theme: 'light' | 'dark'): void

Changes the widget theme.

sdk.setTheme('dark');

setLanguage(theme: string): void

Changes the widget language.

sdk.setLanguage('en');

notifyScrollChange(scrollY: number, scrollX?: number): void

Manually notifies the iframe of scroll position changes.

sdk.notifyScrollChange(window.scrollY);

setBetslipButtonOffset(offset: BetslipButtonOffset): void

Sets the offset for betslip floating button positioning.

sdk.setBetslipButtonOffset({
  top: 80,    // pixels from top
  bottom: 20  // pixels from bottom
});

destroy(): void

Destroys the SDK instance and cleans up all resources.

sdk.destroy();

getIsInitialized(): boolean

Checks if the SDK is initialized.

if (sdk.getIsInitialized()) {
  // SDK is ready
}

Events

The SDK uses an EventEmitter pattern for all events. Use on(), once(), and off() methods.

Event Types

  • betslip:open - Emitted when the betslip is opened
  • betslip:close - Emitted when the betslip is closed
  • login:request - Emitted when the iframe requests login
  • scroll:up - Emitted when the iframe requests scroll to top
  • height:change - Emitted when iframe height changes (receives height string)
  • ready - Emitted when the iframe is loaded and ready

Event Methods

// Listen to an event
sdk.on('betslip:open', () => {
  console.log('Betslip opened');
});

// Listen once
sdk.once('ready', () => {
  console.log('Widget ready - this will only fire once');
});

// Remove listener
const handler = () => console.log('Betslip closed');
sdk.on('betslip:close', handler);
sdk.off('betslip:close', handler);

// Remove all listeners for an event
sdk.removeAllListeners('betslip:open');

// Remove all listeners
sdk.removeAllListeners();

// Get listener count
const count = sdk.listenerCount('betslip:open');

TypeScript Support

The SDK is written in TypeScript and provides full type definitions:

import { PythiaSDK, PythiaSDKOptions, UserInfo, ThemeType } from '@pythiasport/betting-widget';

const options: PythiaSDKOptions = {
  tenantId: 'tenant-123',
  jwtToken: 'token',
  userId: 'user-123',
  currencyCode: 'USD',
  currencySymbol: '',
  theme: 'dark'
};

const sdk = new PythiaSDK();
sdk.init(options);

Legacy Version

For projects that require compatibility with older browsers, a legacy (umd) version of the SDK is available. To use it you can include it via CDN:

<script src="https://unpkg.com/@pythiasport/betting-widget@latest/dist/index.global.js"></script>
<script>
    window.pythiaSDK.init({
        tenantId: 'your-tenant-id',
        jwtToken: 'user-token',
        currencyCode: 'USD',
        currencySymbol: '$',
        theme: 'dark'
        onLoginRequest: () => {
            // Handle login request
            console.log('User needs to login');
        }
    })
</script>

# Migration Guide

This guide helps you migrate from the original JavaScript SDK to the new TypeScript version.

Two Options

You have two options when upgrading to the new SDK:

  1. Use the Legacy API - Zero code changes, backward compatible
  2. Migrate to Modern API - Better features, type safety, and developer experience

Option 1: Legacy API (Zero Changes) ✨

What You Need to Do

Simply replace your script tag with the new legacy build:

Before:

<script src="path/to/old-pythia-sdk.js"></script>

After:

<script src="https://unpkg.com/@pythiasport/betting-widget@latest/dist/legacy.global.js"></script>

That's it! Your existing code will work without any changes:

// All your existing code works exactly as before
window.pythiaSDK.onBetslipOpen = function() {
  console.log('Betslip opened');
};

window.pythiaSDK.init({
  tenantId: 'your-tenant-id',
  jwtToken: 'token',
  userId: 'user-123',
  currencyCode: 'USD',
  currencySymbol: '$',
  theme: 'dark'
});

window.pythiaSDK.setTheme('light');
window.pythiaSDK.updateUserInfo({ /* ... */ });
What's Different (Behind the Scenes)
  • ✅ Modern TypeScript implementation
  • ✅ Better performance and optimization
  • ✅ Improved error handling
  • ✅ Automatic setup of internal listeners
  • ⚠️ Some internal methods log deprecation warnings (but still work)
Deprecation Warnings

You might see console warnings for these methods (they still work, but are no longer necessary):

  • insertIframe() - Auto-handled on init()
  • sendAuthDataToIframe() - Auto-sent on init()
  • listenToIframeEvents() - Auto-setup on init()
  • sendInitialTheme() - Auto-sent on init()
  • syncParentScroll() - Auto-setup on init()
  • syncParentHeight() - Auto-setup on init()
  • sendIframeTopOffset() - Auto-sent on init()

You can safely remove calls to these methods if you want to clean up your code.

Option 2: Migrate to Modern API 🚀

Benefits
  • ✅ Multiple event listeners per event
  • ✅ Type safety with TypeScript
  • ✅ Better IDE autocomplete
  • ✅ One-time listeners with once()
  • ✅ Cleaner event management
  • ✅ Tree-shakeable imports
  • ✅ Modern module system
Step-by-Step Migration
Step 1: Install via NPM
npm install @pythiasport/betting-widget
Step 2: Import the SDK

Before (Global Script):

<script src="path/to/pythia-sdk.js"></script>

After (ES Module):

import { PythiaSDK } from '@pythiasport/betting-widget';
Step 3: Create Instance

Before:

// Used global window.pythiaSDK
window.pythiaSDK.init({ /* ... */ });

After:

// Create your own instance
const sdk = new PythiaSDK();
sdk.init({ /* ... */ });
Step 4: Replace Callback Properties with Events

Before:

window.pythiaSDK.onBetslipOpen = function() {
  console.log('Opened');
};

window.pythiaSDK.onBetslipClose = function() {
  console.log('Closed');
};

After:

sdk.on('betslip:open', () => {
  console.log('Opened');
});

sdk.on('betslip:close', () => {
  console.log('Closed');
});
Step 5: Update Method Calls

Most methods stay the same, just called on your instance:

Before:

window.pythiaSDK.setTheme('light');
window.pythiaSDK.updateUserInfo({ /* ... */ });
window.pythiaSDK.setBetslipButtonOffset({ top: 80 });
window.pythiaSDK.scrollChanged(window.scrollY);

After:

sdk.setTheme('light');
sdk.updateUserInfo({ /* ... */ });
sdk.setBetslipButtonOffset({ top: 80 });
sdk.notifyScrollChange(window.scrollY); // Renamed for clarity
Step 6: Remove Unnecessary Method Calls

These methods are no longer needed (handled automatically):

Before:

window.pythiaSDK.init({ /* ... */ });
window.pythiaSDK.insertIframe();           // Remove this
window.pythiaSDK.sendAuthDataToIframe();   // Remove this
window.pythiaSDK.listenToIframeEvents();   // Remove this
window.pythiaSDK.sendInitialTheme();       // Remove this

After:

sdk.init({ /* ... */ });
// That's it! Everything else is automatic
Step 7: Add Cleanup (Recommended)

Before:

// No cleanup mechanism

After:

// Clean up when done (e.g., component unmount)
sdk.destroy();
Complete Example: Before & After
Before (Legacy JavaScript)
<!DOCTYPE html>
<html>
<head>
  <script src="pythia-sdk.js"></script>
</head>
<body>
  <div id="betting-widget-container"></div>
  
  <script>
    window.pythiaSDK.onBetslipOpen = function() {
      console.log('Betslip opened');
    };

    window.pythiaSDK.onBetslipClose = function() {
      console.log('Betslip closed');
    };

    window.pythiaSDK.init({
      tenantId: 'tenant-123',
      jwtToken: 'token-abc',
      userId: 'user-456',
      currencyCode: 'USD',
      currencySymbol: '$',
      theme: 'dark',
      onLoginRequest: function() {
        alert('Please login');
      }
    });

    // Later...
    window.pythiaSDK.setTheme('light');
    window.pythiaSDK.scrollChanged(window.scrollY);
  </script>
</body>
</html>
After (Modern TypeScript)
import { PythiaSDK } from '@pythiasport/betting-widget';

// Create instance
const sdk = new PythiaSDK();

// Set up event listeners
sdk.on('betslip:open', () => {
  console.log('Betslip opened');
});

sdk.on('betslip:close', () => {
  console.log('Betslip closed');
});

// Initialize
sdk.init({
  tenantId: 'tenant-123',
  jwtToken: 'token-abc',
  userId: 'user-456',
  currencyCode: 'USD',
  currencySymbol: '$',
  theme: 'dark',
  onLoginRequest: () => {
    alert('Please login');
  }
});

// Later...
sdk.setTheme('light');
sdk.notifyScrollChange(window.scrollY);

// Clean up when done
// sdk.destroy();
Framework-Specific Examples
React
import { useEffect, useRef } from 'react';
import { PythiaSDK } from '@pythiasport/betting-widget';

function BettingWidget() {
  const sdkRef = useRef<PythiaSDK | null>(null);

  useEffect(() => {
    const sdk = new PythiaSDK();
    sdkRef.current = sdk;

    // Events
    sdk.on('betslip:open', () => console.log('Opened'));
    sdk.on('betslip:close', () => console.log('Closed'));

    // Initialize
    sdk.init({
      tenantId: 'tenant-123',
      jwtToken: 'token-abc',
      userId: 'user-456',
      currencyCode: 'USD',
      currencySymbol: '$',
      theme: 'dark',
    });

    // Cleanup
    return () => {
      sdk.destroy();
    };
  }, []);

  return <div id="betting-widget-container" />;
}
Vue 3
<template>
  <div id="betting-widget-container"></div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import { PythiaSDK } from '@pythiasport/betting-widget';

const sdk = ref<PythiaSDK | null>(null);

onMounted(() => {
  const instance = new PythiaSDK();
  sdk.value = instance;

  // Events
  instance.on('betslip:open', () => console.log('Opened'));
  instance.on('betslip:close', () => console.log('Closed'));

  // Initialize
  instance.init({
    tenantId: 'tenant-123',
    jwtToken: 'token-abc',
    userId: 'user-456',
    currencyCode: 'USD',
    currencySymbol: '$',
    theme: 'dark',
  });
});

onUnmounted(() => {
  sdk.value?.destroy();
});
</script>

API Changes Summary

| Legacy API | Modern API | Notes | |------------|------------|-------| | window.pythiaSDK.onBetslipOpen = fn | sdk.on('betslip:open', fn) | Event-based | | window.pythiaSDK.onBetslipClose = fn | sdk.on('betslip:close', fn) | Event-based | | window.pythiaSDK.init(opts) | sdk.init(opts) | Same | | window.pythiaSDK.setTheme(theme) | sdk.setTheme(theme) | Same | | window.pythiaSDK.setLanguage(language) | sdk.setLanguage(language) | Same | | window.pythiaSDK.updateUserInfo(info) | sdk.updateUserInfo(info) | Same | | window.pythiaSDK.setBetslipButtonOffset(o) | sdk.setBetslipButtonOffset(o) | Same | | window.pythiaSDK.scrollChanged(y, x) | sdk.notifyScrollChange(y, x) | Renamed | | window.pythiaSDK.getIframe() | Internal | Not exposed | | window.pythiaSDK.insertIframe() | Auto-handled | Not needed | | window.pythiaSDK.config | Internal | Not exposed | | window.pythiaSDK.$iframe | Internal | Not exposed | | - | sdk.destroy() | New method | | - | sdk.on(event, fn) | New method | | - | sdk.once(event, fn) | New method | | - | sdk.off(event, fn) | New method |

Event Names

| Legacy Callback | Modern Event | Description | |----------------|--------------|-------------| | onBetslipOpen | 'betslip:open' | Betslip opened | | onBetslipClose | 'betslip:close' | Betslip closed | | onLoginRequest callback | 'login:request' | Login requested | | - | 'scroll:up' | Scroll to top requested | | - | 'height:change' | Iframe height changed | | - | 'ready' | Widget loaded |

TypeScript Support

Add types to your project:

import type { 
  PythiaSDKOptions,
  UserInfo,
  ThemeType,
  BetslipButtonOffset 
} from '@pythiasport/betting-widget';

const options: PythiaSDKOptions = {
  tenantId: 'tenant-123',
  jwtToken: 'token',
  userId: 'user-456',
  currencyCode: 'USD',
  currencySymbol: '$',
  theme: 'dark'
};

Testing Your Migration

  1. Keep the old implementation running in parallel for testing
  2. Test all events - make sure they fire as expected
  3. Test theme switching - verify dark/light mode works
  4. Test user updates - ensure auth updates work
  5. Test scroll sync - verify scroll position updates
  6. Test cleanup - ensure destroy() works properly

Rollback Plan

If you need to rollback, you can always switch back to the legacy API:

<!-- Rollback: use legacy build -->
<script src="https://unpkg.com/@pythiasport/betting-widget@latest/dist/legacy.global.js"></script>

Your original code will work immediately.

Recommended Migration Path

  1. Week 1-2: Install new SDK, use legacy API (zero changes)
  2. Week 3-4: Migrate one component/page to modern API
  3. Week 5-6: Gradually migrate remaining components
  4. Week 7+: Complete migration, remove legacy API

This gradual approach minimizes risk and allows thorough testing.

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

License

MIT