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

@discordkit/native

v0.1.0

Published

Functional TypeScript bridge to the Discord Social SDK for Electron, Tauri, and other native desktop runtimes

Downloads

296

Readme

@discordkit/native

Functional TypeScript bridge to the Discord Social SDK for native desktop runtimes — Electron, Tauri, and headless Node.

[!WARNING]

🚧 Pre-1.0 and under active development. The API may change between minor versions. 🚧

It wraps the SDK's flat C ABI (cdiscord.h) over a Koffi FFI backend behind a seam that a future node:ffi implementation can slot into. The public surface is free functions + a couple of live handle wrappers, organized into tree-shakeable subpaths so importing one feature never pulls in another.

📦 Installation

npm install @discordkit/native

You must also supply the Discord Social SDK shared library yourself — it can't be redistributed. Download it from the Developer Portal and either pass libraryPath to init/createClient, set DISCORD_SDK_PATH, or place it at ./lib/discord_social_sdk.

🔧 Quick start

import { init, subscribe } from "@discordkit/native";
import { authorize } from "@discordkit/native/auth";
import { setActivity } from "@discordkit/native/presence";

// Configure + activate the ambient client (load the lib, init the handle, pump).
// applicationId can come from DISCORD_APPLICATION_ID instead of being passed here.
const client = init({ applicationId: "1234567890" });

// React to connection status (a TC39 signal: "disconnected" → … → "ready").
using sub = subscribe(client.status, (status) => {
  console.log("Discord:", status);
});

// Run the OAuth2 PKCE flow (opens the browser), then set rich presence.
await authorize();
await setActivity({
  type: "playing",
  state: "In Match",
  details: "Rank: Diamond II"
});

The ambient singleton mirrors @discordkit/client's discord: feature operations resolve it via useClient(), so you never thread a handle around. Use createClient(...) directly for multi-client or test scenarios; both are using-disposable.

🧩 Subpaths

Each feature is its own subpath (@discordkit/native/<name>) — the tree-shaking boundary.

| Subpath | What it does | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | . (root) | Lifecycle (init, configure, shutdown, createClient), client.status signal, client.onLog, subscribe. | | /presence | setActivity (object or builder), clearActivity. | | /auth | authorize (OAuth2 PKCE flow + connect) + the full session lifecycle — startSession/resumeSession/endSession over a pluggable TokenStore (so users authorize once and reconnect silently). Ships fileStore (encrypted file); adapters add an OS-vault backend. Throws typed AuthorizeErrors. | | /users | getCurrentUser, getUser → plain User snapshots. | | /relationships | Friends/blocked/pending list + management (send/accept/reject/cancel friend requests, block/unblock). | | /activity-invites | Send/accept activity invites + join requests; subscribe to incoming invites. acceptActivityInvite resolves with the join secret. | | /lobbies | createOrJoinLobby → a live Lobby (members, metadata, channel linking, per-lobby events); client-wide lobby events; guild/channel discovery. | | /messaging | Send/edit/delete messages (user + lobby), read messages + history, DM summaries, message events. | | /voice | startCall → a live Call (mute/deaf/volume, audio mode, VAD, per-call events); client-wide audio (devices, volume, mute/deaf-all). |

Snapshots vs. live wrappers

Most SDK read-handles are read once into a plain snapshot object (User, Relationship, Message, LobbyMember, …) — simple, GC-friendly, no disposal burden. Two genuinely interactive, long-lived handles are surfaced as live class wrappers instead — Lobby and Call — whose getters re-read the SDK on each access and whose methods drive it:

import { createOrJoinLobby } from "@discordkit/native/lobbies";
import { startCall } from "@discordkit/native/voice";

using lobby = await createOrJoinLobby(secret);
console.log(lobby.members.map((m) => m.user?.username));
using off = lobby.onMemberAdded((id) => console.log("joined:", id));

using call = startCall(lobby.id);
using s = call.onStatusChanged((status) => {
  if (status === "connected") call.setSelfMute(false);
});

Both wrappers are using-disposable; disposing tears down their event subscriptions (it does not end the call or leave the lobby — use endCall / lobby.leave() for that).

The snapshot types are JSON-serializable as-is — snowflake ids are branded strings (matching @discordkit/core and Discord's wire convention, not bigint), and the live wrappers expose toJSON() — so a snapshot crosses any IPC/RPC bridge or JSON.stringify unchanged. This is what lets the Electron/Tauri adapters stay thin.

🔐 Session persistence

@discordkit/native owns the whole OAuth session lifecycle, so users authorize through the browser once and reconnect silently afterward:

import {
  startSession,
  resumeSession,
  endSession,
  fileStore
} from "@discordkit/native/auth";

const client = init({
  applicationId: "1234567890",
  tokenStore: fileStore("1234567890")
});

await resumeSession(); // on boot: silently reconnect from stored tokens
await startSession(); // on a connect button: stored tokens or browser auth
await endSession(); // on logout: end + clear the stored session

TokenStore is a load/save/clear seam; supply your own, or use the shipped fileStore (pure-Node AES-256-GCM, machine-derived key, SEA-safe). For an OS credential vault, the adapters ship a backend (e.g. tauriKeyringStore from @discordkit/tauri/keyring). Tokens refresh proactively via the SDK's expiration callback.

🔔 Events

Two shapes, both returning an unsubscribe that is also a Disposable:

  • Client-wide streamsonLobbyMemberAdded, onMessageCreated, onDeviceChange, … fire for all entities and carry ids; re-fetch (getLobby(id), getMessage(id)) for the full object.
  • Per-instance streamslobby.onMemberAdded, call.onParticipantChanged, … are scoped to that wrapper.
import { onMessageCreated, getMessage } from "@discordkit/native/messaging";

using sub = onMessageCreated((messageId) => {
  const message = getMessage(messageId);
  console.log(message?.author?.username, message?.content);
});

⚠️ Consent

Per Discord's SDK guidance, the action APIs (send a message, send/accept an invite, friend requests, …) must only be called in response to an explicit user action — never automatically.

🪪 License

MIT © Drake Costa