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

@fastslack/socialkit

v0.1.0

Published

Open-source social media OAuth, token management, and publishing SDK. Connect accounts, auto-refresh tokens, publish content — all self-hosted.

Downloads

44

Readme

@fastslack/socialkit

Open-source social media OAuth, token management, publishing, and credit system SDK for Node.js.

Connect user accounts, auto-refresh tokens, publish content, and manage usage credits — all self-hosted with zero third-party dependency.

Features

  • OAuth flows for 7 platforms: LinkedIn, Twitter/X, Instagram, Facebook, TikTok, Threads, YouTube
  • AES-256-GCM encrypted token storage
  • Automatic token refresh with configurable background scheduler
  • Publish content with text, images, and video
  • Credit/quota management — define operations, costs, packages, and track usage
  • Storage adapters — in-memory (dev) or Prisma (production), or bring your own
  • Zero dependencies — only Node.js built-ins + optional Prisma peer dependency
  • MIT licensed — genuinely free software

Install

npm install @fastslack/socialkit

Quick Start

import { SocialKit, MemoryTokenStore, MemoryCreditStore } from "@fastslack/socialkit";

const kit = new SocialKit({
  tokenStore: new MemoryTokenStore(),
  creditStore: new MemoryCreditStore(),
  encryptionKey: SocialKit.generateKey(),
  providers: {
    linkedin: {
      clientId: process.env.LINKEDIN_CLIENT_ID!,
      clientSecret: process.env.LINKEDIN_CLIENT_SECRET!,
      callbackUrl: "https://myapp.com/api/social/linkedin/callback",
    },
    twitter: {
      clientId: process.env.TWITTER_CLIENT_ID!,
      clientSecret: process.env.TWITTER_CLIENT_SECRET!,
      callbackUrl: "https://myapp.com/api/social/twitter/callback",
    },
  },
  operations: [
    { id: "publish:linkedin", name: "Publish to LinkedIn", cost: 1 },
    { id: "publish:twitter", name: "Publish to Twitter", cost: 1 },
    { id: "generate:thread", name: "Generate thread", cost: 3 },
  ],
  packages: [
    { id: "starter", name: "Starter", credits: 50, price: 19, currency: "USD" },
    { id: "pro", name: "Pro", credits: 200, price: 49, currency: "USD" },
  ],
});

OAuth Flow

// 1. Generate auth URL and redirect user
const url = kit.getAuthUrl("linkedin", { userId: "user_123" });
// → redirect user to `url`

// 2. Handle callback (exchange code for tokens, store encrypted)
await kit.handleCallback("linkedin", {
  code: req.query.code,
  userId: "user_123",
});

// 3. Check connected accounts
const connections = await kit.getConnections("user_123");
// → [{ provider: "linkedin", status: "active", expiresAt: ... }]

Publishing

// Publish to one platform
const result = await kit.publish("linkedin", "user_123", {
  text: "Hello from SocialKit!",
});
// → { success: true, postId: "...", postUrl: "https://linkedin.com/..." }

// Publish to multiple platforms
const results = await kit.publishAll(
  ["linkedin", "twitter", "facebook"],
  "user_123",
  { text: "Cross-posted with SocialKit!" },
);

Token Management

// Get a valid token (auto-refreshes if expiring)
const token = await kit.getToken("user_123", "linkedin");

// Disconnect a platform
await kit.disconnect("user_123", "linkedin");

// Start background token refresh (every 15 min)
kit.startRefreshScheduler();

// Manual refresh cycle
await kit.refreshNow();

Credit System

// Add credits
await kit.credits.addCredits("user_123", 100, "purchase", "Starter pack");

// Check balance
const balance = await kit.credits.getBalance("user_123");
// → { balance: 100, totalPurchased: 100, totalUsed: 0 }

// Check if user can afford operations
const canAfford = await kit.credits.canAfford("user_123", [
  "publish:linkedin",
  "publish:twitter",
]);

// Deduct credits
await kit.credits.deductOne("user_123", "publish:linkedin");

// Bulk deduction
await kit.credits.deduct("user_123", [
  "publish:linkedin",
  "publish:twitter",
  "generate:thread",
]);

// Get transaction history
const history = await kit.credits.getTransactions("user_123");

Prisma Adapter (Production)

npm install @prisma/client

Add the models from node_modules/@fastslack/socialkit/prisma/schema.prisma to your schema, then:

import { SocialKit } from "@fastslack/socialkit";
import { PrismaTokenStore, PrismaCreditStore } from "@fastslack/socialkit/prisma";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const kit = new SocialKit({
  tokenStore: new PrismaTokenStore(prisma),
  creditStore: new PrismaCreditStore(prisma),
  encryptionKey: process.env.TOKEN_ENCRYPTION_KEY!,
  providers: { /* ... */ },
});

Custom Storage Adapter

Implement the TokenStore and/or CreditStore interfaces:

import type { TokenStore, CreditStore } from "@fastslack/socialkit";

class MyTokenStore implements TokenStore {
  async save(token) { /* ... */ }
  async get(userId, provider) { /* ... */ }
  async getAll(userId) { /* ... */ }
  async getExpiring(bufferMs, maxFailures) { /* ... */ }
  async update(userId, provider, data) { /* ... */ }
  async delete(userId, provider) { /* ... */ }
}

Token Refresh Schedule

Each platform has different token lifetimes. The refresh scheduler handles them all:

| Platform | Access Token TTL | Refresh Buffer | |---|---|---| | Twitter/X | 2 hours | 30 min before | | YouTube | 1 hour | 10 min before | | TikTok | 24 hours | 2 hours before | | LinkedIn | 60 days | 1 day before | | Instagram | 60 days | 1 day before | | Facebook | 60 days | 1 day before | | Threads | 60 days | 1 day before |

Next.js Integration Example

// app/api/social/[provider]/route.ts
import { kit } from "@/lib/socialkit";
import { getServerSession } from "next-auth";

export async function GET(
  req: Request,
  { params }: { params: { provider: string } },
) {
  const session = await getServerSession();
  const url = kit.getAuthUrl(params.provider, {
    userId: session.user.id,
  });
  return Response.redirect(url);
}

// app/api/social/[provider]/callback/route.ts
export async function GET(
  req: Request,
  { params }: { params: { provider: string } },
) {
  const session = await getServerSession();
  const { searchParams } = new URL(req.url);

  await kit.handleCallback(params.provider, {
    code: searchParams.get("code")!,
    userId: session.user.id,
  });

  return Response.redirect("/dashboard/connections");
}

Generate Encryption Key

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

License

MIT