@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-apiQuick Start
Option 1: True One-Liner (Environment Variable)
Set your API key in .env:
MY_API_KEY=sk_live_your_api_key_hereThen 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[] | nullError 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 keyoptions.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 keyoptions.baseUrl(optional): Base URL for the APIoptions.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_hereThen 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 tocitiesandlanguagescities- City data with relation tocountrylanguages- Language data with relation tocountries
More tables will be added as the API expands.
License
MIT
