> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bytesell.io/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript

> The ByteSell SDK, the cart store, and money helpers.

## `ByteSellSDK`

Served by the platform at `${ platform.sdk }`. Calls are relative to the page,
so a custom domain requires no configuration.

| Namespace     | Members                                                                                |
| ------------- | -------------------------------------------------------------------------------------- |
| `products`    | `list`, `createController`                                                             |
| `collections` | `list`, `get`                                                                          |
| `reviews`     | `list`, submit and list controllers                                                    |
| `auth`        | `me`, `safeRedirect`, a login controller                                               |
| `checkout`    | `goToCheckoutApp`, `fromCart`, `previewCheckout`                                       |
| `account`     | Profile, orders, subscriptions, wallet, sessions, 2FA, email change, exports, deletion |
| `chat`        | The live chat controller                                                               |
| `support`     | `openTicket`                                                                           |
| `giftCards`   | `redeem`                                                                               |
| `affiliate`   | `get`, `apply`, `setPayoutMethod`, `requestPayout`                                     |
| `sentinel`    | `token`, `prewarm`                                                                     |

An expired session is refreshed once and the request replayed. A refusal from
bot protection is not retried, and a request carrying a single-use verification
token is never replayed.

<Warning>
  A contact form must use `support.openTicket`. Posting elsewhere bypasses the
  merchant's ticket inbox and creates a second one they do not monitor.
</Warning>

## The cart

The cart is a shared Alpine store rather than a global object:

```js theme={null}
Alpine.store('cart')
```

| Members                                                 |                          |
| ------------------------------------------------------- | ------------------------ |
| `items`, `count`, `subtotal`, `groupedItems`            | State and derived values |
| `discountCode`, `discount`, `appliedDiscounts`, `total` | Discounts                |
| `add`, `remove`, `updateQty`, `clear`                   | Mutations                |
| `setPreview`, `setDiscountCode`, `clearDiscount`        |                          |

`add()` dispatches a `cart-updated` window event.

State persists in `localStorage`. `preview` is display only. The server
re-derives every total at order creation, so browser-side edits cannot affect
the amount charged.

Checkout is platform-owned. The theme's Checkout button stashes the cart and
navigates to the hosted pay page.

## Money helpers

These are defined by the theme, not the platform. The two first-party themes
define them differently.

| Helper                                 | Behaviour                                                         |
| -------------------------------------- | ----------------------------------------------------------------- |
| `$money(v)`                            | Formats a number without a currency symbol                        |
| `$price(v)`                            | A product price. Renders `Free` at 0.                             |
| `$ccy(v)`                              | A store-currency value, converted to the buyer's display currency |
| `$ccy(v, currency)`                    | Rendered as-is in that currency, never converted                  |
| `window.formatCurrency(v[, currency])` | The underlying function                                           |
| `window.__bsStoreCurrency`             | The store's accounting currency                                   |
| `window.__bsCurrencySymbol`            | The symbol currently displayed                                    |

<Warning>
  The two-argument form is for values that already carry a currency: store
  credit, gift cards, affiliate payouts, and the frozen total of a settled
  order. The one-argument form converts an already-converted number. Nothing
  throws and the displayed figure is wrong.
</Warning>

Prices arrive as strings. `.toFixed()` on one throws.

## Multi-currency

Presentment currency is optional. A theme that does not implement it displays
all prices in the store's own currency.

A theme that implements it owns the entire surface: the picker, the cookie, the
conversion helpers, and `window.__bsPresentmentRates` derived from
`storefront.presentment_rates_json`.

<Note>
  A merchant switching from a theme that supports presentment to one that does
  not loses buyer-currency display without warning. State support in the theme
  listing.
</Note>

## Icons

The icon runtime is served by the platform. Mark an element with a kebab-case
icon name and call the runtime:

```html theme={null}
<i data-lucide="shopping-cart"></i>
<script>lucide.createIcons()</script>
```

Icons are fetched individually and asynchronously. Each replacement is marked,
so a theme's own `MutationObserver` must skip already-marked elements to avoid
re-triggering itself.

<Note>
  Platform scripts are deferred and run after inline end-of-body scripts. Call
  `lucide.createIcons()` from `DOMContentLoaded`, or guard for the runtime being
  present.
</Note>
