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

@scarif/scarif-js

v1.0.1

Published

A TypeScript SDK for Scarif API services

Downloads

219

Readme

Stoorplek Data API SDK

Simple, type-safe SDK for accessing data from your API service with powerful chainable querying capabilities. Built with Supabase-style select syntax for intuitive querying.

Installation

npm install stoorplek-data-api

Quick Start

Option 1: True One-Liner (Environment Variable)

Set your API key in .env:

MY_API_KEY=sk_live_your_api_key_here

Then use the one-liner:

import { stoorplek } from 'stoorplek-data-api';

// That's it! One import, one call
const { data, error } = await stoorplek.from('countries').select('*');
console.log(data);

Option 2: Configure Once, Use Everywhere

import { stoorplek } from 'stoorplek-data-api';

// Configure once at app startup
stoorplek.configure({
  apiKey: 'sk_live_your_api_key_here'
});

// Then use anywhere in your app
const { data: countries } = await stoorplek.from('countries').select('*');
const { data: cities } = await stoorplek.from('cities').select('*');

Option 3: Traditional Client (More Control)

import { createClient } from 'stoorplek-data-api';

const client = createClient({
  apiKey: 'sk_live_your_api_key_here',
  baseUrl: 'https://api.yourservice.com', // optional
  timeout: 30000 // optional, defaults to 30 seconds
});

const { data, error } = await client.from('countries').select('*');

Features

Type-Safe - Full TypeScript support with automatic type inference
🔍 Chainable API - Supabase-like query builder with fluent interface
📦 Zero Config - Works with environment variables out of the box
🎯 One-Liner Ready - Import and use in a single line
Lightweight - Minimal dependencies, maximum performance
🔗 Relations - Easy eager loading of related data

Querying & Filtering

Basic Queries

import { stoorplek } from 'stoorplek-data-api';

// Get all records (select is required)
const { data: all } = await stoorplek.from('countries').select('*');

// Select specific columns
const { data: names } = await stoorplek.from('countries')
  .select('name, iso');

Relations (Eager Loading)

Supabase-style nested relations in the select string:

// Load relations (all columns)
const { data: withCities } = await stoorplek.from('countries')
  .select('*, cities(*)');

// Load relations with specific columns
const { data: custom } = await stoorplek.from('countries')
  .select('name, iso, cities(id, name, population)');

// Multiple relations
const { data: multiple } = await stoorplek.from('countries')
  .select('*, cities(*), languages(*)');

// Multiple relations with column selection
const { data: complex } = await stoorplek.from('countries')
  .select('id, name, cities(id, name), languages(*)');

Filtering

// Equal to
const { data: usa } = await stoorplek.from('countries')
  .select('*')
  .eq('iso', 'US');

// Not equal to
const { data: notUSA } = await stoorplek.from('countries')
  .select('*')
  .neq('iso', 'US');

// Greater than / Less than
const { data: highIds } = await stoorplek.from('countries')
  .select('*')
  .gt('id', 100);

const { data: lowIds } = await stoorplek.from('countries')
  .select('*')
  .lt('id', 50);

// Pattern matching (case-insensitive)
const { data: unitedCountries } = await stoorplek.from('countries')
  .select('*')
  .ilike('name', '%united%');

// Pattern matching (case-sensitive)
const { data: exactMatch } = await stoorplek.from('countries')
  .select('*')
  .like('name', 'United%');

// In array
const { data: specific } = await stoorplek.from('countries')
  .select('*')
  .in('iso', ['US', 'CA', 'MX']);

// Not in array
const { data: excluded } = await stoorplek.from('countries')
  .select('*')
  .notIn('iso', ['US', 'CA']);

// Is null / Is not null
const { data: withNull } = await stoorplek.from('countries')
  .select('*')
  .isNull('deleted_at');

const { data: withoutNull } = await stoorplek.from('countries')
  .select('*')
  .isNotNull('email');

Sorting

// Single column sort (ascending by default)
const { data: sorted } = await stoorplek.from('countries')
  .select('*')
  .order('name');

// Descending order
const { data: sortedDesc } = await stoorplek.from('countries')
  .select('*')
  .order('name', 'desc');

// Multiple columns (chain multiple order calls)
const { data: multiSort } = await stoorplek.from('countries')
  .select('*')
  .order('name', 'asc')
  .order('id', 'desc');

Pagination

// Limit results
const { data: limited } = await stoorplek.from('countries')
  .select('*')
  .limit(10);

// Offset for pagination
const { data: page2 } = await stoorplek.from('countries')
  .select('*')
  .limit(10)
  .offset(10);

// Combined with sorting
const { data: paginatedSorted } = await stoorplek.from('countries')
  .select('*')
  .order('name')
  .limit(20)
  .offset(0);

Complex Queries

Combine multiple filters for powerful queries:

const { data, error } = await stoorplek.from('countries')
  .select('name, iso, cities(id, name), languages(*)')
  .ilike('name', '%united%')
  .order('name', 'asc')
  .limit(10);

Getting Single Result

// Get single result (automatically limits to 1)
const { data: usa, error } = await stoorplek.from('countries')
  .select('*')
  .eq('iso', 'US')
  .single();

TypeScript Support

The SDK provides full type safety with automatic type inference:

import { stoorplek } from 'stoorplek-data-api';

// TypeScript automatically knows this returns ApiResponse<Country[]>
const { data, error } = await stoorplek.from('countries').select('*');

// Full autocomplete and type checking
data?.forEach(country => {
  console.log(country.name); // ✅ TypeScript knows 'name' exists
  console.log(country.iso);  // ✅ TypeScript knows 'iso' exists
});

Custom Types

For dynamic tables or custom type definitions:

interface CustomType {
  id: number;
  customField: string;
}

const { data, error } = await stoorplek.from<CustomType>('custom_table').select('*');
// data is typed as CustomType[] | null

Error Handling

import { stoorplek } from 'stoorplek-data-api';

const { data, error } = await stoorplek.from('countries')
  .select('*')
  .eq('iso', 'US');

if (error) {
  console.error('API Error:', error.message);
  console.error('Error Code:', error.code);
} else {
  console.log('Data:', data);
}

API Reference

createClient(options)

Creates a new API client instance.

Parameters:

  • options.apiKey (required): Your API key
  • options.baseUrl (optional): Base URL for the API (defaults to http://localhost:3000)
  • options.timeout (optional): Request timeout in milliseconds (defaults to 30000)

Returns: ApiClient instance

Example:

const client = createClient({
  apiKey: 'sk_live_your_api_key',
  baseUrl: 'https://api.yourservice.com',
  timeout: 30000
});

configure(options)

Configure the default client for one-liner usage.

Parameters:

  • options.apiKey (required): Your API key
  • options.baseUrl (optional): Base URL for the API
  • options.timeout (optional): Request timeout in milliseconds

Example:

import { configure } from 'stoorplek-data-api';

configure({ 
  apiKey: process.env.MY_API_KEY,
  timeout: 30000
});

from(table) / query(table)

Start a chainable query for a specific table.

Parameters:

  • table: Name of the table to query

Returns: QueryBuilder<T> instance with chainable methods

Chainable Methods:

  • .select(query) - Required. Select columns and relations using Supabase-style syntax (e.g., 'id, name, cities(id, name)')
  • Filters: .eq(), .neq(), .gt(), .gte(), .lt(), .lte(), .like(), .ilike(), .in(), .notIn(), .isNull(), .isNotNull() - See Filtering section for examples
  • .order(column, direction?) - Sort (direction: 'asc' | 'desc', defaults to 'asc')
  • .limit(count) - Limit results
  • .offset(count) - Pagination offset
  • .range(from, to) - Set offset and limit together
  • .single() - Execute query and return single result (returns object instead of array)

Example:

const { data, error } = await stoorplek.from('countries')
  .select('name, iso, cities(id, name)')
  .ilike('name', '%united%')
  .order('name', 'asc')
  .limit(10);

health()

Check if the API is healthy.

Returns: Promise<ApiResponse>

Example:

import { health } from 'stoorplek-data-api';

const status = await health();
console.log(status);

stoorplek

Default export object for easy importing and usage.

Example:

const { stoorplek } = require('stoorplek-data-api');

// Configure (or use MY_API_KEY env var)
stoorplek.configure({ apiKey: 'your-key' });

// Use in queries
const { data, error } = await stoorplek.from('countries').select('*');

Response Format

All API responses follow this structure:

interface ApiResponse<T> {
  data: T;
  error: {
    message: string;
    code?: string;
    details?: any;
  } | null;
  status: number;
}

Example success response:

{
  "data": [
    { "id": 1, "name": "United States", "iso": "US" },
    { "id": 2, "name": "Canada", "iso": "CA" }
  ],
  "error": null,
  "status": 200
}

Example error response:

{
  "data": [],
  "error": {
    "message": "Invalid table name",
    "code": "INVALID_TABLE",
    "details": {}
  },
  "status": 400
}

Advanced Usage

Using with the Client Instance

import { createClient } from 'stoorplek-data-api';

const client = createClient({
  apiKey: process.env.API_KEY
});

// All the same chainable methods work
const { data, error } = await client
  .from('countries')
  .select('name, iso')
  .ilike('name', '%united%');

Environment Variables

The SDK automatically looks for MY_API_KEY in your environment:

# .env file
MY_API_KEY=sk_live_your_api_key_here

Then just import and use:

import { stoorplek } from 'stoorplek-data-api';

const { data, error } = await stoorplek.from('countries').select('*'); // No configuration needed!

Available Tables

Currently supported tables:

  • countries - Country data with relations to cities and languages
  • cities - City data with relation to country
  • languages - Language data with relation to countries

More tables will be added as the API expands.

License

MIT