@managesales/storefront 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +152 -101
  3. package/package.json +2 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@managesales/storefront`. This project adheres to
4
+ [Semantic Versioning](https://semver.org).
5
+
6
+ ## 1.0.2 — 2026-07-11
7
+
8
+ ### Docs
9
+ - Rewrote the README as a full developer landing page: human-readable title and tagline, feature
10
+ overview, all-package-manager install, a copy-paste quick start, a complete **API organization**
11
+ reference, framework examples (React / Next.js / Node.js), server-side auth (SSR) guide, error
12
+ handling, TypeScript guide, a **Versioning** policy, and this changelog.
13
+
14
+ ## 1.0.1 — 2026-07-11
15
+
16
+ ### Docs
17
+ - Expanded the README with per-resource examples and browser/Node runtime support notes.
18
+
19
+ ## 1.0.0 — 2026-07-11
20
+
21
+ ### Added
22
+ - Initial public release. Resource-based Storefront SDK with namespaces for products, collections,
23
+ checkout, cart recovery, auth, customer, blog, bookings, and forms.
24
+ - Built-in customer auth with automatic access-token refresh on `401`.
25
+ - `StorefrontError` class exposing `status`, `code`, `message`, and `details`.
26
+ - Dual ESM + CommonJS builds with bundled TypeScript declarations. Zero runtime dependencies.
package/README.md CHANGED
@@ -1,84 +1,110 @@
1
- # @managesales/storefront
1
+ # ManageSales Storefront SDK
2
+
3
+ **Build custom storefronts on top of the ManageSales Commerce Platform.**
2
4
 
3
5
  [![npm version](https://img.shields.io/npm/v/@managesales/storefront.svg)](https://www.npmjs.com/package/@managesales/storefront)
4
6
  [![license](https://img.shields.io/npm/l/@managesales/storefront.svg)](./LICENSE)
5
7
  [![types](https://img.shields.io/npm/types/@managesales/storefront.svg)](#typescript-support)
6
8
  [![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg)](#browser--node-support)
7
9
 
8
- Resource-based TypeScript client for building online storefronts on the **ManageSales Storefront
9
- API** — think Shopify's Storefront API client, for ManageSales. Browse products, run checkout, and
10
- manage customer accounts with a typed, ergonomic client instead of hand-rolled `fetch` calls.
10
+ `@managesales/storefront` is a typed, resource-based client for the ManageSales Storefront API —
11
+ like Shopify's Storefront client, for ManageSales. Everything you need to ship a storefront:
11
12
 
12
- - 🧩 **Resource namespaces** — `client.products`, `client.checkout`, `client.customer`,
13
- - 🔐 **Auth built in** — customer login + automatic access-token refresh
14
- - 📦 **Zero runtime dependencies** — one small file, uses the platform `fetch`
15
- - 🟦 **Fully typed** — ships `.d.ts`; responses and params are typed end to end
16
- - 🌐 **Runs everywhere** — dual ESM + CommonJS, browser / Node 18+ / Deno / Bun / edge
13
+ - 🛍️ **Products** — list, search, and fetch details
14
+ - 🗂️ **Collections** — browse categories and their products
15
+ - 👤 **Customers** — registration, login, profile, order history
16
+ - 🛒 **Checkout** — line items, coupons, complete purchases (+ abandoned-cart recovery)
17
+ - 🔎 **Search** — full-text product search
18
+ - 🟦 **TypeScript** — first-class types, no `@types` needed
19
+ - ⚡ **SSR-ready** — inject a custom `fetch`; server-side auth pattern built in
20
+ - 📦 **Zero dependencies** — one small file, dual ESM + CommonJS
17
21
 
18
22
  ---
19
23
 
20
24
  ## Table of contents
21
25
 
22
- - [What is this?](#what-is-this)
23
26
  - [Installation](#installation)
24
- - [Quick start](#quick-start-30-seconds)
27
+ - [Quick start](#quick-start)
28
+ - [API organization](#api-organization)
25
29
  - [Create a client](#create-a-client)
26
- - [Products](#products)
30
+ - [Products & search](#products--search)
27
31
  - [Collections](#collections)
28
32
  - [Cart & checkout](#cart--checkout)
29
33
  - [Authentication](#authentication)
30
34
  - [Customer account](#customer-account)
31
35
  - [Error handling](#error-handling)
32
- - [More resources](#more-resources)
33
36
  - [TypeScript support](#typescript-support)
37
+ - [Framework examples](#framework-examples)
34
38
  - [Browser & Node support](#browser--node-support)
39
+ - [Versioning](#versioning)
40
+ - [Changelog](#changelog)
35
41
  - [No-npm alternative](#no-npm-alternative)
36
42
  - [License](#license)
37
43
 
38
- ---
39
-
40
- ## What is this?
41
-
42
- `@managesales/storefront` is the official client SDK for the **ManageSales Storefront API** — the
43
- public, customer-facing API behind a ManageSales store. Use it to build a custom storefront
44
- (product pages, search, cart, checkout, customer login) in any JavaScript/TypeScript framework,
45
- while the SDK handles request headers, workspace scoping, error parsing, pagination, and token
46
- refresh for you.
47
-
48
- It talks to the same API you can also reach directly over HTTP (`/storefront-api/*`) — the SDK is
49
- just the typed, batteries-included way to do it.
50
-
51
44
  ## Installation
52
45
 
53
46
  ```bash
54
47
  npm install @managesales/storefront
55
- # pnpm add @managesales/storefront
56
- # yarn add @managesales/storefront
57
- # bun add @managesales/storefront
48
+ pnpm add @managesales/storefront
49
+ yarn add @managesales/storefront
50
+ bun add @managesales/storefront
58
51
  ```
59
52
 
60
- ## Quick start (30 seconds)
53
+ ## Quick start
54
+
55
+ Copy-paste, add your workspace ID, and you're fetching live catalog data — no auth required:
61
56
 
62
57
  ```ts
63
58
  import { createStorefrontClient } from "@managesales/storefront";
64
59
 
65
60
  const client = createStorefrontClient({
66
- workspaceId: "ws_123", // your store's workspace ID — Settings → API
61
+ workspaceId: "ws_123", // your store — Settings → API
67
62
  });
68
63
 
69
- // Browse products no authentication required
70
- const { data: products, total } = await client.products.list({ limit: 12 });
71
- console.log(`${total} products`, products);
64
+ const { data: products } = await client.products.list({ limit: 12 });
65
+ console.log(products);
72
66
  ```
73
67
 
74
- That's it — public catalog data needs no auth. Add [authentication](#authentication) only when
75
- customers log in.
68
+ ## API organization
76
69
 
77
- ## Create a client
70
+ Every resource is a namespace on the client. Public resources need no auth; customer resources
71
+ require a logged-in session.
78
72
 
79
73
  ```ts
80
- import { createStorefrontClient } from "@managesales/storefront";
74
+ // Catalog (public)
75
+ client.products.list(params?) // paginated list
76
+ client.products.get(idOrSlug) // product details
77
+ client.products.search(query, params?) // full-text search
78
+ client.collections.list(params?)
79
+ client.collections.get(idOrSlug) // collection + its products
80
+
81
+ // Cart & checkout (public)
82
+ client.checkout.create(lineItems) // start a checkout from line items
83
+ client.checkout.get(checkoutId)
84
+ client.checkout.applyCoupon(checkoutId, code)
85
+ client.checkout.complete(checkoutId, payment?)
86
+ client.cart.recover(token) // rebuild a checkout from a recovery link
87
+
88
+ // Auth & customer (customer session)
89
+ client.auth.register({ email, password, name })
90
+ client.auth.login(email, password)
91
+ client.auth.loginWithGoogle(idToken)
92
+ client.auth.logout()
93
+ client.auth.isAuthenticated()
94
+ client.auth.setTokens(access, refresh) // restore a session (e.g. from cookies)
95
+ client.customer.me()
96
+ client.customer.orders(params?) // order history
97
+ client.customer.addresses()
98
+
99
+ // Content (public)
100
+ client.blog.list(params?) / client.blog.get(slug)
101
+ client.bookings.services() / client.bookings.availability(params) / client.bookings.book(data)
102
+ client.forms.get(idOrSlug) / client.forms.submit(formId, data) / client.forms.uploadFile(formId, file)
103
+ ```
81
104
 
105
+ ## Create a client
106
+
107
+ ```ts
82
108
  const client = createStorefrontClient({
83
109
  workspaceId: "ws_123",
84
110
  });
@@ -87,12 +113,11 @@ const client = createStorefrontClient({
87
113
  | Option | Type | Required | Description |
88
114
  |--------|------|----------|-------------|
89
115
  | `workspaceId` | `string` | ✅ | Identifies your store. Found in **Settings → API**. |
90
- | `apiUrl` | `string` | — | Backend base URL **including** the `/api/v1` prefix. Defaults to ManageSales cloud; override for self-hosted/staging/local. |
91
- | `customFetch` | `typeof fetch` | — | Inject a `fetch` implementation for SSR/edge runtimes or Node < 18. |
116
+ | `apiUrl` | `string` | — | Backend base URL **including** the `/api/v1` prefix. Defaults to ManageSales cloud; override for self-hosted / staging / local. |
117
+ | `customFetch` | `typeof fetch` | — | Inject a `fetch` for SSR / edge runtimes or Node < 18. |
92
118
  | `locale` | `string` | — | Default locale for localized content (e.g. `"en"`). |
93
119
 
94
120
  ```ts
95
- // Point at your own backend and inject a custom fetch:
96
121
  const client = createStorefrontClient({
97
122
  workspaceId: "ws_123",
98
123
  apiUrl: "https://api.mystore.com/api/v1",
@@ -101,7 +126,7 @@ const client = createStorefrontClient({
101
126
  });
102
127
  ```
103
128
 
104
- ## Products
129
+ ## Products & search
105
130
 
106
131
  ```ts
107
132
  // List with pagination, search, and sorting
@@ -124,32 +149,30 @@ const { data: results } = await client.products.search("organic cotton");
124
149
  ## Collections
125
150
 
126
151
  ```ts
127
- // List collections
128
152
  const { data: collections } = await client.collections.list();
129
153
 
130
- // Get a collection with its products
131
154
  const summer = await client.collections.get("summer-sale");
132
- console.log(summer.name, summer.products.length);
155
+ console.log(summer.name, summer.products.length); // collection + its products
133
156
  ```
134
157
 
135
158
  ## Cart & checkout
136
159
 
137
- The SDK models a cart as a set of checkout line items. Assemble items in your UI, create a checkout
138
- session, optionally apply a coupon, then complete it.
160
+ Assemble line items in your UI, create a checkout session, optionally apply a coupon, then complete
161
+ it:
139
162
 
140
163
  ```ts
141
- // 1. Create a checkout from cart line items
164
+ // 1. Create a checkout from line items
142
165
  const session = await client.checkout.create([
143
166
  { productId: "prod_123", variantId: "var_456", quantity: 2 },
144
167
  { productId: "prod_789", quantity: 1 },
145
168
  ]);
146
169
 
147
- // 2. Re-fetch a session (e.g. after a page reload)
170
+ // 2. Re-fetch a session (e.g. after a reload)
148
171
  const current = await client.checkout.get(session.id);
149
172
 
150
173
  // 3. Apply a coupon
151
174
  const discounted = await client.checkout.applyCoupon(session.id, "SAVE10");
152
- console.log("Discount:", discounted.discount, "Total:", discounted.total);
175
+ console.log(discounted.discount, discounted.total);
153
176
 
154
177
  // 4. Complete the purchase
155
178
  const order = await client.checkout.complete(session.id, {
@@ -162,44 +185,31 @@ console.log("Order placed:", order.orderNumber);
162
185
  **Abandoned-cart recovery** — turn a recovery link back into a checkout session:
163
186
 
164
187
  ```ts
165
- // URL: https://yourstore.com/recover?token=abc123
166
188
  const token = new URLSearchParams(location.search).get("token")!;
167
189
  const recovered = await client.cart.recover(token);
168
190
  ```
169
191
 
170
192
  ## Authentication
171
193
 
172
- Most storefront pages need **no auth**. When a customer logs in, the SDK stores the access + refresh
173
- tokens internally and refreshes them automatically on `401` — you never handle tokens by hand.
194
+ Most pages need **no auth**. When a customer logs in, the SDK stores the access + refresh tokens and
195
+ **auto-refreshes on `401`** — you never handle tokens by hand.
174
196
 
175
197
  ```ts
176
- // Register
177
- const session = await client.auth.register({
178
- email: "jane@example.com",
179
- password: "SecurePass123!",
180
- name: "Jane Doe",
181
- });
182
-
183
- // Login
198
+ await client.auth.register({ email: "jane@example.com", password: "SecurePass123!", name: "Jane Doe" });
184
199
  await client.auth.login("jane@example.com", "SecurePass123!");
200
+ await client.auth.loginWithGoogle(googleIdToken); // pass a Google ID token
185
201
 
186
- // Google OAuth (pass a Google ID token)
187
- await client.auth.loginWithGoogle(googleIdToken);
188
-
189
- // Check state / log out
190
- if (client.auth.isAuthenticated()) {
191
- /* show account menu */
192
- }
202
+ if (client.auth.isAuthenticated()) { /* show account menu */ }
193
203
  await client.auth.logout();
194
204
  ```
195
205
 
196
206
  ### Server-side (recommended)
197
207
 
198
- For production, run the SDK on your server (Next.js route handlers, Express, etc.) with httpOnly
199
- cookies so tokens never reach the browser. Restore a session from cookies with `setTokens`:
208
+ For production, run the SDK on your server with httpOnly cookies so tokens never reach the browser.
209
+ Restore a session with `setTokens`:
200
210
 
201
211
  ```ts
202
- // app/api/storefront/[...path]/route.ts
212
+ // app/api/storefront/[...path]/route.ts (Next.js)
203
213
  import { createStorefrontClient } from "@managesales/storefront";
204
214
  import { cookies } from "next/headers";
205
215
 
@@ -217,18 +227,17 @@ export async function GET() {
217
227
 
218
228
  ## Customer account
219
229
 
220
- Requires a logged-in session (see [Authentication](#authentication)).
230
+ Requires a logged-in session.
221
231
 
222
232
  ```ts
223
- const me = await client.customer.me(); // profile
233
+ const me = await client.customer.me(); // profile
224
234
  const { data: orders } = await client.customer.orders({ page: 1 }); // order history
225
- const addresses = await client.customer.addresses(); // saved addresses
235
+ const addresses = await client.customer.addresses(); // saved addresses
226
236
  ```
227
237
 
228
238
  ## Error handling
229
239
 
230
- Every non-2xx response throws a `StorefrontError` with structured fields, so you can branch
231
- precisely:
240
+ Every non-2xx response throws a `StorefrontError` with structured fields:
232
241
 
233
242
  ```ts
234
243
  import { StorefrontError } from "@managesales/storefront";
@@ -247,30 +256,13 @@ try {
247
256
  }
248
257
  ```
249
258
 
250
- ## More resources
251
-
252
- The client also exposes `client.blog`, `client.bookings`, and `client.forms`:
253
-
254
- ```ts
255
- const { data: posts } = await client.blog.list({ limit: 10 });
256
- const post = await client.blog.get("how-to-style-leather");
257
-
258
- const services = await client.bookings.services();
259
- const slots = await client.bookings.availability({ serviceId: "svc_1", date: "2026-08-15" });
260
- const booking = await client.bookings.book({
261
- serviceId: "svc_1",
262
- date: "2026-08-15",
263
- startTime: "10:00",
264
- customer: { name: "Jane Doe", email: "jane@example.com" },
265
- });
266
-
267
- const form = await client.forms.get("contact-us");
268
- await client.forms.submit(form.id, { name: "Jane", email: "jane@example.com", message: "Hi!" });
269
- ```
259
+ > **Resilience:** the client automatically retries a request **once** with a refreshed token when a
260
+ > `401` indicates an expired access token. It does not retry on network/5xx errors — wrap calls in
261
+ > your own retry policy if you need that.
270
262
 
271
263
  ## TypeScript support
272
264
 
273
- Written in TypeScript and shipped with declaration files — no `@types/*` package needed. Params and
265
+ Written in TypeScript and shipped with declaration files — no `@types/*` package. Params and
274
266
  responses are fully typed, including generics like `PaginatedResponse<Product>`:
275
267
 
276
268
  ```ts
@@ -288,18 +280,77 @@ const client = createStorefrontClient(config);
288
280
  const page: PaginatedResponse<Product> = await client.products.list();
289
281
  ```
290
282
 
283
+ ## Framework examples
284
+
285
+ **React**
286
+
287
+ ```tsx
288
+ import { useEffect, useState } from "react";
289
+ import { createStorefrontClient, type Product } from "@managesales/storefront";
290
+
291
+ const client = createStorefrontClient({ workspaceId: "ws_123" });
292
+
293
+ export function ProductGrid() {
294
+ const [products, setProducts] = useState<Product[]>([]);
295
+ useEffect(() => {
296
+ client.products.list({ limit: 12 }).then((res) => setProducts(res.data));
297
+ }, []);
298
+ return <ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul>;
299
+ }
300
+ ```
301
+
302
+ **Next.js (Server Component)**
303
+
304
+ ```tsx
305
+ // app/page.tsx
306
+ import { createStorefrontClient } from "@managesales/storefront";
307
+
308
+ const client = createStorefrontClient({ workspaceId: "ws_123" });
309
+
310
+ export default async function Home() {
311
+ const { data: products } = await client.products.list({ limit: 12 });
312
+ return <ProductGrid products={products} />;
313
+ }
314
+ ```
315
+
316
+ **Node.js**
317
+
318
+ ```ts
319
+ import { createStorefrontClient } from "@managesales/storefront";
320
+
321
+ const client = createStorefrontClient({ workspaceId: "ws_123" });
322
+
323
+ const { data } = await client.products.list({ page: 1, limit: 20 });
324
+ console.log(data);
325
+ ```
326
+
291
327
  ## Browser & Node support
292
328
 
293
329
  - **Zero dependencies** — uses the platform's global `fetch`.
294
330
  - **Node.js ≥ 18** (global `fetch`). On older Node, pass `customFetch` (e.g. `undici`).
295
331
  - **Browsers** — all modern evergreen browsers.
296
- - **Deno, Bun, and edge runtimes** (Cloudflare Workers, Vercel Edge) — supported; inject
297
- `customFetch` where a global isn't available.
332
+ - **Deno, Bun, edge runtimes** (Cloudflare Workers, Vercel Edge) — supported; inject `customFetch`
333
+ where a global isn't available.
298
334
  - **Module formats** — ships both **ESM** (`import`) and **CommonJS** (`require`).
299
335
 
336
+ ## Versioning
337
+
338
+ Follows [Semantic Versioning](https://semver.org):
339
+
340
+ - **patch** (`x.y.Z`) — docs and bug fixes, no API change
341
+ - **minor** (`x.Y.z`) — additive, backward-compatible API
342
+ - **major** (`X.y.z`) — breaking changes to the client surface
343
+
344
+ The SDK version tracks the ManageSales Storefront API contract it targets. See the
345
+ [Changelog](#changelog).
346
+
347
+ ## Changelog
348
+
349
+ See [CHANGELOG.md](./CHANGELOG.md) for release notes.
350
+
300
351
  ## No-npm alternative
301
352
 
302
- Prefer not to add a dependency? The exact same client is served as a single file — download it from
353
+ Prefer no dependency? The identical client is served as a single file — download it from
303
354
  **Developers → SDKs** in the app, or curl it:
304
355
 
305
356
  ```bash
@@ -308,7 +359,7 @@ curl -o managesales-storefront.ts \
308
359
  ```
309
360
 
310
361
  Then `import { createStorefrontClient } from "./managesales-storefront"`. The npm package, the curl
311
- endpoint, and the in-app download are all generated from one source, so they're always identical.
362
+ endpoint, and the in-app download are generated from one source, so they're always identical.
312
363
 
313
364
  ## License
314
365
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@managesales/storefront",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Resource-based TypeScript client for building storefronts on the ManageSales Storefront API. Zero runtime dependencies, built-in auth and token refresh.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -16,6 +16,7 @@
16
16
  "files": [
17
17
  "dist",
18
18
  "README.md",
19
+ "CHANGELOG.md",
19
20
  "LICENSE"
20
21
  ],
21
22
  "sideEffects": false,