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 🙏

© 2025 – Pkg Stats / Ryan Hefner

coxwave-sdk

v1.0.14

Published

A vanilla JS SDK

Readme

ax-sdk-chatbot

version: 1.1.0

📚 Table of Contents

installation

npm

npm i ax-sdk-chatbot

yarn

yarn add ax-sdk-chatbot

Quick Use

vite

Use In Root

-main.tsx;

import { createRoot } from "react-dom/client";

import CoxwaveChatSDK from "ax-sdk-chatbot";

import App from "./App.tsx";

import "./index.css";

const sdk = new CoxwaveChatSdk({
  hostClientUrl: import.meta.env.VITE_CLIENT_URL, // your client url (if you use localhost, your client url is http://localhost:5173)
  pluginKey: import.meta.env.VITE_FIRSTBRAIN_PLUGIN_KEY,
  isProd: false,
});

createRoot(document.getElementById("root")!).render(<App />);

sdk.initChat({
  chatApiParams: {
    userId: "user_id",
    courseId: "course_id",
    courseName: "course_name",
    courseCategory: "course_category",
    courseSubCategory: "course_sub_category",
    clipId: "clip_id",
    clipPlayHead:  clip_play_head_number,
  },
  shortcutKey: {
    openChat: { key: "/", modifier: "" },
    sendChat: { key: "Enter", modifier: "" },
  },
  customStyles: {
    floatingButton: {
      isInElement: true,
      parentElementId: "root-button", // <------ here is your Floating Button parent element Id
    },
  },
});

-App.tsx;

import { useEffect, useState } from "react";

import "./App.css";

import CoxwaveChatSdk from "coxwave-sdk";

function App({ sdk }: { sdk: CoxwaveChatSdk }) {
  const [clipPlayHead, setClipPlayHead] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setClipPlayHead((prev) => prev + 5);
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  useEffect(() => {
    sdk.postChatInfo({
      clipId: "58767",
      clipPlayHead,
    });
  }, [clipPlayHead]);

  return (
    <>
      <div id="root-button">{Your Floating Button styles Element}</div> // <------ This is your floating button parent element. It must have the same ID as parentElementId.
    </>
  );
}

export default App;

Use Custom Hook (with useEffect)

  • Test.tsx (can use any component)
import { useEffect, useState } from "react";

import CoxwaveChatSDK from "ax-sdk-chatbot";

import BotImage from "./assets/quick-menu.png";

const sdk = new CoxwaveChatSDK({
  hostClientUrl: import.meta.env.VITE_CLIENT_URL,
  pluginKey: import.meta.env.VITE_FIRSTBRAIN_PLUGIN_KEY,
  isProd: import.meta.env.VITE_IS_PROD === "true",
});


function Test() {
  const [clipPlayHead, setClipPlayHead] = useState(0);

  useEffect(() => {
    sdk.initChat({
      chatApiParams: {
        userId: "user_id",
        courseId: "course_id",
        courseName: "course_name",
        courseCategory: "course_category",
        courseSubCategory: "course_sub_category",
        clipId: "clip_id",
        clipPlayHead: clip_play_head_number,
      },
      customStyles: {
        floatingButton: {
          isInElement: true,
          parentElementId: "root-button",
        },
      },
    });

    return () => {
      sdk.removeChat(); // this is sdk cleanup function
    };
  }, []);

  useEffect(() => {
    const interval = setInterval(() => {
      setClipPlayHead((prev) => prev + 5);
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  useEffect(() => {
    sdk.postChatInfo({
      clipId: "58767",
      clipPlayHead,
    });
  }, [clipPlayHead]);

  return (
    <S.LayoutContainer $isWhiteBack={true}>
      <S.ContentBox>
        <S.RootButton id="root-button">
          <S.BotImage src={BotImage} />
          <S.Text>AI 튜터</S.Text>
        </S.RootButton>
      </S.ContentBox>
    </S.LayoutContainer>
  );
}

export default Test;

const S = {
  ~
} // your styles (this example is for styled-components)

Next.js

  • page.tsx
import Sdk from "./Sdk";

export default function Home() {
  return (
    <Sdk />
  );
}
  • Sdk.tsx
"use client"; // if you use this sdk in Next.js, you must use this

import { useEffect, useRef } from "react";

import CoxwaveChatSdk from "ax-sdk-chatbot";

const clientUrl = process.env.NEXT_PUBLIC_HOST_CLIENT_URL; // your client url (if you use localhost, your client url is http://localhost:3000)
const pluginKey = process.env.NEXT_PUBLIC_COXWAVE_PLUGIN_KEY;

if (!clientUrl) {
  throw new Error("NEXT_PUBLIC_COXWAVE_CLIENT_URL is not set");
}

if (!pluginKey) {
  throw new Error("NEXT_PUBLIC_COXWAVE_PLUGIN_KEY is not set");
}

function Sdk() {
  const iframeRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!clientUrl || !pluginKey) return;

    const coxwaveChatSdkInstance = new CoxwaveChatSdk({
      hostClientUrl: clientUrl,
      pluginKey: pluginKey,
    });

    const init = async () => {
      try {
        await coxwaveChatSdkInstance.initChat({
          chatApiParams: {
            userId: "user_id",
            courseId: "course_id",
            courseName: "course_name",
            courseCategory: "course_category",
            courseSubCategory: "course_sub_category",
            clipId: "clip_id",
            clipPlayHead: clip_play_head_number,
          },
          customStyles: {
            floatingButton: {
              isInElement: true,
              parentElementId: "root-button", // <------ here is your Floating Button parent element Id
            },
          },
        });
      } catch (err) {
        console.error("SDK initChat 실패:", err);
      }
    };

    init(); // 즉시 실행

    return () => {
      coxwaveChatSdkInstance.removeChat();
    };
  }, [clientUrl]);

  return (
    <div
      ref={iframeRef}
      id="root-button" // <------ This is your floating button parent element. It must have the same ID as parentElementId.
      style={{
        width: "50px",
        height: "50px",
        backgroundColor: "red",
        cursor: "pointer",
      }}
    >
      <button>Open Chat</button>
    </div>
  );
}

export default Sdk;

Types

SDK Class

const coxwaveChatSDKInstance = new CoxwaveChatSDK({
  hostClientUrl: "~",
  pluginKey: "~",
});

type CoxwaveChatSDKType = {
  hostClientUrl: string;
  pluginKey: string;
  isProd?: boolean;
};

initChat Method

async initChat({
    chatApiParams,
    customStyles,
    shortcutKey,
  }: {
    chatApiParams: ChatApiParamsType;
    customStyles?: CustomStylesType;
    shortcutKey?: ShortcutKeyType;
  })

type ChatApiParamsType = {
  userId: string;
  courseId: string;
  courseName: string;
  courseCategory: string;
  courseSubCategory: string;
  clipId: string | null;
  clipPlayHead: number | null;
};

type CustomStylesType = {
  floatingButton?: FloatingButtonType;
  chatBody?: ChatBodyType;
};

type ShortcutKeyType = {
  openChat: ShortcutKeyPropertiesType;
  sendChat: ShortcutKeyPropertiesType;
};

type FloatingButtonType = {
  isInElement?: boolean;
  parentElementId?: string;
  style?: Partial<CSSStyleDeclaration>;
};

type ChatBodyType = {
  position?: PositionType;
  width?: string;
  height?: string;
};

type PositionType = {
  top?: string;
  left?: string;
  right?: string;
  bottom?: string;
};

type ShortcutKeyPropertiesType = {
  key: string;
  modifier: "ctrlKey" | "altKey" | "shiftKey" | "metaKey" | "";
};

postChatInfo Method

  postChatInfo({
    clipId,
    clipPlayHead,
  }: {
    clipId: string;
    clipPlayHead: number;
  })
  • you must use postChatInfo method after initChat method

removeChat Method

removeChat();

legacy

Ver 0.x.x: https://www.npmjs.com/package/ax-sdk-chatbot/v/0.3.7

license

MIT

Copyright (c) 2025-present, Coxwave