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

@hopla/sickw

v1.3.3

Published

TypeScript client for the Sickw IMEI check/unlock API

Readme

@hopla/sickw

TypeScript client for the Sickw IMEI check/unlock API.

  • Zero dependencies (uses native fetch)
  • ESM + CJS + full type definitions
  • React hooks via @hopla/sickw/react (no external dependencies)
  • Claude Code skill for AI-assisted development
  • Tree-shakeable (sideEffects: false)
  • Node.js >= 18

Install

npm install @hopla/sickw

Claude Code Skill (optional)

Install the skill so Claude Code knows how to use this library when building your projects:

# Global — available in all projects
npx sickw-skill-install --global

# Project-level — only for current repo
npx sickw-skill-install

Once installed, Claude will automatically use @hopla/sickw when you ask it to build features involving IMEI checks, carrier lookups, iCloud status, phone unlocks, etc. You can also invoke it explicitly with /sickw.

To uninstall: npx sickw-skill-uninstall --global

Quick Start (React + Cloudflare Worker)

1. Backend proxy (Cloudflare Worker with Hono)

Never expose your API key in the browser. Create a Worker route that forwards requests to Sickw:

// worker/src/routes/sickw.ts
import { Hono } from 'hono';
import { createSickwClient } from '@hopla/sickw';

const app = new Hono<{ Bindings: { SICKW_API_KEY: string } }>();

app.post('/sickw/check', async (c) => {
  const sickw = createSickwClient({ apiKey: c.env.SICKW_API_KEY });
  const { imei, serviceId } = await c.req.json();
  const result = await sickw.check(imei, serviceId);
  return c.json({ success: true, data: result });
});

app.get('/sickw/services', async (c) => {
  const sickw = createSickwClient({ apiKey: c.env.SICKW_API_KEY });
  const services = await sickw.services();
  return c.json({ success: true, data: services });
});

app.get('/sickw/balance', async (c) => {
  const sickw = createSickwClient({ apiKey: c.env.SICKW_API_KEY });
  const balance = await sickw.balance();
  return c.json({ success: true, data: balance });
});

export default app;

2. Use the hooks (frontend)

The hooks receive a generic fetchFn — use your app's existing fetch wrapper (e.g., apiPost/apiGet):

import { useSickwCheck, useSickwServices, useSickwBalance } from '@hopla/sickw/react';
import { isValidImeiOrSn } from '@hopla/sickw';
import { apiPost, apiGet } from '@/lib/api'; // your fetch wrapper
import { useState } from 'react';

function ImeiChecker() {
  const [imei, setImei] = useState('');
  const [serviceId, setServiceId] = useState(3);

  const { data: services } = useSickwServices(
    () => apiGet('/sickw/services').then(r => r.data!)
  );
  const { data: balance } = useSickwBalance(
    () => apiGet('/sickw/balance').then(r => r.data!),
    60_000 // refetch every 60s
  );
  const check = useSickwCheck(
    (params) => apiPost('/sickw/check', params).then(r => r.data!)
  );

  const isValid = imei.length === 0 || isValidImeiOrSn(imei);

  return (
    <div>
      <p>Balance: ${balance}</p>

      <input
        value={imei}
        onChange={(e) => setImei(e.target.value.trim())}
        placeholder="Enter IMEI or Serial Number"
        maxLength={15}
        style={{ borderColor: isValid ? undefined : 'red' }}
      />

      <select value={serviceId} onChange={(e) => setServiceId(Number(e.target.value))}>
        {services?.map((s) => (
          <option key={s.service} value={s.service}>
            {s.name} (${s.price})
          </option>
        ))}
      </select>

      <button
        disabled={!isValidImeiOrSn(imei) || check.isPending}
        onClick={() => check.mutate({ imei, serviceId })}
      >
        {check.isPending ? 'Checking...' : 'Check IMEI'}
      </button>

      {check.isSuccess && (
        <pre>{JSON.stringify(check.data!.result, null, 2)}</pre>
      )}

      {check.isError && (
        <p style={{ color: 'red' }}>{check.error!.message}</p>
      )}
    </div>
  );
}

React Hooks

| Hook | Type | Signature | |------|------|-----------| | useSickwCheck(fetchFn, options?) | Action (manual trigger) | → { data, error, isPending, isSuccess, isError, mutate, reset } | | useSickwHistory(fetchFn, options?) | Action (manual trigger) | → { data, error, isPending, isSuccess, isError, mutate, reset } | | useSickwServices(fetchFn) | Auto-fetch on mount | → { data, error, isLoading } | | useSickwBalance(fetchFn, intervalMs?) | Auto-fetch + refetch | → { data, error, isLoading, refetch } |

No @tanstack/react-query or any other external dependency required. The hooks use vanilla useState/useEffect/useCallback.

Each hook receives a fetchFn — a function that calls your backend. This lets you plug in any fetch wrapper (apiPost, apiGet, plain fetch, etc.) without coupling to the Sickw client directly.

Node.js / Backend Usage

The client also works standalone without React:

import { createSickwClient } from '@hopla/sickw';

const client = createSickwClient({
  apiKey: 'ABC-DEF-GHI-JKL-MNO-PQR-STU-VWX',
});

const result = await client.check('354442067957123', 3);
const balance = await client.balance();
const services = await client.services();
const history = await client.history('76369088');

Validators

Validate user input before submitting:

import { isValidImeiOrSn, isValidServiceId, isValidApiKey } from '@hopla/sickw';

isValidImeiOrSn('354442067957123'); // true — 11-15 alphanumeric chars
isValidServiceId(3);                // true — integer 0-250
isValidApiKey('ABC-DEF-GHI-...');   // true — XXX-XXX-XXX-XXX-XXX-XXX-XXX-XXX

Service Catalog

All 84 services are available as a typed constant for building UI dropdowns, filtering, etc.:

import { SERVICES, getServiceById, getServicesByCategory } from '@hopla/sickw';

// Lookup by ID
const icloud = getServiceById(3);
// { id: 3, name: 'iCloud On/Off', price: '0.01', category: 'Apple', instant: true }

// Filter by category
const appleServices = getServicesByCategory('Apple'); // 21 services

// Group for a dropdown
const categories = ['Apple', 'Status', 'Generico', 'Premium', 'Unlock iPhone', 'Unlock Gen'];

| Category | Count | Instant | |----------|-------|---------| | Apple | 21 | Yes | | Status | 10 | Mostly | | Generico | 23 | Yes | | Premium | 1 | No | | Unlock iPhone | 22 | No | | Unlock Gen | 7 | No |

Error Handling

API errors are thrown as SickwError with a typed error code:

import { SickwError } from '@hopla/sickw';

try {
  const result = await sickw.check(imei, serviceId);
} catch (err) {
  if (err instanceof SickwError) {
    console.log(err.code);       // 'E01', 'B01', 'A01', etc.
    console.log(err.rawMessage); // Original API error string
  }
}

| Code | Description | |------|-------------| | E01 | IMEI failed Luhn checksum | | E02 | IMEI/SN invalid format or length | | R01 | Service offline or IMEI/SN not found | | B01 | Insufficient balance | | S01/S02 | Service ID does not exist or is inactive | | S03 | Service is not instant | | A01/A02/A03 | Invalid API key |

Configuration

createSickwClient({
  apiKey: 'XXX-XXX-...',     // Required (can be empty for proxy usage)
  baseUrl: 'https://...',    // Default: 'https://sickw.com'
  timeout: 60000,            // Default: 60000ms
});

Documentation

Full API documentation is included in the docs/ directory:

License

MIT