@spaceis/sdk
v0.2.0
Published
Official JavaScript SDK for SpaceIS shop platform. Zero dependencies, works everywhere.
Maintainers
Readme
@spaceis/sdk
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
- Quick Start
- API Reference
- Prices & Quantities
- Error Handling
- Configuration Options
- TypeScript
- Browser Support
- Related Packages
- License
Installation
npm install @spaceis/sdkOr 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).
CartManagerhandles 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 — centsVouchers & 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>") | "<b>" |
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
