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

@spaceis/sdk

v0.2.0

Published

Official JavaScript SDK for SpaceIS shop platform. Zero dependencies, works everywhere.

Readme

@spaceis/sdk

npm license

Official JavaScript SDK for the SpaceIS shop platform.

  • Zero runtime dependencies
  • Works in browsers, Node.js, Deno, Bun
  • Full TypeScript support
  • Reactive cart with auto-persistence
  • reCAPTCHA v3 built-in

Table of Contents


Installation

npm install @spaceis/sdk

Or via CDN (browser <script> tag):

<!-- unpkg -->
<script src="https://unpkg.com/@spaceis/sdk/dist/spaceis.global.js"></script>

<!-- jsdelivr -->
<script src="https://cdn.jsdelivr.net/npm/@spaceis/sdk/dist/spaceis.global.js"></script>

Quick start

ESM / TypeScript

import { createSpaceIS } from "@spaceis/sdk";

const client = createSpaceIS({
  baseUrl: "https://storefront-api.spaceis.app",
  shopUuid: "YOUR_SHOP_UUID",
  lang: "en",
});

CDN (browser global)

const client = SpaceIS.createSpaceIS({
  baseUrl: "https://storefront-api.spaceis.app",
  shopUuid: "YOUR_SHOP_UUID",
  lang: "en",
});

API reference

Products

// List with pagination
const result = await client.products.list({ page: 1, category_uuid: "..." });
// result.data  — IndexShopProduct[]
// result.meta  — { current_page, last_page, total, per_page }

// Single product
const product = await client.products.get("product-slug");

// Recommendations
const recs = await client.products.recommendations("product-slug");

Categories

const categories = await client.categories.list();
// Recursive tree — each category has .children[]

Cart (reactive)

Use CartManager for reactive cart state with auto-persistence:

const cart = client.createCartManager();

// Listen to changes
const unsubscribe = cart.onChange((data) => {
  console.log(cart.items);
  console.log(cart.formatPrice());
});

// Mutate
await cart.add("variant-uuid", 2);
await cart.increment("variant-uuid");
await cart.decrement("variant-uuid");
await cart.setQuantity("variant-uuid", 5);
await cart.remove("variant-uuid");

// Discount codes
await cart.applyDiscount("CODE123");
await cart.removeDiscount();

// Read state (synchronous)
cart.items;           // CartItem[]
cart.itemCount;       // unique line items
cart.totalQuantity;   // total qty (human-readable)
cart.finalPrice;      // cents (after discounts)
cart.regularPrice;    // cents (before discounts)
cart.discount;        // { code, percentage_discount } | null
cart.isEmpty;         // boolean
cart.isLoading;       // boolean

// Lookup
cart.findItem("variant-uuid");   // CartItem | null
cart.hasItem("variant-uuid");    // boolean
cart.getQuantity("variant-uuid"); // human-readable qty

// Cleanup
cart.clear();
unsubscribe();

Cart token is auto-generated on first mutation and persisted in localStorage.

CartManager Options

Pass options to createCartManager() to customize behavior:

const cart = client.createCartManager({
  autoLoad: true,
  storagePrefix: "my_app_cart_",
});

| Option | Type | Default | Description | |---|---|---|---| | autoLoad | boolean | false | Auto-load cart from server on creation | | storagePrefix | string | "spaceis_cart_" | localStorage key prefix |

Low-level Cart API

For direct API calls without reactive state, use client.cart directly:

const cart = await client.cart.get();
await client.cart.addItem({ variant_uuid: "...", quantity: 1000 });

Note: quantities in the low-level API use thousandths (1 item = 1000). CartManager handles this conversion automatically.

Checkout

const methods    = await client.checkout.paymentMethods();
const agreements = await client.checkout.agreements();

// reCAPTCHA v3 (loads script automatically)
const token = await client.recaptcha.execute("checkout");

const result = await client.checkout.placeOrder({
  email: "[email protected]",
  first_name: "Steve",
  payment_method_uuid: methods[0].uuid,
  "g-recaptcha-response": token,
  agreements: [agreements[0].uuid],
});

if (result.redirect_url) {
  window.location.href = result.redirect_url;
}

Orders

const order = await client.orders.summary("ORDER_CODE");
// order.status           — "pending" | "completed" | "cancelled"
// order.items            — OrderSummaryItem[]
// order.final_total_price — cents

Vouchers & Daily Rewards

const token = await client.recaptcha.execute("voucher");
await client.vouchers.redeem({
  nick: "Steve",
  code: "FREE-VIP",
  "g-recaptcha-response": token,
});

const token2 = await client.recaptcha.execute("daily_reward");
await client.dailyRewards.claim({
  nick: "Steve",
  "g-recaptcha-response": token2,
});

Sales, Goals, Packages

await client.sales.list({ sort: "-percentage_discount" });
await client.goals.list();
await client.packages.list({ page: 1 });

Rankings

await client.rankings.top({ limit: 10, sort: "-total_spent" });
await client.rankings.latest({ limit: 10, sort: "-completed_at" });

Content (CMS)

await client.content.pages();
await client.content.page("about-us");
await client.content.statute();

Shop config

const config = await client.shop.config();
// config.app_name, config.description, config.logo, config.sections, ...

Prices & Quantities

All prices are in cents (grosze). All API quantities are in thousandths (1 item = 1000).

CartManager handles conversion automatically. For raw API data use helpers:

| Helper | Example | Result | |---|---|---| | formatPrice(cents, currency?) | formatPrice(1299) | "12,99 zl" | | centsToAmount(cents) | centsToAmount(1299) | 12.99 | | fromApiQty(apiQty) | fromApiQty(2000) | 2 | | toApiQty(qty) | toApiQty(2) | 2000 | | getItemQty(item) | getItemQty(cartItem) | 2 | | getProductLimits(product) | getProductLimits(p) | { min: 1, max: 64, step: 1 } | | snapQuantity(qty, limits) | snapQuantity(5, { min: 1, max: 64, step: 2 }) | 5 | | getCartItemImage(item) | getCartItemImage(i) | "https://..." \| null | | escapeHtml(str) | escapeHtml("<b>") | "&lt;b&gt;" |

Quantity snapping

When users input custom quantities, use snapQuantity to round to the nearest valid step. This is especially useful for products that must be purchased in fixed increments:

import { getProductLimits, snapQuantity } from "@spaceis/sdk";

const limits = getProductLimits(product); // { min: 3, max: 99, step: 3 }
snapQuantity(5, limits); // 6 (nearest valid: 3, 6, 9...)
snapQuantity(1, limits); // 3 (clamped to min)
snapQuantity(100, limits); // 99 (clamped to max)

Error handling

import { SpaceISError } from "@spaceis/sdk";

try {
  await cart.add("invalid-uuid");
} catch (err) {
  if (err instanceof SpaceISError) {
    err.message;        // "The given data was invalid."
    err.status;         // 422
    err.isValidation;   // true
    err.isNotFound;     // false
    err.isRateLimited;  // false
    err.errors;         // { variant_uuid: ["Invalid UUID"] }
    err.fieldError("email");  // "Email is required." | undefined
    err.allFieldErrors();     // ["field: message", ...]
  }
}

Configuration options

createSpaceIS({
  baseUrl: "https://storefront-api.spaceis.app",  // required
  shopUuid: "your-uuid",                           // required
  lang: "pl",                                      // optional, default: none
  cartToken: "existing-token",                     // optional, restore session
  timeout: 30000,                                  // optional, ms (default: 30000)
  onRequest: (url, init) => {},                    // optional, before each request
  onResponse: (response) => {},                    // optional, after each response
  onError: (error) => {},                          // optional, on API errors
});

// Runtime updates
client.setLang("en");
client.setCartToken("new-token");

Lifecycle hooks

Use lifecycle hooks to add logging, analytics, or custom error handling:

createSpaceIS({
  baseUrl: "https://storefront-api.spaceis.app",
  shopUuid: "your-uuid",
  onRequest: (url, init) => {
    console.log(`[SpaceIS] ${init.method} ${url}`);
  },
  onResponse: (response) => {
    console.log(`[SpaceIS] ${response.status} ${response.url}`);
  },
  onError: (error) => {
    console.error(`[SpaceIS] ${error.status}: ${error.message}`);
  },
});

TypeScript

Full type definitions included:

import {
  createSpaceIS,
  SpaceISError,
  type IndexShopProduct,
  type ShowShopProduct,
  type Cart,
  type CartItem,
  type PaymentMethod,
  type Agreement,
} from "@spaceis/sdk";

Browser support

Chrome 80+, Firefox 78+, Safari 15+, Edge 80+, Node.js 20+, Deno, Bun.

Requires native fetch and AbortSignal.timeout.


API Documentation

For the full SpaceIS REST API reference, see docs.spaceis.app/api.

Related Packages

| Package | Description | |---|---| | @spaceis/react | React hooks + Next.js SSR helpers | | @spaceis/vue | Vue 3 composables + Nuxt SSR helpers |

License

MIT